Path: blob/main/assets/js/Chart.bundle.js
1677 views
/*!1* Chart.js v2.9.32* https://www.chartjs.org3* (c) 2019 Chart.js Contributors4* Released under the MIT License5*/6(function (global, factory) {7typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :8typeof define === 'function' && define.amd ? define(factory) :9(global = global || self, global.Chart = factory());10}(this, (function () { 'use strict';1112var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};1314function commonjsRequire () {15throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');16}1718function createCommonjsModule(fn, module) {19return module = { exports: {} }, fn(module, module.exports), module.exports;20}2122function getCjsExportFromNamespace (n) {23return n && n['default'] || n;24}2526var colorName = {27"aliceblue": [240, 248, 255],28"antiquewhite": [250, 235, 215],29"aqua": [0, 255, 255],30"aquamarine": [127, 255, 212],31"azure": [240, 255, 255],32"beige": [245, 245, 220],33"bisque": [255, 228, 196],34"black": [0, 0, 0],35"blanchedalmond": [255, 235, 205],36"blue": [0, 0, 255],37"blueviolet": [138, 43, 226],38"brown": [165, 42, 42],39"burlywood": [222, 184, 135],40"cadetblue": [95, 158, 160],41"chartreuse": [127, 255, 0],42"chocolate": [210, 105, 30],43"coral": [255, 127, 80],44"cornflowerblue": [100, 149, 237],45"cornsilk": [255, 248, 220],46"crimson": [220, 20, 60],47"cyan": [0, 255, 255],48"darkblue": [0, 0, 139],49"darkcyan": [0, 139, 139],50"darkgoldenrod": [184, 134, 11],51"darkgray": [169, 169, 169],52"darkgreen": [0, 100, 0],53"darkgrey": [169, 169, 169],54"darkkhaki": [189, 183, 107],55"darkmagenta": [139, 0, 139],56"darkolivegreen": [85, 107, 47],57"darkorange": [255, 140, 0],58"darkorchid": [153, 50, 204],59"darkred": [139, 0, 0],60"darksalmon": [233, 150, 122],61"darkseagreen": [143, 188, 143],62"darkslateblue": [72, 61, 139],63"darkslategray": [47, 79, 79],64"darkslategrey": [47, 79, 79],65"darkturquoise": [0, 206, 209],66"darkviolet": [148, 0, 211],67"deeppink": [255, 20, 147],68"deepskyblue": [0, 191, 255],69"dimgray": [105, 105, 105],70"dimgrey": [105, 105, 105],71"dodgerblue": [30, 144, 255],72"firebrick": [178, 34, 34],73"floralwhite": [255, 250, 240],74"forestgreen": [34, 139, 34],75"fuchsia": [255, 0, 255],76"gainsboro": [220, 220, 220],77"ghostwhite": [248, 248, 255],78"gold": [255, 215, 0],79"goldenrod": [218, 165, 32],80"gray": [128, 128, 128],81"green": [0, 128, 0],82"greenyellow": [173, 255, 47],83"grey": [128, 128, 128],84"honeydew": [240, 255, 240],85"hotpink": [255, 105, 180],86"indianred": [205, 92, 92],87"indigo": [75, 0, 130],88"ivory": [255, 255, 240],89"khaki": [240, 230, 140],90"lavender": [230, 230, 250],91"lavenderblush": [255, 240, 245],92"lawngreen": [124, 252, 0],93"lemonchiffon": [255, 250, 205],94"lightblue": [173, 216, 230],95"lightcoral": [240, 128, 128],96"lightcyan": [224, 255, 255],97"lightgoldenrodyellow": [250, 250, 210],98"lightgray": [211, 211, 211],99"lightgreen": [144, 238, 144],100"lightgrey": [211, 211, 211],101"lightpink": [255, 182, 193],102"lightsalmon": [255, 160, 122],103"lightseagreen": [32, 178, 170],104"lightskyblue": [135, 206, 250],105"lightslategray": [119, 136, 153],106"lightslategrey": [119, 136, 153],107"lightsteelblue": [176, 196, 222],108"lightyellow": [255, 255, 224],109"lime": [0, 255, 0],110"limegreen": [50, 205, 50],111"linen": [250, 240, 230],112"magenta": [255, 0, 255],113"maroon": [128, 0, 0],114"mediumaquamarine": [102, 205, 170],115"mediumblue": [0, 0, 205],116"mediumorchid": [186, 85, 211],117"mediumpurple": [147, 112, 219],118"mediumseagreen": [60, 179, 113],119"mediumslateblue": [123, 104, 238],120"mediumspringgreen": [0, 250, 154],121"mediumturquoise": [72, 209, 204],122"mediumvioletred": [199, 21, 133],123"midnightblue": [25, 25, 112],124"mintcream": [245, 255, 250],125"mistyrose": [255, 228, 225],126"moccasin": [255, 228, 181],127"navajowhite": [255, 222, 173],128"navy": [0, 0, 128],129"oldlace": [253, 245, 230],130"olive": [128, 128, 0],131"olivedrab": [107, 142, 35],132"orange": [255, 165, 0],133"orangered": [255, 69, 0],134"orchid": [218, 112, 214],135"palegoldenrod": [238, 232, 170],136"palegreen": [152, 251, 152],137"paleturquoise": [175, 238, 238],138"palevioletred": [219, 112, 147],139"papayawhip": [255, 239, 213],140"peachpuff": [255, 218, 185],141"peru": [205, 133, 63],142"pink": [255, 192, 203],143"plum": [221, 160, 221],144"powderblue": [176, 224, 230],145"purple": [128, 0, 128],146"rebeccapurple": [102, 51, 153],147"red": [255, 0, 0],148"rosybrown": [188, 143, 143],149"royalblue": [65, 105, 225],150"saddlebrown": [139, 69, 19],151"salmon": [250, 128, 114],152"sandybrown": [244, 164, 96],153"seagreen": [46, 139, 87],154"seashell": [255, 245, 238],155"sienna": [160, 82, 45],156"silver": [192, 192, 192],157"skyblue": [135, 206, 235],158"slateblue": [106, 90, 205],159"slategray": [112, 128, 144],160"slategrey": [112, 128, 144],161"snow": [255, 250, 250],162"springgreen": [0, 255, 127],163"steelblue": [70, 130, 180],164"tan": [210, 180, 140],165"teal": [0, 128, 128],166"thistle": [216, 191, 216],167"tomato": [255, 99, 71],168"turquoise": [64, 224, 208],169"violet": [238, 130, 238],170"wheat": [245, 222, 179],171"white": [255, 255, 255],172"whitesmoke": [245, 245, 245],173"yellow": [255, 255, 0],174"yellowgreen": [154, 205, 50]175};176177var conversions = createCommonjsModule(function (module) {178/* MIT license */179180181// NOTE: conversions should only return primitive values (i.e. arrays, or182// values that give correct `typeof` results).183// do not use box values types (i.e. Number(), String(), etc.)184185var reverseKeywords = {};186for (var key in colorName) {187if (colorName.hasOwnProperty(key)) {188reverseKeywords[colorName[key]] = key;189}190}191192var convert = module.exports = {193rgb: {channels: 3, labels: 'rgb'},194hsl: {channels: 3, labels: 'hsl'},195hsv: {channels: 3, labels: 'hsv'},196hwb: {channels: 3, labels: 'hwb'},197cmyk: {channels: 4, labels: 'cmyk'},198xyz: {channels: 3, labels: 'xyz'},199lab: {channels: 3, labels: 'lab'},200lch: {channels: 3, labels: 'lch'},201hex: {channels: 1, labels: ['hex']},202keyword: {channels: 1, labels: ['keyword']},203ansi16: {channels: 1, labels: ['ansi16']},204ansi256: {channels: 1, labels: ['ansi256']},205hcg: {channels: 3, labels: ['h', 'c', 'g']},206apple: {channels: 3, labels: ['r16', 'g16', 'b16']},207gray: {channels: 1, labels: ['gray']}208};209210// hide .channels and .labels properties211for (var model in convert) {212if (convert.hasOwnProperty(model)) {213if (!('channels' in convert[model])) {214throw new Error('missing channels property: ' + model);215}216217if (!('labels' in convert[model])) {218throw new Error('missing channel labels property: ' + model);219}220221if (convert[model].labels.length !== convert[model].channels) {222throw new Error('channel and label counts mismatch: ' + model);223}224225var channels = convert[model].channels;226var labels = convert[model].labels;227delete convert[model].channels;228delete convert[model].labels;229Object.defineProperty(convert[model], 'channels', {value: channels});230Object.defineProperty(convert[model], 'labels', {value: labels});231}232}233234convert.rgb.hsl = function (rgb) {235var r = rgb[0] / 255;236var g = rgb[1] / 255;237var b = rgb[2] / 255;238var min = Math.min(r, g, b);239var max = Math.max(r, g, b);240var delta = max - min;241var h;242var s;243var l;244245if (max === min) {246h = 0;247} else if (r === max) {248h = (g - b) / delta;249} else if (g === max) {250h = 2 + (b - r) / delta;251} else if (b === max) {252h = 4 + (r - g) / delta;253}254255h = Math.min(h * 60, 360);256257if (h < 0) {258h += 360;259}260261l = (min + max) / 2;262263if (max === min) {264s = 0;265} else if (l <= 0.5) {266s = delta / (max + min);267} else {268s = delta / (2 - max - min);269}270271return [h, s * 100, l * 100];272};273274convert.rgb.hsv = function (rgb) {275var rdif;276var gdif;277var bdif;278var h;279var s;280281var r = rgb[0] / 255;282var g = rgb[1] / 255;283var b = rgb[2] / 255;284var v = Math.max(r, g, b);285var diff = v - Math.min(r, g, b);286var diffc = function (c) {287return (v - c) / 6 / diff + 1 / 2;288};289290if (diff === 0) {291h = s = 0;292} else {293s = diff / v;294rdif = diffc(r);295gdif = diffc(g);296bdif = diffc(b);297298if (r === v) {299h = bdif - gdif;300} else if (g === v) {301h = (1 / 3) + rdif - bdif;302} else if (b === v) {303h = (2 / 3) + gdif - rdif;304}305if (h < 0) {306h += 1;307} else if (h > 1) {308h -= 1;309}310}311312return [313h * 360,314s * 100,315v * 100316];317};318319convert.rgb.hwb = function (rgb) {320var r = rgb[0];321var g = rgb[1];322var b = rgb[2];323var h = convert.rgb.hsl(rgb)[0];324var w = 1 / 255 * Math.min(r, Math.min(g, b));325326b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));327328return [h, w * 100, b * 100];329};330331convert.rgb.cmyk = function (rgb) {332var r = rgb[0] / 255;333var g = rgb[1] / 255;334var b = rgb[2] / 255;335var c;336var m;337var y;338var k;339340k = Math.min(1 - r, 1 - g, 1 - b);341c = (1 - r - k) / (1 - k) || 0;342m = (1 - g - k) / (1 - k) || 0;343y = (1 - b - k) / (1 - k) || 0;344345return [c * 100, m * 100, y * 100, k * 100];346};347348/**349* See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance350* */351function comparativeDistance(x, y) {352return (353Math.pow(x[0] - y[0], 2) +354Math.pow(x[1] - y[1], 2) +355Math.pow(x[2] - y[2], 2)356);357}358359convert.rgb.keyword = function (rgb) {360var reversed = reverseKeywords[rgb];361if (reversed) {362return reversed;363}364365var currentClosestDistance = Infinity;366var currentClosestKeyword;367368for (var keyword in colorName) {369if (colorName.hasOwnProperty(keyword)) {370var value = colorName[keyword];371372// Compute comparative distance373var distance = comparativeDistance(rgb, value);374375// Check if its less, if so set as closest376if (distance < currentClosestDistance) {377currentClosestDistance = distance;378currentClosestKeyword = keyword;379}380}381}382383return currentClosestKeyword;384};385386convert.keyword.rgb = function (keyword) {387return colorName[keyword];388};389390convert.rgb.xyz = function (rgb) {391var r = rgb[0] / 255;392var g = rgb[1] / 255;393var b = rgb[2] / 255;394395// assume sRGB396r = r > 0.04045 ? Math.pow(((r + 0.055) / 1.055), 2.4) : (r / 12.92);397g = g > 0.04045 ? Math.pow(((g + 0.055) / 1.055), 2.4) : (g / 12.92);398b = b > 0.04045 ? Math.pow(((b + 0.055) / 1.055), 2.4) : (b / 12.92);399400var x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);401var y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);402var z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);403404return [x * 100, y * 100, z * 100];405};406407convert.rgb.lab = function (rgb) {408var xyz = convert.rgb.xyz(rgb);409var x = xyz[0];410var y = xyz[1];411var z = xyz[2];412var l;413var a;414var b;415416x /= 95.047;417y /= 100;418z /= 108.883;419420x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);421y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);422z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);423424l = (116 * y) - 16;425a = 500 * (x - y);426b = 200 * (y - z);427428return [l, a, b];429};430431convert.hsl.rgb = function (hsl) {432var h = hsl[0] / 360;433var s = hsl[1] / 100;434var l = hsl[2] / 100;435var t1;436var t2;437var t3;438var rgb;439var val;440441if (s === 0) {442val = l * 255;443return [val, val, val];444}445446if (l < 0.5) {447t2 = l * (1 + s);448} else {449t2 = l + s - l * s;450}451452t1 = 2 * l - t2;453454rgb = [0, 0, 0];455for (var i = 0; i < 3; i++) {456t3 = h + 1 / 3 * -(i - 1);457if (t3 < 0) {458t3++;459}460if (t3 > 1) {461t3--;462}463464if (6 * t3 < 1) {465val = t1 + (t2 - t1) * 6 * t3;466} else if (2 * t3 < 1) {467val = t2;468} else if (3 * t3 < 2) {469val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;470} else {471val = t1;472}473474rgb[i] = val * 255;475}476477return rgb;478};479480convert.hsl.hsv = function (hsl) {481var h = hsl[0];482var s = hsl[1] / 100;483var l = hsl[2] / 100;484var smin = s;485var lmin = Math.max(l, 0.01);486var sv;487var v;488489l *= 2;490s *= (l <= 1) ? l : 2 - l;491smin *= lmin <= 1 ? lmin : 2 - lmin;492v = (l + s) / 2;493sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);494495return [h, sv * 100, v * 100];496};497498convert.hsv.rgb = function (hsv) {499var h = hsv[0] / 60;500var s = hsv[1] / 100;501var v = hsv[2] / 100;502var hi = Math.floor(h) % 6;503504var f = h - Math.floor(h);505var p = 255 * v * (1 - s);506var q = 255 * v * (1 - (s * f));507var t = 255 * v * (1 - (s * (1 - f)));508v *= 255;509510switch (hi) {511case 0:512return [v, t, p];513case 1:514return [q, v, p];515case 2:516return [p, v, t];517case 3:518return [p, q, v];519case 4:520return [t, p, v];521case 5:522return [v, p, q];523}524};525526convert.hsv.hsl = function (hsv) {527var h = hsv[0];528var s = hsv[1] / 100;529var v = hsv[2] / 100;530var vmin = Math.max(v, 0.01);531var lmin;532var sl;533var l;534535l = (2 - s) * v;536lmin = (2 - s) * vmin;537sl = s * vmin;538sl /= (lmin <= 1) ? lmin : 2 - lmin;539sl = sl || 0;540l /= 2;541542return [h, sl * 100, l * 100];543};544545// http://dev.w3.org/csswg/css-color/#hwb-to-rgb546convert.hwb.rgb = function (hwb) {547var h = hwb[0] / 360;548var wh = hwb[1] / 100;549var bl = hwb[2] / 100;550var ratio = wh + bl;551var i;552var v;553var f;554var n;555556// wh + bl cant be > 1557if (ratio > 1) {558wh /= ratio;559bl /= ratio;560}561562i = Math.floor(6 * h);563v = 1 - bl;564f = 6 * h - i;565566if ((i & 0x01) !== 0) {567f = 1 - f;568}569570n = wh + f * (v - wh); // linear interpolation571572var r;573var g;574var b;575switch (i) {576default:577case 6:578case 0: r = v; g = n; b = wh; break;579case 1: r = n; g = v; b = wh; break;580case 2: r = wh; g = v; b = n; break;581case 3: r = wh; g = n; b = v; break;582case 4: r = n; g = wh; b = v; break;583case 5: r = v; g = wh; b = n; break;584}585586return [r * 255, g * 255, b * 255];587};588589convert.cmyk.rgb = function (cmyk) {590var c = cmyk[0] / 100;591var m = cmyk[1] / 100;592var y = cmyk[2] / 100;593var k = cmyk[3] / 100;594var r;595var g;596var b;597598r = 1 - Math.min(1, c * (1 - k) + k);599g = 1 - Math.min(1, m * (1 - k) + k);600b = 1 - Math.min(1, y * (1 - k) + k);601602return [r * 255, g * 255, b * 255];603};604605convert.xyz.rgb = function (xyz) {606var x = xyz[0] / 100;607var y = xyz[1] / 100;608var z = xyz[2] / 100;609var r;610var g;611var b;612613r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);614g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);615b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);616617// assume sRGB618r = r > 0.0031308619? ((1.055 * Math.pow(r, 1.0 / 2.4)) - 0.055)620: r * 12.92;621622g = g > 0.0031308623? ((1.055 * Math.pow(g, 1.0 / 2.4)) - 0.055)624: g * 12.92;625626b = b > 0.0031308627? ((1.055 * Math.pow(b, 1.0 / 2.4)) - 0.055)628: b * 12.92;629630r = Math.min(Math.max(0, r), 1);631g = Math.min(Math.max(0, g), 1);632b = Math.min(Math.max(0, b), 1);633634return [r * 255, g * 255, b * 255];635};636637convert.xyz.lab = function (xyz) {638var x = xyz[0];639var y = xyz[1];640var z = xyz[2];641var l;642var a;643var b;644645x /= 95.047;646y /= 100;647z /= 108.883;648649x = x > 0.008856 ? Math.pow(x, 1 / 3) : (7.787 * x) + (16 / 116);650y = y > 0.008856 ? Math.pow(y, 1 / 3) : (7.787 * y) + (16 / 116);651z = z > 0.008856 ? Math.pow(z, 1 / 3) : (7.787 * z) + (16 / 116);652653l = (116 * y) - 16;654a = 500 * (x - y);655b = 200 * (y - z);656657return [l, a, b];658};659660convert.lab.xyz = function (lab) {661var l = lab[0];662var a = lab[1];663var b = lab[2];664var x;665var y;666var z;667668y = (l + 16) / 116;669x = a / 500 + y;670z = y - b / 200;671672var y2 = Math.pow(y, 3);673var x2 = Math.pow(x, 3);674var z2 = Math.pow(z, 3);675y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;676x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;677z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;678679x *= 95.047;680y *= 100;681z *= 108.883;682683return [x, y, z];684};685686convert.lab.lch = function (lab) {687var l = lab[0];688var a = lab[1];689var b = lab[2];690var hr;691var h;692var c;693694hr = Math.atan2(b, a);695h = hr * 360 / 2 / Math.PI;696697if (h < 0) {698h += 360;699}700701c = Math.sqrt(a * a + b * b);702703return [l, c, h];704};705706convert.lch.lab = function (lch) {707var l = lch[0];708var c = lch[1];709var h = lch[2];710var a;711var b;712var hr;713714hr = h / 360 * 2 * Math.PI;715a = c * Math.cos(hr);716b = c * Math.sin(hr);717718return [l, a, b];719};720721convert.rgb.ansi16 = function (args) {722var r = args[0];723var g = args[1];724var b = args[2];725var value = 1 in arguments ? arguments[1] : convert.rgb.hsv(args)[2]; // hsv -> ansi16 optimization726727value = Math.round(value / 50);728729if (value === 0) {730return 30;731}732733var ansi = 30734+ ((Math.round(b / 255) << 2)735| (Math.round(g / 255) << 1)736| Math.round(r / 255));737738if (value === 2) {739ansi += 60;740}741742return ansi;743};744745convert.hsv.ansi16 = function (args) {746// optimization here; we already know the value and don't need to get747// it converted for us.748return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);749};750751convert.rgb.ansi256 = function (args) {752var r = args[0];753var g = args[1];754var b = args[2];755756// we use the extended greyscale palette here, with the exception of757// black and white. normal palette only has 4 greyscale shades.758if (r === g && g === b) {759if (r < 8) {760return 16;761}762763if (r > 248) {764return 231;765}766767return Math.round(((r - 8) / 247) * 24) + 232;768}769770var ansi = 16771+ (36 * Math.round(r / 255 * 5))772+ (6 * Math.round(g / 255 * 5))773+ Math.round(b / 255 * 5);774775return ansi;776};777778convert.ansi16.rgb = function (args) {779var color = args % 10;780781// handle greyscale782if (color === 0 || color === 7) {783if (args > 50) {784color += 3.5;785}786787color = color / 10.5 * 255;788789return [color, color, color];790}791792var mult = (~~(args > 50) + 1) * 0.5;793var r = ((color & 1) * mult) * 255;794var g = (((color >> 1) & 1) * mult) * 255;795var b = (((color >> 2) & 1) * mult) * 255;796797return [r, g, b];798};799800convert.ansi256.rgb = function (args) {801// handle greyscale802if (args >= 232) {803var c = (args - 232) * 10 + 8;804return [c, c, c];805}806807args -= 16;808809var rem;810var r = Math.floor(args / 36) / 5 * 255;811var g = Math.floor((rem = args % 36) / 6) / 5 * 255;812var b = (rem % 6) / 5 * 255;813814return [r, g, b];815};816817convert.rgb.hex = function (args) {818var integer = ((Math.round(args[0]) & 0xFF) << 16)819+ ((Math.round(args[1]) & 0xFF) << 8)820+ (Math.round(args[2]) & 0xFF);821822var string = integer.toString(16).toUpperCase();823return '000000'.substring(string.length) + string;824};825826convert.hex.rgb = function (args) {827var match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);828if (!match) {829return [0, 0, 0];830}831832var colorString = match[0];833834if (match[0].length === 3) {835colorString = colorString.split('').map(function (char) {836return char + char;837}).join('');838}839840var integer = parseInt(colorString, 16);841var r = (integer >> 16) & 0xFF;842var g = (integer >> 8) & 0xFF;843var b = integer & 0xFF;844845return [r, g, b];846};847848convert.rgb.hcg = function (rgb) {849var r = rgb[0] / 255;850var g = rgb[1] / 255;851var b = rgb[2] / 255;852var max = Math.max(Math.max(r, g), b);853var min = Math.min(Math.min(r, g), b);854var chroma = (max - min);855var grayscale;856var hue;857858if (chroma < 1) {859grayscale = min / (1 - chroma);860} else {861grayscale = 0;862}863864if (chroma <= 0) {865hue = 0;866} else867if (max === r) {868hue = ((g - b) / chroma) % 6;869} else870if (max === g) {871hue = 2 + (b - r) / chroma;872} else {873hue = 4 + (r - g) / chroma + 4;874}875876hue /= 6;877hue %= 1;878879return [hue * 360, chroma * 100, grayscale * 100];880};881882convert.hsl.hcg = function (hsl) {883var s = hsl[1] / 100;884var l = hsl[2] / 100;885var c = 1;886var f = 0;887888if (l < 0.5) {889c = 2.0 * s * l;890} else {891c = 2.0 * s * (1.0 - l);892}893894if (c < 1.0) {895f = (l - 0.5 * c) / (1.0 - c);896}897898return [hsl[0], c * 100, f * 100];899};900901convert.hsv.hcg = function (hsv) {902var s = hsv[1] / 100;903var v = hsv[2] / 100;904905var c = s * v;906var f = 0;907908if (c < 1.0) {909f = (v - c) / (1 - c);910}911912return [hsv[0], c * 100, f * 100];913};914915convert.hcg.rgb = function (hcg) {916var h = hcg[0] / 360;917var c = hcg[1] / 100;918var g = hcg[2] / 100;919920if (c === 0.0) {921return [g * 255, g * 255, g * 255];922}923924var pure = [0, 0, 0];925var hi = (h % 1) * 6;926var v = hi % 1;927var w = 1 - v;928var mg = 0;929930switch (Math.floor(hi)) {931case 0:932pure[0] = 1; pure[1] = v; pure[2] = 0; break;933case 1:934pure[0] = w; pure[1] = 1; pure[2] = 0; break;935case 2:936pure[0] = 0; pure[1] = 1; pure[2] = v; break;937case 3:938pure[0] = 0; pure[1] = w; pure[2] = 1; break;939case 4:940pure[0] = v; pure[1] = 0; pure[2] = 1; break;941default:942pure[0] = 1; pure[1] = 0; pure[2] = w;943}944945mg = (1.0 - c) * g;946947return [948(c * pure[0] + mg) * 255,949(c * pure[1] + mg) * 255,950(c * pure[2] + mg) * 255951];952};953954convert.hcg.hsv = function (hcg) {955var c = hcg[1] / 100;956var g = hcg[2] / 100;957958var v = c + g * (1.0 - c);959var f = 0;960961if (v > 0.0) {962f = c / v;963}964965return [hcg[0], f * 100, v * 100];966};967968convert.hcg.hsl = function (hcg) {969var c = hcg[1] / 100;970var g = hcg[2] / 100;971972var l = g * (1.0 - c) + 0.5 * c;973var s = 0;974975if (l > 0.0 && l < 0.5) {976s = c / (2 * l);977} else978if (l >= 0.5 && l < 1.0) {979s = c / (2 * (1 - l));980}981982return [hcg[0], s * 100, l * 100];983};984985convert.hcg.hwb = function (hcg) {986var c = hcg[1] / 100;987var g = hcg[2] / 100;988var v = c + g * (1.0 - c);989return [hcg[0], (v - c) * 100, (1 - v) * 100];990};991992convert.hwb.hcg = function (hwb) {993var w = hwb[1] / 100;994var b = hwb[2] / 100;995var v = 1 - b;996var c = v - w;997var g = 0;998999if (c < 1) {1000g = (v - c) / (1 - c);1001}10021003return [hwb[0], c * 100, g * 100];1004};10051006convert.apple.rgb = function (apple) {1007return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];1008};10091010convert.rgb.apple = function (rgb) {1011return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];1012};10131014convert.gray.rgb = function (args) {1015return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];1016};10171018convert.gray.hsl = convert.gray.hsv = function (args) {1019return [0, 0, args[0]];1020};10211022convert.gray.hwb = function (gray) {1023return [0, 100, gray[0]];1024};10251026convert.gray.cmyk = function (gray) {1027return [0, 0, 0, gray[0]];1028};10291030convert.gray.lab = function (gray) {1031return [gray[0], 0, 0];1032};10331034convert.gray.hex = function (gray) {1035var val = Math.round(gray[0] / 100 * 255) & 0xFF;1036var integer = (val << 16) + (val << 8) + val;10371038var string = integer.toString(16).toUpperCase();1039return '000000'.substring(string.length) + string;1040};10411042convert.rgb.gray = function (rgb) {1043var val = (rgb[0] + rgb[1] + rgb[2]) / 3;1044return [val / 255 * 100];1045};1046});1047var conversions_1 = conversions.rgb;1048var conversions_2 = conversions.hsl;1049var conversions_3 = conversions.hsv;1050var conversions_4 = conversions.hwb;1051var conversions_5 = conversions.cmyk;1052var conversions_6 = conversions.xyz;1053var conversions_7 = conversions.lab;1054var conversions_8 = conversions.lch;1055var conversions_9 = conversions.hex;1056var conversions_10 = conversions.keyword;1057var conversions_11 = conversions.ansi16;1058var conversions_12 = conversions.ansi256;1059var conversions_13 = conversions.hcg;1060var conversions_14 = conversions.apple;1061var conversions_15 = conversions.gray;10621063/*1064this function routes a model to all other models.10651066all functions that are routed have a property `.conversion` attached1067to the returned synthetic function. This property is an array1068of strings, each with the steps in between the 'from' and 'to'1069color models (inclusive).10701071conversions that are not possible simply are not included.1072*/10731074function buildGraph() {1075var graph = {};1076// https://jsperf.com/object-keys-vs-for-in-with-closure/31077var models = Object.keys(conversions);10781079for (var len = models.length, i = 0; i < len; i++) {1080graph[models[i]] = {1081// http://jsperf.com/1-vs-infinity1082// micro-opt, but this is simple.1083distance: -1,1084parent: null1085};1086}10871088return graph;1089}10901091// https://en.wikipedia.org/wiki/Breadth-first_search1092function deriveBFS(fromModel) {1093var graph = buildGraph();1094var queue = [fromModel]; // unshift -> queue -> pop10951096graph[fromModel].distance = 0;10971098while (queue.length) {1099var current = queue.pop();1100var adjacents = Object.keys(conversions[current]);11011102for (var len = adjacents.length, i = 0; i < len; i++) {1103var adjacent = adjacents[i];1104var node = graph[adjacent];11051106if (node.distance === -1) {1107node.distance = graph[current].distance + 1;1108node.parent = current;1109queue.unshift(adjacent);1110}1111}1112}11131114return graph;1115}11161117function link(from, to) {1118return function (args) {1119return to(from(args));1120};1121}11221123function wrapConversion(toModel, graph) {1124var path = [graph[toModel].parent, toModel];1125var fn = conversions[graph[toModel].parent][toModel];11261127var cur = graph[toModel].parent;1128while (graph[cur].parent) {1129path.unshift(graph[cur].parent);1130fn = link(conversions[graph[cur].parent][cur], fn);1131cur = graph[cur].parent;1132}11331134fn.conversion = path;1135return fn;1136}11371138var route = function (fromModel) {1139var graph = deriveBFS(fromModel);1140var conversion = {};11411142var models = Object.keys(graph);1143for (var len = models.length, i = 0; i < len; i++) {1144var toModel = models[i];1145var node = graph[toModel];11461147if (node.parent === null) {1148// no possible conversion, or this node is the source model.1149continue;1150}11511152conversion[toModel] = wrapConversion(toModel, graph);1153}11541155return conversion;1156};11571158var convert = {};11591160var models = Object.keys(conversions);11611162function wrapRaw(fn) {1163var wrappedFn = function (args) {1164if (args === undefined || args === null) {1165return args;1166}11671168if (arguments.length > 1) {1169args = Array.prototype.slice.call(arguments);1170}11711172return fn(args);1173};11741175// preserve .conversion property if there is one1176if ('conversion' in fn) {1177wrappedFn.conversion = fn.conversion;1178}11791180return wrappedFn;1181}11821183function wrapRounded(fn) {1184var wrappedFn = function (args) {1185if (args === undefined || args === null) {1186return args;1187}11881189if (arguments.length > 1) {1190args = Array.prototype.slice.call(arguments);1191}11921193var result = fn(args);11941195// we're assuming the result is an array here.1196// see notice in conversions.js; don't use box types1197// in conversion functions.1198if (typeof result === 'object') {1199for (var len = result.length, i = 0; i < len; i++) {1200result[i] = Math.round(result[i]);1201}1202}12031204return result;1205};12061207// preserve .conversion property if there is one1208if ('conversion' in fn) {1209wrappedFn.conversion = fn.conversion;1210}12111212return wrappedFn;1213}12141215models.forEach(function (fromModel) {1216convert[fromModel] = {};12171218Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});1219Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});12201221var routes = route(fromModel);1222var routeModels = Object.keys(routes);12231224routeModels.forEach(function (toModel) {1225var fn = routes[toModel];12261227convert[fromModel][toModel] = wrapRounded(fn);1228convert[fromModel][toModel].raw = wrapRaw(fn);1229});1230});12311232var colorConvert = convert;12331234var colorName$1 = {1235"aliceblue": [240, 248, 255],1236"antiquewhite": [250, 235, 215],1237"aqua": [0, 255, 255],1238"aquamarine": [127, 255, 212],1239"azure": [240, 255, 255],1240"beige": [245, 245, 220],1241"bisque": [255, 228, 196],1242"black": [0, 0, 0],1243"blanchedalmond": [255, 235, 205],1244"blue": [0, 0, 255],1245"blueviolet": [138, 43, 226],1246"brown": [165, 42, 42],1247"burlywood": [222, 184, 135],1248"cadetblue": [95, 158, 160],1249"chartreuse": [127, 255, 0],1250"chocolate": [210, 105, 30],1251"coral": [255, 127, 80],1252"cornflowerblue": [100, 149, 237],1253"cornsilk": [255, 248, 220],1254"crimson": [220, 20, 60],1255"cyan": [0, 255, 255],1256"darkblue": [0, 0, 139],1257"darkcyan": [0, 139, 139],1258"darkgoldenrod": [184, 134, 11],1259"darkgray": [169, 169, 169],1260"darkgreen": [0, 100, 0],1261"darkgrey": [169, 169, 169],1262"darkkhaki": [189, 183, 107],1263"darkmagenta": [139, 0, 139],1264"darkolivegreen": [85, 107, 47],1265"darkorange": [255, 140, 0],1266"darkorchid": [153, 50, 204],1267"darkred": [139, 0, 0],1268"darksalmon": [233, 150, 122],1269"darkseagreen": [143, 188, 143],1270"darkslateblue": [72, 61, 139],1271"darkslategray": [47, 79, 79],1272"darkslategrey": [47, 79, 79],1273"darkturquoise": [0, 206, 209],1274"darkviolet": [148, 0, 211],1275"deeppink": [255, 20, 147],1276"deepskyblue": [0, 191, 255],1277"dimgray": [105, 105, 105],1278"dimgrey": [105, 105, 105],1279"dodgerblue": [30, 144, 255],1280"firebrick": [178, 34, 34],1281"floralwhite": [255, 250, 240],1282"forestgreen": [34, 139, 34],1283"fuchsia": [255, 0, 255],1284"gainsboro": [220, 220, 220],1285"ghostwhite": [248, 248, 255],1286"gold": [255, 215, 0],1287"goldenrod": [218, 165, 32],1288"gray": [128, 128, 128],1289"green": [0, 128, 0],1290"greenyellow": [173, 255, 47],1291"grey": [128, 128, 128],1292"honeydew": [240, 255, 240],1293"hotpink": [255, 105, 180],1294"indianred": [205, 92, 92],1295"indigo": [75, 0, 130],1296"ivory": [255, 255, 240],1297"khaki": [240, 230, 140],1298"lavender": [230, 230, 250],1299"lavenderblush": [255, 240, 245],1300"lawngreen": [124, 252, 0],1301"lemonchiffon": [255, 250, 205],1302"lightblue": [173, 216, 230],1303"lightcoral": [240, 128, 128],1304"lightcyan": [224, 255, 255],1305"lightgoldenrodyellow": [250, 250, 210],1306"lightgray": [211, 211, 211],1307"lightgreen": [144, 238, 144],1308"lightgrey": [211, 211, 211],1309"lightpink": [255, 182, 193],1310"lightsalmon": [255, 160, 122],1311"lightseagreen": [32, 178, 170],1312"lightskyblue": [135, 206, 250],1313"lightslategray": [119, 136, 153],1314"lightslategrey": [119, 136, 153],1315"lightsteelblue": [176, 196, 222],1316"lightyellow": [255, 255, 224],1317"lime": [0, 255, 0],1318"limegreen": [50, 205, 50],1319"linen": [250, 240, 230],1320"magenta": [255, 0, 255],1321"maroon": [128, 0, 0],1322"mediumaquamarine": [102, 205, 170],1323"mediumblue": [0, 0, 205],1324"mediumorchid": [186, 85, 211],1325"mediumpurple": [147, 112, 219],1326"mediumseagreen": [60, 179, 113],1327"mediumslateblue": [123, 104, 238],1328"mediumspringgreen": [0, 250, 154],1329"mediumturquoise": [72, 209, 204],1330"mediumvioletred": [199, 21, 133],1331"midnightblue": [25, 25, 112],1332"mintcream": [245, 255, 250],1333"mistyrose": [255, 228, 225],1334"moccasin": [255, 228, 181],1335"navajowhite": [255, 222, 173],1336"navy": [0, 0, 128],1337"oldlace": [253, 245, 230],1338"olive": [128, 128, 0],1339"olivedrab": [107, 142, 35],1340"orange": [255, 165, 0],1341"orangered": [255, 69, 0],1342"orchid": [218, 112, 214],1343"palegoldenrod": [238, 232, 170],1344"palegreen": [152, 251, 152],1345"paleturquoise": [175, 238, 238],1346"palevioletred": [219, 112, 147],1347"papayawhip": [255, 239, 213],1348"peachpuff": [255, 218, 185],1349"peru": [205, 133, 63],1350"pink": [255, 192, 203],1351"plum": [221, 160, 221],1352"powderblue": [176, 224, 230],1353"purple": [128, 0, 128],1354"rebeccapurple": [102, 51, 153],1355"red": [255, 0, 0],1356"rosybrown": [188, 143, 143],1357"royalblue": [65, 105, 225],1358"saddlebrown": [139, 69, 19],1359"salmon": [250, 128, 114],1360"sandybrown": [244, 164, 96],1361"seagreen": [46, 139, 87],1362"seashell": [255, 245, 238],1363"sienna": [160, 82, 45],1364"silver": [192, 192, 192],1365"skyblue": [135, 206, 235],1366"slateblue": [106, 90, 205],1367"slategray": [112, 128, 144],1368"slategrey": [112, 128, 144],1369"snow": [255, 250, 250],1370"springgreen": [0, 255, 127],1371"steelblue": [70, 130, 180],1372"tan": [210, 180, 140],1373"teal": [0, 128, 128],1374"thistle": [216, 191, 216],1375"tomato": [255, 99, 71],1376"turquoise": [64, 224, 208],1377"violet": [238, 130, 238],1378"wheat": [245, 222, 179],1379"white": [255, 255, 255],1380"whitesmoke": [245, 245, 245],1381"yellow": [255, 255, 0],1382"yellowgreen": [154, 205, 50]1383};13841385/* MIT license */138613871388var colorString = {1389getRgba: getRgba,1390getHsla: getHsla,1391getRgb: getRgb,1392getHsl: getHsl,1393getHwb: getHwb,1394getAlpha: getAlpha,13951396hexString: hexString,1397rgbString: rgbString,1398rgbaString: rgbaString,1399percentString: percentString,1400percentaString: percentaString,1401hslString: hslString,1402hslaString: hslaString,1403hwbString: hwbString,1404keyword: keyword1405};14061407function getRgba(string) {1408if (!string) {1409return;1410}1411var abbr = /^#([a-fA-F0-9]{3,4})$/i,1412hex = /^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i,1413rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,1414per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i,1415keyword = /(\w+)/;14161417var rgb = [0, 0, 0],1418a = 1,1419match = string.match(abbr),1420hexAlpha = "";1421if (match) {1422match = match[1];1423hexAlpha = match[3];1424for (var i = 0; i < rgb.length; i++) {1425rgb[i] = parseInt(match[i] + match[i], 16);1426}1427if (hexAlpha) {1428a = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;1429}1430}1431else if (match = string.match(hex)) {1432hexAlpha = match[2];1433match = match[1];1434for (var i = 0; i < rgb.length; i++) {1435rgb[i] = parseInt(match.slice(i * 2, i * 2 + 2), 16);1436}1437if (hexAlpha) {1438a = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;1439}1440}1441else if (match = string.match(rgba)) {1442for (var i = 0; i < rgb.length; i++) {1443rgb[i] = parseInt(match[i + 1]);1444}1445a = parseFloat(match[4]);1446}1447else if (match = string.match(per)) {1448for (var i = 0; i < rgb.length; i++) {1449rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);1450}1451a = parseFloat(match[4]);1452}1453else if (match = string.match(keyword)) {1454if (match[1] == "transparent") {1455return [0, 0, 0, 0];1456}1457rgb = colorName$1[match[1]];1458if (!rgb) {1459return;1460}1461}14621463for (var i = 0; i < rgb.length; i++) {1464rgb[i] = scale(rgb[i], 0, 255);1465}1466if (!a && a != 0) {1467a = 1;1468}1469else {1470a = scale(a, 0, 1);1471}1472rgb[3] = a;1473return rgb;1474}14751476function getHsla(string) {1477if (!string) {1478return;1479}1480var hsl = /^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;1481var match = string.match(hsl);1482if (match) {1483var alpha = parseFloat(match[4]);1484var h = scale(parseInt(match[1]), 0, 360),1485s = scale(parseFloat(match[2]), 0, 100),1486l = scale(parseFloat(match[3]), 0, 100),1487a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);1488return [h, s, l, a];1489}1490}14911492function getHwb(string) {1493if (!string) {1494return;1495}1496var hwb = /^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/;1497var match = string.match(hwb);1498if (match) {1499var alpha = parseFloat(match[4]);1500var h = scale(parseInt(match[1]), 0, 360),1501w = scale(parseFloat(match[2]), 0, 100),1502b = scale(parseFloat(match[3]), 0, 100),1503a = scale(isNaN(alpha) ? 1 : alpha, 0, 1);1504return [h, w, b, a];1505}1506}15071508function getRgb(string) {1509var rgba = getRgba(string);1510return rgba && rgba.slice(0, 3);1511}15121513function getHsl(string) {1514var hsla = getHsla(string);1515return hsla && hsla.slice(0, 3);1516}15171518function getAlpha(string) {1519var vals = getRgba(string);1520if (vals) {1521return vals[3];1522}1523else if (vals = getHsla(string)) {1524return vals[3];1525}1526else if (vals = getHwb(string)) {1527return vals[3];1528}1529}15301531// generators1532function hexString(rgba, a) {1533var a = (a !== undefined && rgba.length === 3) ? a : rgba[3];1534return "#" + hexDouble(rgba[0])1535+ hexDouble(rgba[1])1536+ hexDouble(rgba[2])1537+ (1538(a >= 0 && a < 1)1539? hexDouble(Math.round(a * 255))1540: ""1541);1542}15431544function rgbString(rgba, alpha) {1545if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {1546return rgbaString(rgba, alpha);1547}1548return "rgb(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2] + ")";1549}15501551function rgbaString(rgba, alpha) {1552if (alpha === undefined) {1553alpha = (rgba[3] !== undefined ? rgba[3] : 1);1554}1555return "rgba(" + rgba[0] + ", " + rgba[1] + ", " + rgba[2]1556+ ", " + alpha + ")";1557}15581559function percentString(rgba, alpha) {1560if (alpha < 1 || (rgba[3] && rgba[3] < 1)) {1561return percentaString(rgba, alpha);1562}1563var r = Math.round(rgba[0]/255 * 100),1564g = Math.round(rgba[1]/255 * 100),1565b = Math.round(rgba[2]/255 * 100);15661567return "rgb(" + r + "%, " + g + "%, " + b + "%)";1568}15691570function percentaString(rgba, alpha) {1571var r = Math.round(rgba[0]/255 * 100),1572g = Math.round(rgba[1]/255 * 100),1573b = Math.round(rgba[2]/255 * 100);1574return "rgba(" + r + "%, " + g + "%, " + b + "%, " + (alpha || rgba[3] || 1) + ")";1575}15761577function hslString(hsla, alpha) {1578if (alpha < 1 || (hsla[3] && hsla[3] < 1)) {1579return hslaString(hsla, alpha);1580}1581return "hsl(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%)";1582}15831584function hslaString(hsla, alpha) {1585if (alpha === undefined) {1586alpha = (hsla[3] !== undefined ? hsla[3] : 1);1587}1588return "hsla(" + hsla[0] + ", " + hsla[1] + "%, " + hsla[2] + "%, "1589+ alpha + ")";1590}15911592// hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax1593// (hwb have alpha optional & 1 is default value)1594function hwbString(hwb, alpha) {1595if (alpha === undefined) {1596alpha = (hwb[3] !== undefined ? hwb[3] : 1);1597}1598return "hwb(" + hwb[0] + ", " + hwb[1] + "%, " + hwb[2] + "%"1599+ (alpha !== undefined && alpha !== 1 ? ", " + alpha : "") + ")";1600}16011602function keyword(rgb) {1603return reverseNames[rgb.slice(0, 3)];1604}16051606// helpers1607function scale(num, min, max) {1608return Math.min(Math.max(min, num), max);1609}16101611function hexDouble(num) {1612var str = num.toString(16).toUpperCase();1613return (str.length < 2) ? "0" + str : str;1614}161516161617//create a list of reverse color names1618var reverseNames = {};1619for (var name in colorName$1) {1620reverseNames[colorName$1[name]] = name;1621}16221623/* MIT license */1624162516261627var Color = function (obj) {1628if (obj instanceof Color) {1629return obj;1630}1631if (!(this instanceof Color)) {1632return new Color(obj);1633}16341635this.valid = false;1636this.values = {1637rgb: [0, 0, 0],1638hsl: [0, 0, 0],1639hsv: [0, 0, 0],1640hwb: [0, 0, 0],1641cmyk: [0, 0, 0, 0],1642alpha: 11643};16441645// parse Color() argument1646var vals;1647if (typeof obj === 'string') {1648vals = colorString.getRgba(obj);1649if (vals) {1650this.setValues('rgb', vals);1651} else if (vals = colorString.getHsla(obj)) {1652this.setValues('hsl', vals);1653} else if (vals = colorString.getHwb(obj)) {1654this.setValues('hwb', vals);1655}1656} else if (typeof obj === 'object') {1657vals = obj;1658if (vals.r !== undefined || vals.red !== undefined) {1659this.setValues('rgb', vals);1660} else if (vals.l !== undefined || vals.lightness !== undefined) {1661this.setValues('hsl', vals);1662} else if (vals.v !== undefined || vals.value !== undefined) {1663this.setValues('hsv', vals);1664} else if (vals.w !== undefined || vals.whiteness !== undefined) {1665this.setValues('hwb', vals);1666} else if (vals.c !== undefined || vals.cyan !== undefined) {1667this.setValues('cmyk', vals);1668}1669}1670};16711672Color.prototype = {1673isValid: function () {1674return this.valid;1675},1676rgb: function () {1677return this.setSpace('rgb', arguments);1678},1679hsl: function () {1680return this.setSpace('hsl', arguments);1681},1682hsv: function () {1683return this.setSpace('hsv', arguments);1684},1685hwb: function () {1686return this.setSpace('hwb', arguments);1687},1688cmyk: function () {1689return this.setSpace('cmyk', arguments);1690},16911692rgbArray: function () {1693return this.values.rgb;1694},1695hslArray: function () {1696return this.values.hsl;1697},1698hsvArray: function () {1699return this.values.hsv;1700},1701hwbArray: function () {1702var values = this.values;1703if (values.alpha !== 1) {1704return values.hwb.concat([values.alpha]);1705}1706return values.hwb;1707},1708cmykArray: function () {1709return this.values.cmyk;1710},1711rgbaArray: function () {1712var values = this.values;1713return values.rgb.concat([values.alpha]);1714},1715hslaArray: function () {1716var values = this.values;1717return values.hsl.concat([values.alpha]);1718},1719alpha: function (val) {1720if (val === undefined) {1721return this.values.alpha;1722}1723this.setValues('alpha', val);1724return this;1725},17261727red: function (val) {1728return this.setChannel('rgb', 0, val);1729},1730green: function (val) {1731return this.setChannel('rgb', 1, val);1732},1733blue: function (val) {1734return this.setChannel('rgb', 2, val);1735},1736hue: function (val) {1737if (val) {1738val %= 360;1739val = val < 0 ? 360 + val : val;1740}1741return this.setChannel('hsl', 0, val);1742},1743saturation: function (val) {1744return this.setChannel('hsl', 1, val);1745},1746lightness: function (val) {1747return this.setChannel('hsl', 2, val);1748},1749saturationv: function (val) {1750return this.setChannel('hsv', 1, val);1751},1752whiteness: function (val) {1753return this.setChannel('hwb', 1, val);1754},1755blackness: function (val) {1756return this.setChannel('hwb', 2, val);1757},1758value: function (val) {1759return this.setChannel('hsv', 2, val);1760},1761cyan: function (val) {1762return this.setChannel('cmyk', 0, val);1763},1764magenta: function (val) {1765return this.setChannel('cmyk', 1, val);1766},1767yellow: function (val) {1768return this.setChannel('cmyk', 2, val);1769},1770black: function (val) {1771return this.setChannel('cmyk', 3, val);1772},17731774hexString: function () {1775return colorString.hexString(this.values.rgb);1776},1777rgbString: function () {1778return colorString.rgbString(this.values.rgb, this.values.alpha);1779},1780rgbaString: function () {1781return colorString.rgbaString(this.values.rgb, this.values.alpha);1782},1783percentString: function () {1784return colorString.percentString(this.values.rgb, this.values.alpha);1785},1786hslString: function () {1787return colorString.hslString(this.values.hsl, this.values.alpha);1788},1789hslaString: function () {1790return colorString.hslaString(this.values.hsl, this.values.alpha);1791},1792hwbString: function () {1793return colorString.hwbString(this.values.hwb, this.values.alpha);1794},1795keyword: function () {1796return colorString.keyword(this.values.rgb, this.values.alpha);1797},17981799rgbNumber: function () {1800var rgb = this.values.rgb;1801return (rgb[0] << 16) | (rgb[1] << 8) | rgb[2];1802},18031804luminosity: function () {1805// http://www.w3.org/TR/WCAG20/#relativeluminancedef1806var rgb = this.values.rgb;1807var lum = [];1808for (var i = 0; i < rgb.length; i++) {1809var chan = rgb[i] / 255;1810lum[i] = (chan <= 0.03928) ? chan / 12.92 : Math.pow(((chan + 0.055) / 1.055), 2.4);1811}1812return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];1813},18141815contrast: function (color2) {1816// http://www.w3.org/TR/WCAG20/#contrast-ratiodef1817var lum1 = this.luminosity();1818var lum2 = color2.luminosity();1819if (lum1 > lum2) {1820return (lum1 + 0.05) / (lum2 + 0.05);1821}1822return (lum2 + 0.05) / (lum1 + 0.05);1823},18241825level: function (color2) {1826var contrastRatio = this.contrast(color2);1827if (contrastRatio >= 7.1) {1828return 'AAA';1829}18301831return (contrastRatio >= 4.5) ? 'AA' : '';1832},18331834dark: function () {1835// YIQ equation from http://24ways.org/2010/calculating-color-contrast1836var rgb = this.values.rgb;1837var yiq = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000;1838return yiq < 128;1839},18401841light: function () {1842return !this.dark();1843},18441845negate: function () {1846var rgb = [];1847for (var i = 0; i < 3; i++) {1848rgb[i] = 255 - this.values.rgb[i];1849}1850this.setValues('rgb', rgb);1851return this;1852},18531854lighten: function (ratio) {1855var hsl = this.values.hsl;1856hsl[2] += hsl[2] * ratio;1857this.setValues('hsl', hsl);1858return this;1859},18601861darken: function (ratio) {1862var hsl = this.values.hsl;1863hsl[2] -= hsl[2] * ratio;1864this.setValues('hsl', hsl);1865return this;1866},18671868saturate: function (ratio) {1869var hsl = this.values.hsl;1870hsl[1] += hsl[1] * ratio;1871this.setValues('hsl', hsl);1872return this;1873},18741875desaturate: function (ratio) {1876var hsl = this.values.hsl;1877hsl[1] -= hsl[1] * ratio;1878this.setValues('hsl', hsl);1879return this;1880},18811882whiten: function (ratio) {1883var hwb = this.values.hwb;1884hwb[1] += hwb[1] * ratio;1885this.setValues('hwb', hwb);1886return this;1887},18881889blacken: function (ratio) {1890var hwb = this.values.hwb;1891hwb[2] += hwb[2] * ratio;1892this.setValues('hwb', hwb);1893return this;1894},18951896greyscale: function () {1897var rgb = this.values.rgb;1898// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale1899var val = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;1900this.setValues('rgb', [val, val, val]);1901return this;1902},19031904clearer: function (ratio) {1905var alpha = this.values.alpha;1906this.setValues('alpha', alpha - (alpha * ratio));1907return this;1908},19091910opaquer: function (ratio) {1911var alpha = this.values.alpha;1912this.setValues('alpha', alpha + (alpha * ratio));1913return this;1914},19151916rotate: function (degrees) {1917var hsl = this.values.hsl;1918var hue = (hsl[0] + degrees) % 360;1919hsl[0] = hue < 0 ? 360 + hue : hue;1920this.setValues('hsl', hsl);1921return this;1922},19231924/**1925* Ported from sass implementation in C1926* https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L2091927*/1928mix: function (mixinColor, weight) {1929var color1 = this;1930var color2 = mixinColor;1931var p = weight === undefined ? 0.5 : weight;19321933var w = 2 * p - 1;1934var a = color1.alpha() - color2.alpha();19351936var w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2.0;1937var w2 = 1 - w1;19381939return this1940.rgb(1941w1 * color1.red() + w2 * color2.red(),1942w1 * color1.green() + w2 * color2.green(),1943w1 * color1.blue() + w2 * color2.blue()1944)1945.alpha(color1.alpha() * p + color2.alpha() * (1 - p));1946},19471948toJSON: function () {1949return this.rgb();1950},19511952clone: function () {1953// NOTE(SB): using node-clone creates a dependency to Buffer when using browserify,1954// making the final build way to big to embed in Chart.js. So let's do it manually,1955// assuming that values to clone are 1 dimension arrays containing only numbers,1956// except 'alpha' which is a number.1957var result = new Color();1958var source = this.values;1959var target = result.values;1960var value, type;19611962for (var prop in source) {1963if (source.hasOwnProperty(prop)) {1964value = source[prop];1965type = ({}).toString.call(value);1966if (type === '[object Array]') {1967target[prop] = value.slice(0);1968} else if (type === '[object Number]') {1969target[prop] = value;1970} else {1971console.error('unexpected color value:', value);1972}1973}1974}19751976return result;1977}1978};19791980Color.prototype.spaces = {1981rgb: ['red', 'green', 'blue'],1982hsl: ['hue', 'saturation', 'lightness'],1983hsv: ['hue', 'saturation', 'value'],1984hwb: ['hue', 'whiteness', 'blackness'],1985cmyk: ['cyan', 'magenta', 'yellow', 'black']1986};19871988Color.prototype.maxes = {1989rgb: [255, 255, 255],1990hsl: [360, 100, 100],1991hsv: [360, 100, 100],1992hwb: [360, 100, 100],1993cmyk: [100, 100, 100, 100]1994};19951996Color.prototype.getValues = function (space) {1997var values = this.values;1998var vals = {};19992000for (var i = 0; i < space.length; i++) {2001vals[space.charAt(i)] = values[space][i];2002}20032004if (values.alpha !== 1) {2005vals.a = values.alpha;2006}20072008// {r: 255, g: 255, b: 255, a: 0.4}2009return vals;2010};20112012Color.prototype.setValues = function (space, vals) {2013var values = this.values;2014var spaces = this.spaces;2015var maxes = this.maxes;2016var alpha = 1;2017var i;20182019this.valid = true;20202021if (space === 'alpha') {2022alpha = vals;2023} else if (vals.length) {2024// [10, 10, 10]2025values[space] = vals.slice(0, space.length);2026alpha = vals[space.length];2027} else if (vals[space.charAt(0)] !== undefined) {2028// {r: 10, g: 10, b: 10}2029for (i = 0; i < space.length; i++) {2030values[space][i] = vals[space.charAt(i)];2031}20322033alpha = vals.a;2034} else if (vals[spaces[space][0]] !== undefined) {2035// {red: 10, green: 10, blue: 10}2036var chans = spaces[space];20372038for (i = 0; i < space.length; i++) {2039values[space][i] = vals[chans[i]];2040}20412042alpha = vals.alpha;2043}20442045values.alpha = Math.max(0, Math.min(1, (alpha === undefined ? values.alpha : alpha)));20462047if (space === 'alpha') {2048return false;2049}20502051var capped;20522053// cap values of the space prior converting all values2054for (i = 0; i < space.length; i++) {2055capped = Math.max(0, Math.min(maxes[space][i], values[space][i]));2056values[space][i] = Math.round(capped);2057}20582059// convert to all the other color spaces2060for (var sname in spaces) {2061if (sname !== space) {2062values[sname] = colorConvert[space][sname](values[space]);2063}2064}20652066return true;2067};20682069Color.prototype.setSpace = function (space, args) {2070var vals = args[0];20712072if (vals === undefined) {2073// color.rgb()2074return this.getValues(space);2075}20762077// color.rgb(10, 10, 10)2078if (typeof vals === 'number') {2079vals = Array.prototype.slice.call(args);2080}20812082this.setValues(space, vals);2083return this;2084};20852086Color.prototype.setChannel = function (space, index, val) {2087var svalues = this.values[space];2088if (val === undefined) {2089// color.red()2090return svalues[index];2091} else if (val === svalues[index]) {2092// color.red(color.red())2093return this;2094}20952096// color.red(100)2097svalues[index] = val;2098this.setValues(space, svalues);20992100return this;2101};21022103if (typeof window !== 'undefined') {2104window.Color = Color;2105}21062107var chartjsColor = Color;21082109/**2110* @namespace Chart.helpers2111*/2112var helpers = {2113/**2114* An empty function that can be used, for example, for optional callback.2115*/2116noop: function() {},21172118/**2119* Returns a unique id, sequentially generated from a global variable.2120* @returns {number}2121* @function2122*/2123uid: (function() {2124var id = 0;2125return function() {2126return id++;2127};2128}()),21292130/**2131* Returns true if `value` is neither null nor undefined, else returns false.2132* @param {*} value - The value to test.2133* @returns {boolean}2134* @since 2.7.02135*/2136isNullOrUndef: function(value) {2137return value === null || typeof value === 'undefined';2138},21392140/**2141* Returns true if `value` is an array (including typed arrays), else returns false.2142* @param {*} value - The value to test.2143* @returns {boolean}2144* @function2145*/2146isArray: function(value) {2147if (Array.isArray && Array.isArray(value)) {2148return true;2149}2150var type = Object.prototype.toString.call(value);2151if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {2152return true;2153}2154return false;2155},21562157/**2158* Returns true if `value` is an object (excluding null), else returns false.2159* @param {*} value - The value to test.2160* @returns {boolean}2161* @since 2.7.02162*/2163isObject: function(value) {2164return value !== null && Object.prototype.toString.call(value) === '[object Object]';2165},21662167/**2168* Returns true if `value` is a finite number, else returns false2169* @param {*} value - The value to test.2170* @returns {boolean}2171*/2172isFinite: function(value) {2173return (typeof value === 'number' || value instanceof Number) && isFinite(value);2174},21752176/**2177* Returns `value` if defined, else returns `defaultValue`.2178* @param {*} value - The value to return if defined.2179* @param {*} defaultValue - The value to return if `value` is undefined.2180* @returns {*}2181*/2182valueOrDefault: function(value, defaultValue) {2183return typeof value === 'undefined' ? defaultValue : value;2184},21852186/**2187* Returns value at the given `index` in array if defined, else returns `defaultValue`.2188* @param {Array} value - The array to lookup for value at `index`.2189* @param {number} index - The index in `value` to lookup for value.2190* @param {*} defaultValue - The value to return if `value[index]` is undefined.2191* @returns {*}2192*/2193valueAtIndexOrDefault: function(value, index, defaultValue) {2194return helpers.valueOrDefault(helpers.isArray(value) ? value[index] : value, defaultValue);2195},21962197/**2198* Calls `fn` with the given `args` in the scope defined by `thisArg` and returns the2199* value returned by `fn`. If `fn` is not a function, this method returns undefined.2200* @param {function} fn - The function to call.2201* @param {Array|undefined|null} args - The arguments with which `fn` should be called.2202* @param {object} [thisArg] - The value of `this` provided for the call to `fn`.2203* @returns {*}2204*/2205callback: function(fn, args, thisArg) {2206if (fn && typeof fn.call === 'function') {2207return fn.apply(thisArg, args);2208}2209},22102211/**2212* Note(SB) for performance sake, this method should only be used when loopable type2213* is unknown or in none intensive code (not called often and small loopable). Else2214* it's preferable to use a regular for() loop and save extra function calls.2215* @param {object|Array} loopable - The object or array to be iterated.2216* @param {function} fn - The function to call for each item.2217* @param {object} [thisArg] - The value of `this` provided for the call to `fn`.2218* @param {boolean} [reverse] - If true, iterates backward on the loopable.2219*/2220each: function(loopable, fn, thisArg, reverse) {2221var i, len, keys;2222if (helpers.isArray(loopable)) {2223len = loopable.length;2224if (reverse) {2225for (i = len - 1; i >= 0; i--) {2226fn.call(thisArg, loopable[i], i);2227}2228} else {2229for (i = 0; i < len; i++) {2230fn.call(thisArg, loopable[i], i);2231}2232}2233} else if (helpers.isObject(loopable)) {2234keys = Object.keys(loopable);2235len = keys.length;2236for (i = 0; i < len; i++) {2237fn.call(thisArg, loopable[keys[i]], keys[i]);2238}2239}2240},22412242/**2243* Returns true if the `a0` and `a1` arrays have the same content, else returns false.2244* @see https://stackoverflow.com/a/148539742245* @param {Array} a0 - The array to compare2246* @param {Array} a1 - The array to compare2247* @returns {boolean}2248*/2249arrayEquals: function(a0, a1) {2250var i, ilen, v0, v1;22512252if (!a0 || !a1 || a0.length !== a1.length) {2253return false;2254}22552256for (i = 0, ilen = a0.length; i < ilen; ++i) {2257v0 = a0[i];2258v1 = a1[i];22592260if (v0 instanceof Array && v1 instanceof Array) {2261if (!helpers.arrayEquals(v0, v1)) {2262return false;2263}2264} else if (v0 !== v1) {2265// NOTE: two different object instances will never be equal: {x:20} != {x:20}2266return false;2267}2268}22692270return true;2271},22722273/**2274* Returns a deep copy of `source` without keeping references on objects and arrays.2275* @param {*} source - The value to clone.2276* @returns {*}2277*/2278clone: function(source) {2279if (helpers.isArray(source)) {2280return source.map(helpers.clone);2281}22822283if (helpers.isObject(source)) {2284var target = {};2285var keys = Object.keys(source);2286var klen = keys.length;2287var k = 0;22882289for (; k < klen; ++k) {2290target[keys[k]] = helpers.clone(source[keys[k]]);2291}22922293return target;2294}22952296return source;2297},22982299/**2300* The default merger when Chart.helpers.merge is called without merger option.2301* Note(SB): also used by mergeConfig and mergeScaleConfig as fallback.2302* @private2303*/2304_merger: function(key, target, source, options) {2305var tval = target[key];2306var sval = source[key];23072308if (helpers.isObject(tval) && helpers.isObject(sval)) {2309helpers.merge(tval, sval, options);2310} else {2311target[key] = helpers.clone(sval);2312}2313},23142315/**2316* Merges source[key] in target[key] only if target[key] is undefined.2317* @private2318*/2319_mergerIf: function(key, target, source) {2320var tval = target[key];2321var sval = source[key];23222323if (helpers.isObject(tval) && helpers.isObject(sval)) {2324helpers.mergeIf(tval, sval);2325} else if (!target.hasOwnProperty(key)) {2326target[key] = helpers.clone(sval);2327}2328},23292330/**2331* Recursively deep copies `source` properties into `target` with the given `options`.2332* IMPORTANT: `target` is not cloned and will be updated with `source` properties.2333* @param {object} target - The target object in which all sources are merged into.2334* @param {object|object[]} source - Object(s) to merge into `target`.2335* @param {object} [options] - Merging options:2336* @param {function} [options.merger] - The merge method (key, target, source, options)2337* @returns {object} The `target` object.2338*/2339merge: function(target, source, options) {2340var sources = helpers.isArray(source) ? source : [source];2341var ilen = sources.length;2342var merge, i, keys, klen, k;23432344if (!helpers.isObject(target)) {2345return target;2346}23472348options = options || {};2349merge = options.merger || helpers._merger;23502351for (i = 0; i < ilen; ++i) {2352source = sources[i];2353if (!helpers.isObject(source)) {2354continue;2355}23562357keys = Object.keys(source);2358for (k = 0, klen = keys.length; k < klen; ++k) {2359merge(keys[k], target, source, options);2360}2361}23622363return target;2364},23652366/**2367* Recursively deep copies `source` properties into `target` *only* if not defined in target.2368* IMPORTANT: `target` is not cloned and will be updated with `source` properties.2369* @param {object} target - The target object in which all sources are merged into.2370* @param {object|object[]} source - Object(s) to merge into `target`.2371* @returns {object} The `target` object.2372*/2373mergeIf: function(target, source) {2374return helpers.merge(target, source, {merger: helpers._mergerIf});2375},23762377/**2378* Applies the contents of two or more objects together into the first object.2379* @param {object} target - The target object in which all objects are merged into.2380* @param {object} arg1 - Object containing additional properties to merge in target.2381* @param {object} argN - Additional objects containing properties to merge in target.2382* @returns {object} The `target` object.2383*/2384extend: Object.assign || function(target) {2385return helpers.merge(target, [].slice.call(arguments, 1), {2386merger: function(key, dst, src) {2387dst[key] = src[key];2388}2389});2390},23912392/**2393* Basic javascript inheritance based on the model created in Backbone.js2394*/2395inherits: function(extensions) {2396var me = this;2397var ChartElement = (extensions && extensions.hasOwnProperty('constructor')) ? extensions.constructor : function() {2398return me.apply(this, arguments);2399};24002401var Surrogate = function() {2402this.constructor = ChartElement;2403};24042405Surrogate.prototype = me.prototype;2406ChartElement.prototype = new Surrogate();2407ChartElement.extend = helpers.inherits;24082409if (extensions) {2410helpers.extend(ChartElement.prototype, extensions);2411}24122413ChartElement.__super__ = me.prototype;2414return ChartElement;2415},24162417_deprecated: function(scope, value, previous, current) {2418if (value !== undefined) {2419console.warn(scope + ': "' + previous +2420'" is deprecated. Please use "' + current + '" instead');2421}2422}2423};24242425var helpers_core = helpers;24262427// DEPRECATIONS24282429/**2430* Provided for backward compatibility, use Chart.helpers.callback instead.2431* @function Chart.helpers.callCallback2432* @deprecated since version 2.6.02433* @todo remove at version 32434* @private2435*/2436helpers.callCallback = helpers.callback;24372438/**2439* Provided for backward compatibility, use Array.prototype.indexOf instead.2440* Array.prototype.indexOf compatibility: Chrome, Opera, Safari, FF1.5+, IE9+2441* @function Chart.helpers.indexOf2442* @deprecated since version 2.7.02443* @todo remove at version 32444* @private2445*/2446helpers.indexOf = function(array, item, fromIndex) {2447return Array.prototype.indexOf.call(array, item, fromIndex);2448};24492450/**2451* Provided for backward compatibility, use Chart.helpers.valueOrDefault instead.2452* @function Chart.helpers.getValueOrDefault2453* @deprecated since version 2.7.02454* @todo remove at version 32455* @private2456*/2457helpers.getValueOrDefault = helpers.valueOrDefault;24582459/**2460* Provided for backward compatibility, use Chart.helpers.valueAtIndexOrDefault instead.2461* @function Chart.helpers.getValueAtIndexOrDefault2462* @deprecated since version 2.7.02463* @todo remove at version 32464* @private2465*/2466helpers.getValueAtIndexOrDefault = helpers.valueAtIndexOrDefault;24672468/**2469* Easing functions adapted from Robert Penner's easing equations.2470* @namespace Chart.helpers.easingEffects2471* @see http://www.robertpenner.com/easing/2472*/2473var effects = {2474linear: function(t) {2475return t;2476},24772478easeInQuad: function(t) {2479return t * t;2480},24812482easeOutQuad: function(t) {2483return -t * (t - 2);2484},24852486easeInOutQuad: function(t) {2487if ((t /= 0.5) < 1) {2488return 0.5 * t * t;2489}2490return -0.5 * ((--t) * (t - 2) - 1);2491},24922493easeInCubic: function(t) {2494return t * t * t;2495},24962497easeOutCubic: function(t) {2498return (t = t - 1) * t * t + 1;2499},25002501easeInOutCubic: function(t) {2502if ((t /= 0.5) < 1) {2503return 0.5 * t * t * t;2504}2505return 0.5 * ((t -= 2) * t * t + 2);2506},25072508easeInQuart: function(t) {2509return t * t * t * t;2510},25112512easeOutQuart: function(t) {2513return -((t = t - 1) * t * t * t - 1);2514},25152516easeInOutQuart: function(t) {2517if ((t /= 0.5) < 1) {2518return 0.5 * t * t * t * t;2519}2520return -0.5 * ((t -= 2) * t * t * t - 2);2521},25222523easeInQuint: function(t) {2524return t * t * t * t * t;2525},25262527easeOutQuint: function(t) {2528return (t = t - 1) * t * t * t * t + 1;2529},25302531easeInOutQuint: function(t) {2532if ((t /= 0.5) < 1) {2533return 0.5 * t * t * t * t * t;2534}2535return 0.5 * ((t -= 2) * t * t * t * t + 2);2536},25372538easeInSine: function(t) {2539return -Math.cos(t * (Math.PI / 2)) + 1;2540},25412542easeOutSine: function(t) {2543return Math.sin(t * (Math.PI / 2));2544},25452546easeInOutSine: function(t) {2547return -0.5 * (Math.cos(Math.PI * t) - 1);2548},25492550easeInExpo: function(t) {2551return (t === 0) ? 0 : Math.pow(2, 10 * (t - 1));2552},25532554easeOutExpo: function(t) {2555return (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1;2556},25572558easeInOutExpo: function(t) {2559if (t === 0) {2560return 0;2561}2562if (t === 1) {2563return 1;2564}2565if ((t /= 0.5) < 1) {2566return 0.5 * Math.pow(2, 10 * (t - 1));2567}2568return 0.5 * (-Math.pow(2, -10 * --t) + 2);2569},25702571easeInCirc: function(t) {2572if (t >= 1) {2573return t;2574}2575return -(Math.sqrt(1 - t * t) - 1);2576},25772578easeOutCirc: function(t) {2579return Math.sqrt(1 - (t = t - 1) * t);2580},25812582easeInOutCirc: function(t) {2583if ((t /= 0.5) < 1) {2584return -0.5 * (Math.sqrt(1 - t * t) - 1);2585}2586return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);2587},25882589easeInElastic: function(t) {2590var s = 1.70158;2591var p = 0;2592var a = 1;2593if (t === 0) {2594return 0;2595}2596if (t === 1) {2597return 1;2598}2599if (!p) {2600p = 0.3;2601}2602if (a < 1) {2603a = 1;2604s = p / 4;2605} else {2606s = p / (2 * Math.PI) * Math.asin(1 / a);2607}2608return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));2609},26102611easeOutElastic: function(t) {2612var s = 1.70158;2613var p = 0;2614var a = 1;2615if (t === 0) {2616return 0;2617}2618if (t === 1) {2619return 1;2620}2621if (!p) {2622p = 0.3;2623}2624if (a < 1) {2625a = 1;2626s = p / 4;2627} else {2628s = p / (2 * Math.PI) * Math.asin(1 / a);2629}2630return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1;2631},26322633easeInOutElastic: function(t) {2634var s = 1.70158;2635var p = 0;2636var a = 1;2637if (t === 0) {2638return 0;2639}2640if ((t /= 0.5) === 2) {2641return 1;2642}2643if (!p) {2644p = 0.45;2645}2646if (a < 1) {2647a = 1;2648s = p / 4;2649} else {2650s = p / (2 * Math.PI) * Math.asin(1 / a);2651}2652if (t < 1) {2653return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p));2654}2655return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1;2656},2657easeInBack: function(t) {2658var s = 1.70158;2659return t * t * ((s + 1) * t - s);2660},26612662easeOutBack: function(t) {2663var s = 1.70158;2664return (t = t - 1) * t * ((s + 1) * t + s) + 1;2665},26662667easeInOutBack: function(t) {2668var s = 1.70158;2669if ((t /= 0.5) < 1) {2670return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));2671}2672return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);2673},26742675easeInBounce: function(t) {2676return 1 - effects.easeOutBounce(1 - t);2677},26782679easeOutBounce: function(t) {2680if (t < (1 / 2.75)) {2681return 7.5625 * t * t;2682}2683if (t < (2 / 2.75)) {2684return 7.5625 * (t -= (1.5 / 2.75)) * t + 0.75;2685}2686if (t < (2.5 / 2.75)) {2687return 7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375;2688}2689return 7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375;2690},26912692easeInOutBounce: function(t) {2693if (t < 0.5) {2694return effects.easeInBounce(t * 2) * 0.5;2695}2696return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5;2697}2698};26992700var helpers_easing = {2701effects: effects2702};27032704// DEPRECATIONS27052706/**2707* Provided for backward compatibility, use Chart.helpers.easing.effects instead.2708* @function Chart.helpers.easingEffects2709* @deprecated since version 2.7.02710* @todo remove at version 32711* @private2712*/2713helpers_core.easingEffects = effects;27142715var PI = Math.PI;2716var RAD_PER_DEG = PI / 180;2717var DOUBLE_PI = PI * 2;2718var HALF_PI = PI / 2;2719var QUARTER_PI = PI / 4;2720var TWO_THIRDS_PI = PI * 2 / 3;27212722/**2723* @namespace Chart.helpers.canvas2724*/2725var exports$1 = {2726/**2727* Clears the entire canvas associated to the given `chart`.2728* @param {Chart} chart - The chart for which to clear the canvas.2729*/2730clear: function(chart) {2731chart.ctx.clearRect(0, 0, chart.width, chart.height);2732},27332734/**2735* Creates a "path" for a rectangle with rounded corners at position (x, y) with a2736* given size (width, height) and the same `radius` for all corners.2737* @param {CanvasRenderingContext2D} ctx - The canvas 2D Context.2738* @param {number} x - The x axis of the coordinate for the rectangle starting point.2739* @param {number} y - The y axis of the coordinate for the rectangle starting point.2740* @param {number} width - The rectangle's width.2741* @param {number} height - The rectangle's height.2742* @param {number} radius - The rounded amount (in pixels) for the four corners.2743* @todo handle `radius` as top-left, top-right, bottom-right, bottom-left array/object?2744*/2745roundedRect: function(ctx, x, y, width, height, radius) {2746if (radius) {2747var r = Math.min(radius, height / 2, width / 2);2748var left = x + r;2749var top = y + r;2750var right = x + width - r;2751var bottom = y + height - r;27522753ctx.moveTo(x, top);2754if (left < right && top < bottom) {2755ctx.arc(left, top, r, -PI, -HALF_PI);2756ctx.arc(right, top, r, -HALF_PI, 0);2757ctx.arc(right, bottom, r, 0, HALF_PI);2758ctx.arc(left, bottom, r, HALF_PI, PI);2759} else if (left < right) {2760ctx.moveTo(left, y);2761ctx.arc(right, top, r, -HALF_PI, HALF_PI);2762ctx.arc(left, top, r, HALF_PI, PI + HALF_PI);2763} else if (top < bottom) {2764ctx.arc(left, top, r, -PI, 0);2765ctx.arc(left, bottom, r, 0, PI);2766} else {2767ctx.arc(left, top, r, -PI, PI);2768}2769ctx.closePath();2770ctx.moveTo(x, y);2771} else {2772ctx.rect(x, y, width, height);2773}2774},27752776drawPoint: function(ctx, style, radius, x, y, rotation) {2777var type, xOffset, yOffset, size, cornerRadius;2778var rad = (rotation || 0) * RAD_PER_DEG;27792780if (style && typeof style === 'object') {2781type = style.toString();2782if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {2783ctx.save();2784ctx.translate(x, y);2785ctx.rotate(rad);2786ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);2787ctx.restore();2788return;2789}2790}27912792if (isNaN(radius) || radius <= 0) {2793return;2794}27952796ctx.beginPath();27972798switch (style) {2799// Default includes circle2800default:2801ctx.arc(x, y, radius, 0, DOUBLE_PI);2802ctx.closePath();2803break;2804case 'triangle':2805ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);2806rad += TWO_THIRDS_PI;2807ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);2808rad += TWO_THIRDS_PI;2809ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);2810ctx.closePath();2811break;2812case 'rectRounded':2813// NOTE: the rounded rect implementation changed to use `arc` instead of2814// `quadraticCurveTo` since it generates better results when rect is2815// almost a circle. 0.516 (instead of 0.5) produces results with visually2816// closer proportion to the previous impl and it is inscribed in the2817// circle with `radius`. For more details, see the following PRs:2818// https://github.com/chartjs/Chart.js/issues/55972819// https://github.com/chartjs/Chart.js/issues/58582820cornerRadius = radius * 0.516;2821size = radius - cornerRadius;2822xOffset = Math.cos(rad + QUARTER_PI) * size;2823yOffset = Math.sin(rad + QUARTER_PI) * size;2824ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);2825ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);2826ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);2827ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);2828ctx.closePath();2829break;2830case 'rect':2831if (!rotation) {2832size = Math.SQRT1_2 * radius;2833ctx.rect(x - size, y - size, 2 * size, 2 * size);2834break;2835}2836rad += QUARTER_PI;2837/* falls through */2838case 'rectRot':2839xOffset = Math.cos(rad) * radius;2840yOffset = Math.sin(rad) * radius;2841ctx.moveTo(x - xOffset, y - yOffset);2842ctx.lineTo(x + yOffset, y - xOffset);2843ctx.lineTo(x + xOffset, y + yOffset);2844ctx.lineTo(x - yOffset, y + xOffset);2845ctx.closePath();2846break;2847case 'crossRot':2848rad += QUARTER_PI;2849/* falls through */2850case 'cross':2851xOffset = Math.cos(rad) * radius;2852yOffset = Math.sin(rad) * radius;2853ctx.moveTo(x - xOffset, y - yOffset);2854ctx.lineTo(x + xOffset, y + yOffset);2855ctx.moveTo(x + yOffset, y - xOffset);2856ctx.lineTo(x - yOffset, y + xOffset);2857break;2858case 'star':2859xOffset = Math.cos(rad) * radius;2860yOffset = Math.sin(rad) * radius;2861ctx.moveTo(x - xOffset, y - yOffset);2862ctx.lineTo(x + xOffset, y + yOffset);2863ctx.moveTo(x + yOffset, y - xOffset);2864ctx.lineTo(x - yOffset, y + xOffset);2865rad += QUARTER_PI;2866xOffset = Math.cos(rad) * radius;2867yOffset = Math.sin(rad) * radius;2868ctx.moveTo(x - xOffset, y - yOffset);2869ctx.lineTo(x + xOffset, y + yOffset);2870ctx.moveTo(x + yOffset, y - xOffset);2871ctx.lineTo(x - yOffset, y + xOffset);2872break;2873case 'line':2874xOffset = Math.cos(rad) * radius;2875yOffset = Math.sin(rad) * radius;2876ctx.moveTo(x - xOffset, y - yOffset);2877ctx.lineTo(x + xOffset, y + yOffset);2878break;2879case 'dash':2880ctx.moveTo(x, y);2881ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);2882break;2883}28842885ctx.fill();2886ctx.stroke();2887},28882889/**2890* Returns true if the point is inside the rectangle2891* @param {object} point - The point to test2892* @param {object} area - The rectangle2893* @returns {boolean}2894* @private2895*/2896_isPointInArea: function(point, area) {2897var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.28982899return point.x > area.left - epsilon && point.x < area.right + epsilon &&2900point.y > area.top - epsilon && point.y < area.bottom + epsilon;2901},29022903clipArea: function(ctx, area) {2904ctx.save();2905ctx.beginPath();2906ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);2907ctx.clip();2908},29092910unclipArea: function(ctx) {2911ctx.restore();2912},29132914lineTo: function(ctx, previous, target, flip) {2915var stepped = target.steppedLine;2916if (stepped) {2917if (stepped === 'middle') {2918var midpoint = (previous.x + target.x) / 2.0;2919ctx.lineTo(midpoint, flip ? target.y : previous.y);2920ctx.lineTo(midpoint, flip ? previous.y : target.y);2921} else if ((stepped === 'after' && !flip) || (stepped !== 'after' && flip)) {2922ctx.lineTo(previous.x, target.y);2923} else {2924ctx.lineTo(target.x, previous.y);2925}2926ctx.lineTo(target.x, target.y);2927return;2928}29292930if (!target.tension) {2931ctx.lineTo(target.x, target.y);2932return;2933}29342935ctx.bezierCurveTo(2936flip ? previous.controlPointPreviousX : previous.controlPointNextX,2937flip ? previous.controlPointPreviousY : previous.controlPointNextY,2938flip ? target.controlPointNextX : target.controlPointPreviousX,2939flip ? target.controlPointNextY : target.controlPointPreviousY,2940target.x,2941target.y);2942}2943};29442945var helpers_canvas = exports$1;29462947// DEPRECATIONS29482949/**2950* Provided for backward compatibility, use Chart.helpers.canvas.clear instead.2951* @namespace Chart.helpers.clear2952* @deprecated since version 2.7.02953* @todo remove at version 32954* @private2955*/2956helpers_core.clear = exports$1.clear;29572958/**2959* Provided for backward compatibility, use Chart.helpers.canvas.roundedRect instead.2960* @namespace Chart.helpers.drawRoundedRectangle2961* @deprecated since version 2.7.02962* @todo remove at version 32963* @private2964*/2965helpers_core.drawRoundedRectangle = function(ctx) {2966ctx.beginPath();2967exports$1.roundedRect.apply(exports$1, arguments);2968};29692970var defaults = {2971/**2972* @private2973*/2974_set: function(scope, values) {2975return helpers_core.merge(this[scope] || (this[scope] = {}), values);2976}2977};29782979// TODO(v3): remove 'global' from namespace. all default are global and2980// there's inconsistency around which options are under 'global'2981defaults._set('global', {2982defaultColor: 'rgba(0,0,0,0.1)',2983defaultFontColor: '#666',2984defaultFontFamily: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",2985defaultFontSize: 12,2986defaultFontStyle: 'normal',2987defaultLineHeight: 1.2,2988showLines: true2989});29902991var core_defaults = defaults;29922993var valueOrDefault = helpers_core.valueOrDefault;29942995/**2996* Converts the given font object into a CSS font string.2997* @param {object} font - A font object.2998* @return {string} The CSS font string. See https://developer.mozilla.org/en-US/docs/Web/CSS/font2999* @private3000*/3001function toFontString(font) {3002if (!font || helpers_core.isNullOrUndef(font.size) || helpers_core.isNullOrUndef(font.family)) {3003return null;3004}30053006return (font.style ? font.style + ' ' : '')3007+ (font.weight ? font.weight + ' ' : '')3008+ font.size + 'px '3009+ font.family;3010}30113012/**3013* @alias Chart.helpers.options3014* @namespace3015*/3016var helpers_options = {3017/**3018* Converts the given line height `value` in pixels for a specific font `size`.3019* @param {number|string} value - The lineHeight to parse (eg. 1.6, '14px', '75%', '1.6em').3020* @param {number} size - The font size (in pixels) used to resolve relative `value`.3021* @returns {number} The effective line height in pixels (size * 1.2 if value is invalid).3022* @see https://developer.mozilla.org/en-US/docs/Web/CSS/line-height3023* @since 2.7.03024*/3025toLineHeight: function(value, size) {3026var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);3027if (!matches || matches[1] === 'normal') {3028return size * 1.2;3029}30303031value = +matches[2];30323033switch (matches[3]) {3034case 'px':3035return value;3036case '%':3037value /= 100;3038break;3039}30403041return size * value;3042},30433044/**3045* Converts the given value into a padding object with pre-computed width/height.3046* @param {number|object} value - If a number, set the value to all TRBL component,3047* else, if and object, use defined properties and sets undefined ones to 0.3048* @returns {object} The padding values (top, right, bottom, left, width, height)3049* @since 2.7.03050*/3051toPadding: function(value) {3052var t, r, b, l;30533054if (helpers_core.isObject(value)) {3055t = +value.top || 0;3056r = +value.right || 0;3057b = +value.bottom || 0;3058l = +value.left || 0;3059} else {3060t = r = b = l = +value || 0;3061}30623063return {3064top: t,3065right: r,3066bottom: b,3067left: l,3068height: t + b,3069width: l + r3070};3071},30723073/**3074* Parses font options and returns the font object.3075* @param {object} options - A object that contains font options to be parsed.3076* @return {object} The font object.3077* @todo Support font.* options and renamed to toFont().3078* @private3079*/3080_parseFont: function(options) {3081var globalDefaults = core_defaults.global;3082var size = valueOrDefault(options.fontSize, globalDefaults.defaultFontSize);3083var font = {3084family: valueOrDefault(options.fontFamily, globalDefaults.defaultFontFamily),3085lineHeight: helpers_core.options.toLineHeight(valueOrDefault(options.lineHeight, globalDefaults.defaultLineHeight), size),3086size: size,3087style: valueOrDefault(options.fontStyle, globalDefaults.defaultFontStyle),3088weight: null,3089string: ''3090};30913092font.string = toFontString(font);3093return font;3094},30953096/**3097* Evaluates the given `inputs` sequentially and returns the first defined value.3098* @param {Array} inputs - An array of values, falling back to the last value.3099* @param {object} [context] - If defined and the current value is a function, the value3100* is called with `context` as first argument and the result becomes the new input.3101* @param {number} [index] - If defined and the current value is an array, the value3102* at `index` become the new input.3103* @param {object} [info] - object to return information about resolution in3104* @param {boolean} [info.cacheable] - Will be set to `false` if option is not cacheable.3105* @since 2.7.03106*/3107resolve: function(inputs, context, index, info) {3108var cacheable = true;3109var i, ilen, value;31103111for (i = 0, ilen = inputs.length; i < ilen; ++i) {3112value = inputs[i];3113if (value === undefined) {3114continue;3115}3116if (context !== undefined && typeof value === 'function') {3117value = value(context);3118cacheable = false;3119}3120if (index !== undefined && helpers_core.isArray(value)) {3121value = value[index];3122cacheable = false;3123}3124if (value !== undefined) {3125if (info && !cacheable) {3126info.cacheable = false;3127}3128return value;3129}3130}3131}3132};31333134/**3135* @alias Chart.helpers.math3136* @namespace3137*/3138var exports$2 = {3139/**3140* Returns an array of factors sorted from 1 to sqrt(value)3141* @private3142*/3143_factorize: function(value) {3144var result = [];3145var sqrt = Math.sqrt(value);3146var i;31473148for (i = 1; i < sqrt; i++) {3149if (value % i === 0) {3150result.push(i);3151result.push(value / i);3152}3153}3154if (sqrt === (sqrt | 0)) { // if value is a square number3155result.push(sqrt);3156}31573158result.sort(function(a, b) {3159return a - b;3160}).pop();3161return result;3162},31633164log10: Math.log10 || function(x) {3165var exponent = Math.log(x) * Math.LOG10E; // Math.LOG10E = 1 / Math.LN10.3166// Check for whole powers of 10,3167// which due to floating point rounding error should be corrected.3168var powerOf10 = Math.round(exponent);3169var isPowerOf10 = x === Math.pow(10, powerOf10);31703171return isPowerOf10 ? powerOf10 : exponent;3172}3173};31743175var helpers_math = exports$2;31763177// DEPRECATIONS31783179/**3180* Provided for backward compatibility, use Chart.helpers.math.log10 instead.3181* @namespace Chart.helpers.log103182* @deprecated since version 2.9.03183* @todo remove at version 33184* @private3185*/3186helpers_core.log10 = exports$2.log10;31873188var getRtlAdapter = function(rectX, width) {3189return {3190x: function(x) {3191return rectX + rectX + width - x;3192},3193setWidth: function(w) {3194width = w;3195},3196textAlign: function(align) {3197if (align === 'center') {3198return align;3199}3200return align === 'right' ? 'left' : 'right';3201},3202xPlus: function(x, value) {3203return x - value;3204},3205leftForLtr: function(x, itemWidth) {3206return x - itemWidth;3207},3208};3209};32103211var getLtrAdapter = function() {3212return {3213x: function(x) {3214return x;3215},3216setWidth: function(w) { // eslint-disable-line no-unused-vars3217},3218textAlign: function(align) {3219return align;3220},3221xPlus: function(x, value) {3222return x + value;3223},3224leftForLtr: function(x, _itemWidth) { // eslint-disable-line no-unused-vars3225return x;3226},3227};3228};32293230var getAdapter = function(rtl, rectX, width) {3231return rtl ? getRtlAdapter(rectX, width) : getLtrAdapter();3232};32333234var overrideTextDirection = function(ctx, direction) {3235var style, original;3236if (direction === 'ltr' || direction === 'rtl') {3237style = ctx.canvas.style;3238original = [3239style.getPropertyValue('direction'),3240style.getPropertyPriority('direction'),3241];32423243style.setProperty('direction', direction, 'important');3244ctx.prevTextDirection = original;3245}3246};32473248var restoreTextDirection = function(ctx) {3249var original = ctx.prevTextDirection;3250if (original !== undefined) {3251delete ctx.prevTextDirection;3252ctx.canvas.style.setProperty('direction', original[0], original[1]);3253}3254};32553256var helpers_rtl = {3257getRtlAdapter: getAdapter,3258overrideTextDirection: overrideTextDirection,3259restoreTextDirection: restoreTextDirection,3260};32613262var helpers$1 = helpers_core;3263var easing = helpers_easing;3264var canvas = helpers_canvas;3265var options = helpers_options;3266var math = helpers_math;3267var rtl = helpers_rtl;3268helpers$1.easing = easing;3269helpers$1.canvas = canvas;3270helpers$1.options = options;3271helpers$1.math = math;3272helpers$1.rtl = rtl;32733274function interpolate(start, view, model, ease) {3275var keys = Object.keys(model);3276var i, ilen, key, actual, origin, target, type, c0, c1;32773278for (i = 0, ilen = keys.length; i < ilen; ++i) {3279key = keys[i];32803281target = model[key];32823283// if a value is added to the model after pivot() has been called, the view3284// doesn't contain it, so let's initialize the view to the target value.3285if (!view.hasOwnProperty(key)) {3286view[key] = target;3287}32883289actual = view[key];32903291if (actual === target || key[0] === '_') {3292continue;3293}32943295if (!start.hasOwnProperty(key)) {3296start[key] = actual;3297}32983299origin = start[key];33003301type = typeof target;33023303if (type === typeof origin) {3304if (type === 'string') {3305c0 = chartjsColor(origin);3306if (c0.valid) {3307c1 = chartjsColor(target);3308if (c1.valid) {3309view[key] = c1.mix(c0, ease).rgbString();3310continue;3311}3312}3313} else if (helpers$1.isFinite(origin) && helpers$1.isFinite(target)) {3314view[key] = origin + (target - origin) * ease;3315continue;3316}3317}33183319view[key] = target;3320}3321}33223323var Element = function(configuration) {3324helpers$1.extend(this, configuration);3325this.initialize.apply(this, arguments);3326};33273328helpers$1.extend(Element.prototype, {3329_type: undefined,33303331initialize: function() {3332this.hidden = false;3333},33343335pivot: function() {3336var me = this;3337if (!me._view) {3338me._view = helpers$1.extend({}, me._model);3339}3340me._start = {};3341return me;3342},33433344transition: function(ease) {3345var me = this;3346var model = me._model;3347var start = me._start;3348var view = me._view;33493350// No animation -> No Transition3351if (!model || ease === 1) {3352me._view = helpers$1.extend({}, model);3353me._start = null;3354return me;3355}33563357if (!view) {3358view = me._view = {};3359}33603361if (!start) {3362start = me._start = {};3363}33643365interpolate(start, view, model, ease);33663367return me;3368},33693370tooltipPosition: function() {3371return {3372x: this._model.x,3373y: this._model.y3374};3375},33763377hasValue: function() {3378return helpers$1.isNumber(this._model.x) && helpers$1.isNumber(this._model.y);3379}3380});33813382Element.extend = helpers$1.inherits;33833384var core_element = Element;33853386var exports$3 = core_element.extend({3387chart: null, // the animation associated chart instance3388currentStep: 0, // the current animation step3389numSteps: 60, // default number of steps3390easing: '', // the easing to use for this animation3391render: null, // render function used by the animation service33923393onAnimationProgress: null, // user specified callback to fire on each step of the animation3394onAnimationComplete: null, // user specified callback to fire when the animation finishes3395});33963397var core_animation = exports$3;33983399// DEPRECATIONS34003401/**3402* Provided for backward compatibility, use Chart.Animation instead3403* @prop Chart.Animation#animationObject3404* @deprecated since version 2.6.03405* @todo remove at version 33406*/3407Object.defineProperty(exports$3.prototype, 'animationObject', {3408get: function() {3409return this;3410}3411});34123413/**3414* Provided for backward compatibility, use Chart.Animation#chart instead3415* @prop Chart.Animation#chartInstance3416* @deprecated since version 2.6.03417* @todo remove at version 33418*/3419Object.defineProperty(exports$3.prototype, 'chartInstance', {3420get: function() {3421return this.chart;3422},3423set: function(value) {3424this.chart = value;3425}3426});34273428core_defaults._set('global', {3429animation: {3430duration: 1000,3431easing: 'easeOutQuart',3432onProgress: helpers$1.noop,3433onComplete: helpers$1.noop3434}3435});34363437var core_animations = {3438animations: [],3439request: null,34403441/**3442* @param {Chart} chart - The chart to animate.3443* @param {Chart.Animation} animation - The animation that we will animate.3444* @param {number} duration - The animation duration in ms.3445* @param {boolean} lazy - if true, the chart is not marked as animating to enable more responsive interactions3446*/3447addAnimation: function(chart, animation, duration, lazy) {3448var animations = this.animations;3449var i, ilen;34503451animation.chart = chart;3452animation.startTime = Date.now();3453animation.duration = duration;34543455if (!lazy) {3456chart.animating = true;3457}34583459for (i = 0, ilen = animations.length; i < ilen; ++i) {3460if (animations[i].chart === chart) {3461animations[i] = animation;3462return;3463}3464}34653466animations.push(animation);34673468// If there are no animations queued, manually kickstart a digest, for lack of a better word3469if (animations.length === 1) {3470this.requestAnimationFrame();3471}3472},34733474cancelAnimation: function(chart) {3475var index = helpers$1.findIndex(this.animations, function(animation) {3476return animation.chart === chart;3477});34783479if (index !== -1) {3480this.animations.splice(index, 1);3481chart.animating = false;3482}3483},34843485requestAnimationFrame: function() {3486var me = this;3487if (me.request === null) {3488// Skip animation frame requests until the active one is executed.3489// This can happen when processing mouse events, e.g. 'mousemove'3490// and 'mouseout' events will trigger multiple renders.3491me.request = helpers$1.requestAnimFrame.call(window, function() {3492me.request = null;3493me.startDigest();3494});3495}3496},34973498/**3499* @private3500*/3501startDigest: function() {3502var me = this;35033504me.advance();35053506// Do we have more stuff to animate?3507if (me.animations.length > 0) {3508me.requestAnimationFrame();3509}3510},35113512/**3513* @private3514*/3515advance: function() {3516var animations = this.animations;3517var animation, chart, numSteps, nextStep;3518var i = 0;35193520// 1 animation per chart, so we are looping charts here3521while (i < animations.length) {3522animation = animations[i];3523chart = animation.chart;3524numSteps = animation.numSteps;35253526// Make sure that currentStep starts at 13527// https://github.com/chartjs/Chart.js/issues/61043528nextStep = Math.floor((Date.now() - animation.startTime) / animation.duration * numSteps) + 1;3529animation.currentStep = Math.min(nextStep, numSteps);35303531helpers$1.callback(animation.render, [chart, animation], chart);3532helpers$1.callback(animation.onAnimationProgress, [animation], chart);35333534if (animation.currentStep >= numSteps) {3535helpers$1.callback(animation.onAnimationComplete, [animation], chart);3536chart.animating = false;3537animations.splice(i, 1);3538} else {3539++i;3540}3541}3542}3543};35443545var resolve = helpers$1.options.resolve;35463547var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];35483549/**3550* Hooks the array methods that add or remove values ('push', pop', 'shift', 'splice',3551* 'unshift') and notify the listener AFTER the array has been altered. Listeners are3552* called on the 'onData*' callbacks (e.g. onDataPush, etc.) with same arguments.3553*/3554function listenArrayEvents(array, listener) {3555if (array._chartjs) {3556array._chartjs.listeners.push(listener);3557return;3558}35593560Object.defineProperty(array, '_chartjs', {3561configurable: true,3562enumerable: false,3563value: {3564listeners: [listener]3565}3566});35673568arrayEvents.forEach(function(key) {3569var method = 'onData' + key.charAt(0).toUpperCase() + key.slice(1);3570var base = array[key];35713572Object.defineProperty(array, key, {3573configurable: true,3574enumerable: false,3575value: function() {3576var args = Array.prototype.slice.call(arguments);3577var res = base.apply(this, args);35783579helpers$1.each(array._chartjs.listeners, function(object) {3580if (typeof object[method] === 'function') {3581object[method].apply(object, args);3582}3583});35843585return res;3586}3587});3588});3589}35903591/**3592* Removes the given array event listener and cleanup extra attached properties (such as3593* the _chartjs stub and overridden methods) if array doesn't have any more listeners.3594*/3595function unlistenArrayEvents(array, listener) {3596var stub = array._chartjs;3597if (!stub) {3598return;3599}36003601var listeners = stub.listeners;3602var index = listeners.indexOf(listener);3603if (index !== -1) {3604listeners.splice(index, 1);3605}36063607if (listeners.length > 0) {3608return;3609}36103611arrayEvents.forEach(function(key) {3612delete array[key];3613});36143615delete array._chartjs;3616}36173618// Base class for all dataset controllers (line, bar, etc)3619var DatasetController = function(chart, datasetIndex) {3620this.initialize(chart, datasetIndex);3621};36223623helpers$1.extend(DatasetController.prototype, {36243625/**3626* Element type used to generate a meta dataset (e.g. Chart.element.Line).3627* @type {Chart.core.element}3628*/3629datasetElementType: null,36303631/**3632* Element type used to generate a meta data (e.g. Chart.element.Point).3633* @type {Chart.core.element}3634*/3635dataElementType: null,36363637/**3638* Dataset element option keys to be resolved in _resolveDatasetElementOptions.3639* A derived controller may override this to resolve controller-specific options.3640* The keys defined here are for backward compatibility for legend styles.3641* @private3642*/3643_datasetElementOptions: [3644'backgroundColor',3645'borderCapStyle',3646'borderColor',3647'borderDash',3648'borderDashOffset',3649'borderJoinStyle',3650'borderWidth'3651],36523653/**3654* Data element option keys to be resolved in _resolveDataElementOptions.3655* A derived controller may override this to resolve controller-specific options.3656* The keys defined here are for backward compatibility for legend styles.3657* @private3658*/3659_dataElementOptions: [3660'backgroundColor',3661'borderColor',3662'borderWidth',3663'pointStyle'3664],36653666initialize: function(chart, datasetIndex) {3667var me = this;3668me.chart = chart;3669me.index = datasetIndex;3670me.linkScales();3671me.addElements();3672me._type = me.getMeta().type;3673},36743675updateIndex: function(datasetIndex) {3676this.index = datasetIndex;3677},36783679linkScales: function() {3680var me = this;3681var meta = me.getMeta();3682var chart = me.chart;3683var scales = chart.scales;3684var dataset = me.getDataset();3685var scalesOpts = chart.options.scales;36863687if (meta.xAxisID === null || !(meta.xAxisID in scales) || dataset.xAxisID) {3688meta.xAxisID = dataset.xAxisID || scalesOpts.xAxes[0].id;3689}3690if (meta.yAxisID === null || !(meta.yAxisID in scales) || dataset.yAxisID) {3691meta.yAxisID = dataset.yAxisID || scalesOpts.yAxes[0].id;3692}3693},36943695getDataset: function() {3696return this.chart.data.datasets[this.index];3697},36983699getMeta: function() {3700return this.chart.getDatasetMeta(this.index);3701},37023703getScaleForId: function(scaleID) {3704return this.chart.scales[scaleID];3705},37063707/**3708* @private3709*/3710_getValueScaleId: function() {3711return this.getMeta().yAxisID;3712},37133714/**3715* @private3716*/3717_getIndexScaleId: function() {3718return this.getMeta().xAxisID;3719},37203721/**3722* @private3723*/3724_getValueScale: function() {3725return this.getScaleForId(this._getValueScaleId());3726},37273728/**3729* @private3730*/3731_getIndexScale: function() {3732return this.getScaleForId(this._getIndexScaleId());3733},37343735reset: function() {3736this._update(true);3737},37383739/**3740* @private3741*/3742destroy: function() {3743if (this._data) {3744unlistenArrayEvents(this._data, this);3745}3746},37473748createMetaDataset: function() {3749var me = this;3750var type = me.datasetElementType;3751return type && new type({3752_chart: me.chart,3753_datasetIndex: me.index3754});3755},37563757createMetaData: function(index) {3758var me = this;3759var type = me.dataElementType;3760return type && new type({3761_chart: me.chart,3762_datasetIndex: me.index,3763_index: index3764});3765},37663767addElements: function() {3768var me = this;3769var meta = me.getMeta();3770var data = me.getDataset().data || [];3771var metaData = meta.data;3772var i, ilen;37733774for (i = 0, ilen = data.length; i < ilen; ++i) {3775metaData[i] = metaData[i] || me.createMetaData(i);3776}37773778meta.dataset = meta.dataset || me.createMetaDataset();3779},37803781addElementAndReset: function(index) {3782var element = this.createMetaData(index);3783this.getMeta().data.splice(index, 0, element);3784this.updateElement(element, index, true);3785},37863787buildOrUpdateElements: function() {3788var me = this;3789var dataset = me.getDataset();3790var data = dataset.data || (dataset.data = []);37913792// In order to correctly handle data addition/deletion animation (an thus simulate3793// real-time charts), we need to monitor these data modifications and synchronize3794// the internal meta data accordingly.3795if (me._data !== data) {3796if (me._data) {3797// This case happens when the user replaced the data array instance.3798unlistenArrayEvents(me._data, me);3799}38003801if (data && Object.isExtensible(data)) {3802listenArrayEvents(data, me);3803}3804me._data = data;3805}38063807// Re-sync meta data in case the user replaced the data array or if we missed3808// any updates and so make sure that we handle number of datapoints changing.3809me.resyncElements();3810},38113812/**3813* Returns the merged user-supplied and default dataset-level options3814* @private3815*/3816_configure: function() {3817var me = this;3818me._config = helpers$1.merge({}, [3819me.chart.options.datasets[me._type],3820me.getDataset(),3821], {3822merger: function(key, target, source) {3823if (key !== '_meta' && key !== 'data') {3824helpers$1._merger(key, target, source);3825}3826}3827});3828},38293830_update: function(reset) {3831var me = this;3832me._configure();3833me._cachedDataOpts = null;3834me.update(reset);3835},38363837update: helpers$1.noop,38383839transition: function(easingValue) {3840var meta = this.getMeta();3841var elements = meta.data || [];3842var ilen = elements.length;3843var i = 0;38443845for (; i < ilen; ++i) {3846elements[i].transition(easingValue);3847}38483849if (meta.dataset) {3850meta.dataset.transition(easingValue);3851}3852},38533854draw: function() {3855var meta = this.getMeta();3856var elements = meta.data || [];3857var ilen = elements.length;3858var i = 0;38593860if (meta.dataset) {3861meta.dataset.draw();3862}38633864for (; i < ilen; ++i) {3865elements[i].draw();3866}3867},38683869/**3870* Returns a set of predefined style properties that should be used to represent the dataset3871* or the data if the index is specified3872* @param {number} index - data index3873* @return {IStyleInterface} style object3874*/3875getStyle: function(index) {3876var me = this;3877var meta = me.getMeta();3878var dataset = meta.dataset;3879var style;38803881me._configure();3882if (dataset && index === undefined) {3883style = me._resolveDatasetElementOptions(dataset || {});3884} else {3885index = index || 0;3886style = me._resolveDataElementOptions(meta.data[index] || {}, index);3887}38883889if (style.fill === false || style.fill === null) {3890style.backgroundColor = style.borderColor;3891}38923893return style;3894},38953896/**3897* @private3898*/3899_resolveDatasetElementOptions: function(element, hover) {3900var me = this;3901var chart = me.chart;3902var datasetOpts = me._config;3903var custom = element.custom || {};3904var options = chart.options.elements[me.datasetElementType.prototype._type] || {};3905var elementOptions = me._datasetElementOptions;3906var values = {};3907var i, ilen, key, readKey;39083909// Scriptable options3910var context = {3911chart: chart,3912dataset: me.getDataset(),3913datasetIndex: me.index,3914hover: hover3915};39163917for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {3918key = elementOptions[i];3919readKey = hover ? 'hover' + key.charAt(0).toUpperCase() + key.slice(1) : key;3920values[key] = resolve([3921custom[readKey],3922datasetOpts[readKey],3923options[readKey]3924], context);3925}39263927return values;3928},39293930/**3931* @private3932*/3933_resolveDataElementOptions: function(element, index) {3934var me = this;3935var custom = element && element.custom;3936var cached = me._cachedDataOpts;3937if (cached && !custom) {3938return cached;3939}3940var chart = me.chart;3941var datasetOpts = me._config;3942var options = chart.options.elements[me.dataElementType.prototype._type] || {};3943var elementOptions = me._dataElementOptions;3944var values = {};39453946// Scriptable options3947var context = {3948chart: chart,3949dataIndex: index,3950dataset: me.getDataset(),3951datasetIndex: me.index3952};39533954// `resolve` sets cacheable to `false` if any option is indexed or scripted3955var info = {cacheable: !custom};39563957var keys, i, ilen, key;39583959custom = custom || {};39603961if (helpers$1.isArray(elementOptions)) {3962for (i = 0, ilen = elementOptions.length; i < ilen; ++i) {3963key = elementOptions[i];3964values[key] = resolve([3965custom[key],3966datasetOpts[key],3967options[key]3968], context, index, info);3969}3970} else {3971keys = Object.keys(elementOptions);3972for (i = 0, ilen = keys.length; i < ilen; ++i) {3973key = keys[i];3974values[key] = resolve([3975custom[key],3976datasetOpts[elementOptions[key]],3977datasetOpts[key],3978options[key]3979], context, index, info);3980}3981}39823983if (info.cacheable) {3984me._cachedDataOpts = Object.freeze(values);3985}39863987return values;3988},39893990removeHoverStyle: function(element) {3991helpers$1.merge(element._model, element.$previousStyle || {});3992delete element.$previousStyle;3993},39943995setHoverStyle: function(element) {3996var dataset = this.chart.data.datasets[element._datasetIndex];3997var index = element._index;3998var custom = element.custom || {};3999var model = element._model;4000var getHoverColor = helpers$1.getHoverColor;40014002element.$previousStyle = {4003backgroundColor: model.backgroundColor,4004borderColor: model.borderColor,4005borderWidth: model.borderWidth4006};40074008model.backgroundColor = resolve([custom.hoverBackgroundColor, dataset.hoverBackgroundColor, getHoverColor(model.backgroundColor)], undefined, index);4009model.borderColor = resolve([custom.hoverBorderColor, dataset.hoverBorderColor, getHoverColor(model.borderColor)], undefined, index);4010model.borderWidth = resolve([custom.hoverBorderWidth, dataset.hoverBorderWidth, model.borderWidth], undefined, index);4011},40124013/**4014* @private4015*/4016_removeDatasetHoverStyle: function() {4017var element = this.getMeta().dataset;40184019if (element) {4020this.removeHoverStyle(element);4021}4022},40234024/**4025* @private4026*/4027_setDatasetHoverStyle: function() {4028var element = this.getMeta().dataset;4029var prev = {};4030var i, ilen, key, keys, hoverOptions, model;40314032if (!element) {4033return;4034}40354036model = element._model;4037hoverOptions = this._resolveDatasetElementOptions(element, true);40384039keys = Object.keys(hoverOptions);4040for (i = 0, ilen = keys.length; i < ilen; ++i) {4041key = keys[i];4042prev[key] = model[key];4043model[key] = hoverOptions[key];4044}40454046element.$previousStyle = prev;4047},40484049/**4050* @private4051*/4052resyncElements: function() {4053var me = this;4054var meta = me.getMeta();4055var data = me.getDataset().data;4056var numMeta = meta.data.length;4057var numData = data.length;40584059if (numData < numMeta) {4060meta.data.splice(numData, numMeta - numData);4061} else if (numData > numMeta) {4062me.insertElements(numMeta, numData - numMeta);4063}4064},40654066/**4067* @private4068*/4069insertElements: function(start, count) {4070for (var i = 0; i < count; ++i) {4071this.addElementAndReset(start + i);4072}4073},40744075/**4076* @private4077*/4078onDataPush: function() {4079var count = arguments.length;4080this.insertElements(this.getDataset().data.length - count, count);4081},40824083/**4084* @private4085*/4086onDataPop: function() {4087this.getMeta().data.pop();4088},40894090/**4091* @private4092*/4093onDataShift: function() {4094this.getMeta().data.shift();4095},40964097/**4098* @private4099*/4100onDataSplice: function(start, count) {4101this.getMeta().data.splice(start, count);4102this.insertElements(start, arguments.length - 2);4103},41044105/**4106* @private4107*/4108onDataUnshift: function() {4109this.insertElements(0, arguments.length);4110}4111});41124113DatasetController.extend = helpers$1.inherits;41144115var core_datasetController = DatasetController;41164117var TAU = Math.PI * 2;41184119core_defaults._set('global', {4120elements: {4121arc: {4122backgroundColor: core_defaults.global.defaultColor,4123borderColor: '#fff',4124borderWidth: 2,4125borderAlign: 'center'4126}4127}4128});41294130function clipArc(ctx, arc) {4131var startAngle = arc.startAngle;4132var endAngle = arc.endAngle;4133var pixelMargin = arc.pixelMargin;4134var angleMargin = pixelMargin / arc.outerRadius;4135var x = arc.x;4136var y = arc.y;41374138// Draw an inner border by cliping the arc and drawing a double-width border4139// Enlarge the clipping arc by 0.33 pixels to eliminate glitches between borders4140ctx.beginPath();4141ctx.arc(x, y, arc.outerRadius, startAngle - angleMargin, endAngle + angleMargin);4142if (arc.innerRadius > pixelMargin) {4143angleMargin = pixelMargin / arc.innerRadius;4144ctx.arc(x, y, arc.innerRadius - pixelMargin, endAngle + angleMargin, startAngle - angleMargin, true);4145} else {4146ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2);4147}4148ctx.closePath();4149ctx.clip();4150}41514152function drawFullCircleBorders(ctx, vm, arc, inner) {4153var endAngle = arc.endAngle;4154var i;41554156if (inner) {4157arc.endAngle = arc.startAngle + TAU;4158clipArc(ctx, arc);4159arc.endAngle = endAngle;4160if (arc.endAngle === arc.startAngle && arc.fullCircles) {4161arc.endAngle += TAU;4162arc.fullCircles--;4163}4164}41654166ctx.beginPath();4167ctx.arc(arc.x, arc.y, arc.innerRadius, arc.startAngle + TAU, arc.startAngle, true);4168for (i = 0; i < arc.fullCircles; ++i) {4169ctx.stroke();4170}41714172ctx.beginPath();4173ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.startAngle + TAU);4174for (i = 0; i < arc.fullCircles; ++i) {4175ctx.stroke();4176}4177}41784179function drawBorder(ctx, vm, arc) {4180var inner = vm.borderAlign === 'inner';41814182if (inner) {4183ctx.lineWidth = vm.borderWidth * 2;4184ctx.lineJoin = 'round';4185} else {4186ctx.lineWidth = vm.borderWidth;4187ctx.lineJoin = 'bevel';4188}41894190if (arc.fullCircles) {4191drawFullCircleBorders(ctx, vm, arc, inner);4192}41934194if (inner) {4195clipArc(ctx, arc);4196}41974198ctx.beginPath();4199ctx.arc(arc.x, arc.y, vm.outerRadius, arc.startAngle, arc.endAngle);4200ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);4201ctx.closePath();4202ctx.stroke();4203}42044205var element_arc = core_element.extend({4206_type: 'arc',42074208inLabelRange: function(mouseX) {4209var vm = this._view;42104211if (vm) {4212return (Math.pow(mouseX - vm.x, 2) < Math.pow(vm.radius + vm.hoverRadius, 2));4213}4214return false;4215},42164217inRange: function(chartX, chartY) {4218var vm = this._view;42194220if (vm) {4221var pointRelativePosition = helpers$1.getAngleFromPoint(vm, {x: chartX, y: chartY});4222var angle = pointRelativePosition.angle;4223var distance = pointRelativePosition.distance;42244225// Sanitise angle range4226var startAngle = vm.startAngle;4227var endAngle = vm.endAngle;4228while (endAngle < startAngle) {4229endAngle += TAU;4230}4231while (angle > endAngle) {4232angle -= TAU;4233}4234while (angle < startAngle) {4235angle += TAU;4236}42374238// Check if within the range of the open/close angle4239var betweenAngles = (angle >= startAngle && angle <= endAngle);4240var withinRadius = (distance >= vm.innerRadius && distance <= vm.outerRadius);42414242return (betweenAngles && withinRadius);4243}4244return false;4245},42464247getCenterPoint: function() {4248var vm = this._view;4249var halfAngle = (vm.startAngle + vm.endAngle) / 2;4250var halfRadius = (vm.innerRadius + vm.outerRadius) / 2;4251return {4252x: vm.x + Math.cos(halfAngle) * halfRadius,4253y: vm.y + Math.sin(halfAngle) * halfRadius4254};4255},42564257getArea: function() {4258var vm = this._view;4259return Math.PI * ((vm.endAngle - vm.startAngle) / (2 * Math.PI)) * (Math.pow(vm.outerRadius, 2) - Math.pow(vm.innerRadius, 2));4260},42614262tooltipPosition: function() {4263var vm = this._view;4264var centreAngle = vm.startAngle + ((vm.endAngle - vm.startAngle) / 2);4265var rangeFromCentre = (vm.outerRadius - vm.innerRadius) / 2 + vm.innerRadius;42664267return {4268x: vm.x + (Math.cos(centreAngle) * rangeFromCentre),4269y: vm.y + (Math.sin(centreAngle) * rangeFromCentre)4270};4271},42724273draw: function() {4274var ctx = this._chart.ctx;4275var vm = this._view;4276var pixelMargin = (vm.borderAlign === 'inner') ? 0.33 : 0;4277var arc = {4278x: vm.x,4279y: vm.y,4280innerRadius: vm.innerRadius,4281outerRadius: Math.max(vm.outerRadius - pixelMargin, 0),4282pixelMargin: pixelMargin,4283startAngle: vm.startAngle,4284endAngle: vm.endAngle,4285fullCircles: Math.floor(vm.circumference / TAU)4286};4287var i;42884289ctx.save();42904291ctx.fillStyle = vm.backgroundColor;4292ctx.strokeStyle = vm.borderColor;42934294if (arc.fullCircles) {4295arc.endAngle = arc.startAngle + TAU;4296ctx.beginPath();4297ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);4298ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);4299ctx.closePath();4300for (i = 0; i < arc.fullCircles; ++i) {4301ctx.fill();4302}4303arc.endAngle = arc.startAngle + vm.circumference % TAU;4304}43054306ctx.beginPath();4307ctx.arc(arc.x, arc.y, arc.outerRadius, arc.startAngle, arc.endAngle);4308ctx.arc(arc.x, arc.y, arc.innerRadius, arc.endAngle, arc.startAngle, true);4309ctx.closePath();4310ctx.fill();43114312if (vm.borderWidth) {4313drawBorder(ctx, vm, arc);4314}43154316ctx.restore();4317}4318});43194320var valueOrDefault$1 = helpers$1.valueOrDefault;43214322var defaultColor = core_defaults.global.defaultColor;43234324core_defaults._set('global', {4325elements: {4326line: {4327tension: 0.4,4328backgroundColor: defaultColor,4329borderWidth: 3,4330borderColor: defaultColor,4331borderCapStyle: 'butt',4332borderDash: [],4333borderDashOffset: 0.0,4334borderJoinStyle: 'miter',4335capBezierPoints: true,4336fill: true, // do we fill in the area between the line and its base axis4337}4338}4339});43404341var element_line = core_element.extend({4342_type: 'line',43434344draw: function() {4345var me = this;4346var vm = me._view;4347var ctx = me._chart.ctx;4348var spanGaps = vm.spanGaps;4349var points = me._children.slice(); // clone array4350var globalDefaults = core_defaults.global;4351var globalOptionLineElements = globalDefaults.elements.line;4352var lastDrawnIndex = -1;4353var closePath = me._loop;4354var index, previous, currentVM;43554356if (!points.length) {4357return;4358}43594360if (me._loop) {4361for (index = 0; index < points.length; ++index) {4362previous = helpers$1.previousItem(points, index);4363// If the line has an open path, shift the point array4364if (!points[index]._view.skip && previous._view.skip) {4365points = points.slice(index).concat(points.slice(0, index));4366closePath = spanGaps;4367break;4368}4369}4370// If the line has a close path, add the first point again4371if (closePath) {4372points.push(points[0]);4373}4374}43754376ctx.save();43774378// Stroke Line Options4379ctx.lineCap = vm.borderCapStyle || globalOptionLineElements.borderCapStyle;43804381// IE 9 and 10 do not support line dash4382if (ctx.setLineDash) {4383ctx.setLineDash(vm.borderDash || globalOptionLineElements.borderDash);4384}43854386ctx.lineDashOffset = valueOrDefault$1(vm.borderDashOffset, globalOptionLineElements.borderDashOffset);4387ctx.lineJoin = vm.borderJoinStyle || globalOptionLineElements.borderJoinStyle;4388ctx.lineWidth = valueOrDefault$1(vm.borderWidth, globalOptionLineElements.borderWidth);4389ctx.strokeStyle = vm.borderColor || globalDefaults.defaultColor;43904391// Stroke Line4392ctx.beginPath();43934394// First point moves to it's starting position no matter what4395currentVM = points[0]._view;4396if (!currentVM.skip) {4397ctx.moveTo(currentVM.x, currentVM.y);4398lastDrawnIndex = 0;4399}44004401for (index = 1; index < points.length; ++index) {4402currentVM = points[index]._view;4403previous = lastDrawnIndex === -1 ? helpers$1.previousItem(points, index) : points[lastDrawnIndex];44044405if (!currentVM.skip) {4406if ((lastDrawnIndex !== (index - 1) && !spanGaps) || lastDrawnIndex === -1) {4407// There was a gap and this is the first point after the gap4408ctx.moveTo(currentVM.x, currentVM.y);4409} else {4410// Line to next point4411helpers$1.canvas.lineTo(ctx, previous._view, currentVM);4412}4413lastDrawnIndex = index;4414}4415}44164417if (closePath) {4418ctx.closePath();4419}44204421ctx.stroke();4422ctx.restore();4423}4424});44254426var valueOrDefault$2 = helpers$1.valueOrDefault;44274428var defaultColor$1 = core_defaults.global.defaultColor;44294430core_defaults._set('global', {4431elements: {4432point: {4433radius: 3,4434pointStyle: 'circle',4435backgroundColor: defaultColor$1,4436borderColor: defaultColor$1,4437borderWidth: 1,4438// Hover4439hitRadius: 1,4440hoverRadius: 4,4441hoverBorderWidth: 14442}4443}4444});44454446function xRange(mouseX) {4447var vm = this._view;4448return vm ? (Math.abs(mouseX - vm.x) < vm.radius + vm.hitRadius) : false;4449}44504451function yRange(mouseY) {4452var vm = this._view;4453return vm ? (Math.abs(mouseY - vm.y) < vm.radius + vm.hitRadius) : false;4454}44554456var element_point = core_element.extend({4457_type: 'point',44584459inRange: function(mouseX, mouseY) {4460var vm = this._view;4461return vm ? ((Math.pow(mouseX - vm.x, 2) + Math.pow(mouseY - vm.y, 2)) < Math.pow(vm.hitRadius + vm.radius, 2)) : false;4462},44634464inLabelRange: xRange,4465inXRange: xRange,4466inYRange: yRange,44674468getCenterPoint: function() {4469var vm = this._view;4470return {4471x: vm.x,4472y: vm.y4473};4474},44754476getArea: function() {4477return Math.PI * Math.pow(this._view.radius, 2);4478},44794480tooltipPosition: function() {4481var vm = this._view;4482return {4483x: vm.x,4484y: vm.y,4485padding: vm.radius + vm.borderWidth4486};4487},44884489draw: function(chartArea) {4490var vm = this._view;4491var ctx = this._chart.ctx;4492var pointStyle = vm.pointStyle;4493var rotation = vm.rotation;4494var radius = vm.radius;4495var x = vm.x;4496var y = vm.y;4497var globalDefaults = core_defaults.global;4498var defaultColor = globalDefaults.defaultColor; // eslint-disable-line no-shadow44994500if (vm.skip) {4501return;4502}45034504// Clipping for Points.4505if (chartArea === undefined || helpers$1.canvas._isPointInArea(vm, chartArea)) {4506ctx.strokeStyle = vm.borderColor || defaultColor;4507ctx.lineWidth = valueOrDefault$2(vm.borderWidth, globalDefaults.elements.point.borderWidth);4508ctx.fillStyle = vm.backgroundColor || defaultColor;4509helpers$1.canvas.drawPoint(ctx, pointStyle, radius, x, y, rotation);4510}4511}4512});45134514var defaultColor$2 = core_defaults.global.defaultColor;45154516core_defaults._set('global', {4517elements: {4518rectangle: {4519backgroundColor: defaultColor$2,4520borderColor: defaultColor$2,4521borderSkipped: 'bottom',4522borderWidth: 04523}4524}4525});45264527function isVertical(vm) {4528return vm && vm.width !== undefined;4529}45304531/**4532* Helper function to get the bounds of the bar regardless of the orientation4533* @param bar {Chart.Element.Rectangle} the bar4534* @return {Bounds} bounds of the bar4535* @private4536*/4537function getBarBounds(vm) {4538var x1, x2, y1, y2, half;45394540if (isVertical(vm)) {4541half = vm.width / 2;4542x1 = vm.x - half;4543x2 = vm.x + half;4544y1 = Math.min(vm.y, vm.base);4545y2 = Math.max(vm.y, vm.base);4546} else {4547half = vm.height / 2;4548x1 = Math.min(vm.x, vm.base);4549x2 = Math.max(vm.x, vm.base);4550y1 = vm.y - half;4551y2 = vm.y + half;4552}45534554return {4555left: x1,4556top: y1,4557right: x2,4558bottom: y24559};4560}45614562function swap(orig, v1, v2) {4563return orig === v1 ? v2 : orig === v2 ? v1 : orig;4564}45654566function parseBorderSkipped(vm) {4567var edge = vm.borderSkipped;4568var res = {};45694570if (!edge) {4571return res;4572}45734574if (vm.horizontal) {4575if (vm.base > vm.x) {4576edge = swap(edge, 'left', 'right');4577}4578} else if (vm.base < vm.y) {4579edge = swap(edge, 'bottom', 'top');4580}45814582res[edge] = true;4583return res;4584}45854586function parseBorderWidth(vm, maxW, maxH) {4587var value = vm.borderWidth;4588var skip = parseBorderSkipped(vm);4589var t, r, b, l;45904591if (helpers$1.isObject(value)) {4592t = +value.top || 0;4593r = +value.right || 0;4594b = +value.bottom || 0;4595l = +value.left || 0;4596} else {4597t = r = b = l = +value || 0;4598}45994600return {4601t: skip.top || (t < 0) ? 0 : t > maxH ? maxH : t,4602r: skip.right || (r < 0) ? 0 : r > maxW ? maxW : r,4603b: skip.bottom || (b < 0) ? 0 : b > maxH ? maxH : b,4604l: skip.left || (l < 0) ? 0 : l > maxW ? maxW : l4605};4606}46074608function boundingRects(vm) {4609var bounds = getBarBounds(vm);4610var width = bounds.right - bounds.left;4611var height = bounds.bottom - bounds.top;4612var border = parseBorderWidth(vm, width / 2, height / 2);46134614return {4615outer: {4616x: bounds.left,4617y: bounds.top,4618w: width,4619h: height4620},4621inner: {4622x: bounds.left + border.l,4623y: bounds.top + border.t,4624w: width - border.l - border.r,4625h: height - border.t - border.b4626}4627};4628}46294630function inRange(vm, x, y) {4631var skipX = x === null;4632var skipY = y === null;4633var bounds = !vm || (skipX && skipY) ? false : getBarBounds(vm);46344635return bounds4636&& (skipX || x >= bounds.left && x <= bounds.right)4637&& (skipY || y >= bounds.top && y <= bounds.bottom);4638}46394640var element_rectangle = core_element.extend({4641_type: 'rectangle',46424643draw: function() {4644var ctx = this._chart.ctx;4645var vm = this._view;4646var rects = boundingRects(vm);4647var outer = rects.outer;4648var inner = rects.inner;46494650ctx.fillStyle = vm.backgroundColor;4651ctx.fillRect(outer.x, outer.y, outer.w, outer.h);46524653if (outer.w === inner.w && outer.h === inner.h) {4654return;4655}46564657ctx.save();4658ctx.beginPath();4659ctx.rect(outer.x, outer.y, outer.w, outer.h);4660ctx.clip();4661ctx.fillStyle = vm.borderColor;4662ctx.rect(inner.x, inner.y, inner.w, inner.h);4663ctx.fill('evenodd');4664ctx.restore();4665},46664667height: function() {4668var vm = this._view;4669return vm.base - vm.y;4670},46714672inRange: function(mouseX, mouseY) {4673return inRange(this._view, mouseX, mouseY);4674},46754676inLabelRange: function(mouseX, mouseY) {4677var vm = this._view;4678return isVertical(vm)4679? inRange(vm, mouseX, null)4680: inRange(vm, null, mouseY);4681},46824683inXRange: function(mouseX) {4684return inRange(this._view, mouseX, null);4685},46864687inYRange: function(mouseY) {4688return inRange(this._view, null, mouseY);4689},46904691getCenterPoint: function() {4692var vm = this._view;4693var x, y;4694if (isVertical(vm)) {4695x = vm.x;4696y = (vm.y + vm.base) / 2;4697} else {4698x = (vm.x + vm.base) / 2;4699y = vm.y;4700}47014702return {x: x, y: y};4703},47044705getArea: function() {4706var vm = this._view;47074708return isVertical(vm)4709? vm.width * Math.abs(vm.y - vm.base)4710: vm.height * Math.abs(vm.x - vm.base);4711},47124713tooltipPosition: function() {4714var vm = this._view;4715return {4716x: vm.x,4717y: vm.y4718};4719}4720});47214722var elements = {};4723var Arc = element_arc;4724var Line = element_line;4725var Point = element_point;4726var Rectangle = element_rectangle;4727elements.Arc = Arc;4728elements.Line = Line;4729elements.Point = Point;4730elements.Rectangle = Rectangle;47314732var deprecated = helpers$1._deprecated;4733var valueOrDefault$3 = helpers$1.valueOrDefault;47344735core_defaults._set('bar', {4736hover: {4737mode: 'label'4738},47394740scales: {4741xAxes: [{4742type: 'category',4743offset: true,4744gridLines: {4745offsetGridLines: true4746}4747}],47484749yAxes: [{4750type: 'linear'4751}]4752}4753});47544755core_defaults._set('global', {4756datasets: {4757bar: {4758categoryPercentage: 0.8,4759barPercentage: 0.94760}4761}4762});47634764/**4765* Computes the "optimal" sample size to maintain bars equally sized while preventing overlap.4766* @private4767*/4768function computeMinSampleSize(scale, pixels) {4769var min = scale._length;4770var prev, curr, i, ilen;47714772for (i = 1, ilen = pixels.length; i < ilen; ++i) {4773min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1]));4774}47754776for (i = 0, ilen = scale.getTicks().length; i < ilen; ++i) {4777curr = scale.getPixelForTick(i);4778min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min;4779prev = curr;4780}47814782return min;4783}47844785/**4786* Computes an "ideal" category based on the absolute bar thickness or, if undefined or null,4787* uses the smallest interval (see computeMinSampleSize) that prevents bar overlapping. This4788* mode currently always generates bars equally sized (until we introduce scriptable options?).4789* @private4790*/4791function computeFitCategoryTraits(index, ruler, options) {4792var thickness = options.barThickness;4793var count = ruler.stackCount;4794var curr = ruler.pixels[index];4795var min = helpers$1.isNullOrUndef(thickness)4796? computeMinSampleSize(ruler.scale, ruler.pixels)4797: -1;4798var size, ratio;47994800if (helpers$1.isNullOrUndef(thickness)) {4801size = min * options.categoryPercentage;4802ratio = options.barPercentage;4803} else {4804// When bar thickness is enforced, category and bar percentages are ignored.4805// Note(SB): we could add support for relative bar thickness (e.g. barThickness: '50%')4806// and deprecate barPercentage since this value is ignored when thickness is absolute.4807size = thickness * count;4808ratio = 1;4809}48104811return {4812chunk: size / count,4813ratio: ratio,4814start: curr - (size / 2)4815};4816}48174818/**4819* Computes an "optimal" category that globally arranges bars side by side (no gap when4820* percentage options are 1), based on the previous and following categories. This mode4821* generates bars with different widths when data are not evenly spaced.4822* @private4823*/4824function computeFlexCategoryTraits(index, ruler, options) {4825var pixels = ruler.pixels;4826var curr = pixels[index];4827var prev = index > 0 ? pixels[index - 1] : null;4828var next = index < pixels.length - 1 ? pixels[index + 1] : null;4829var percent = options.categoryPercentage;4830var start, size;48314832if (prev === null) {4833// first data: its size is double based on the next point or,4834// if it's also the last data, we use the scale size.4835prev = curr - (next === null ? ruler.end - ruler.start : next - curr);4836}48374838if (next === null) {4839// last data: its size is also double based on the previous point.4840next = curr + curr - prev;4841}48424843start = curr - (curr - Math.min(prev, next)) / 2 * percent;4844size = Math.abs(next - prev) / 2 * percent;48454846return {4847chunk: size / ruler.stackCount,4848ratio: options.barPercentage,4849start: start4850};4851}48524853var controller_bar = core_datasetController.extend({48544855dataElementType: elements.Rectangle,48564857/**4858* @private4859*/4860_dataElementOptions: [4861'backgroundColor',4862'borderColor',4863'borderSkipped',4864'borderWidth',4865'barPercentage',4866'barThickness',4867'categoryPercentage',4868'maxBarThickness',4869'minBarLength'4870],48714872initialize: function() {4873var me = this;4874var meta, scaleOpts;48754876core_datasetController.prototype.initialize.apply(me, arguments);48774878meta = me.getMeta();4879meta.stack = me.getDataset().stack;4880meta.bar = true;48814882scaleOpts = me._getIndexScale().options;4883deprecated('bar chart', scaleOpts.barPercentage, 'scales.[x/y]Axes.barPercentage', 'dataset.barPercentage');4884deprecated('bar chart', scaleOpts.barThickness, 'scales.[x/y]Axes.barThickness', 'dataset.barThickness');4885deprecated('bar chart', scaleOpts.categoryPercentage, 'scales.[x/y]Axes.categoryPercentage', 'dataset.categoryPercentage');4886deprecated('bar chart', me._getValueScale().options.minBarLength, 'scales.[x/y]Axes.minBarLength', 'dataset.minBarLength');4887deprecated('bar chart', scaleOpts.maxBarThickness, 'scales.[x/y]Axes.maxBarThickness', 'dataset.maxBarThickness');4888},48894890update: function(reset) {4891var me = this;4892var rects = me.getMeta().data;4893var i, ilen;48944895me._ruler = me.getRuler();48964897for (i = 0, ilen = rects.length; i < ilen; ++i) {4898me.updateElement(rects[i], i, reset);4899}4900},49014902updateElement: function(rectangle, index, reset) {4903var me = this;4904var meta = me.getMeta();4905var dataset = me.getDataset();4906var options = me._resolveDataElementOptions(rectangle, index);49074908rectangle._xScale = me.getScaleForId(meta.xAxisID);4909rectangle._yScale = me.getScaleForId(meta.yAxisID);4910rectangle._datasetIndex = me.index;4911rectangle._index = index;4912rectangle._model = {4913backgroundColor: options.backgroundColor,4914borderColor: options.borderColor,4915borderSkipped: options.borderSkipped,4916borderWidth: options.borderWidth,4917datasetLabel: dataset.label,4918label: me.chart.data.labels[index]4919};49204921if (helpers$1.isArray(dataset.data[index])) {4922rectangle._model.borderSkipped = null;4923}49244925me._updateElementGeometry(rectangle, index, reset, options);49264927rectangle.pivot();4928},49294930/**4931* @private4932*/4933_updateElementGeometry: function(rectangle, index, reset, options) {4934var me = this;4935var model = rectangle._model;4936var vscale = me._getValueScale();4937var base = vscale.getBasePixel();4938var horizontal = vscale.isHorizontal();4939var ruler = me._ruler || me.getRuler();4940var vpixels = me.calculateBarValuePixels(me.index, index, options);4941var ipixels = me.calculateBarIndexPixels(me.index, index, ruler, options);49424943model.horizontal = horizontal;4944model.base = reset ? base : vpixels.base;4945model.x = horizontal ? reset ? base : vpixels.head : ipixels.center;4946model.y = horizontal ? ipixels.center : reset ? base : vpixels.head;4947model.height = horizontal ? ipixels.size : undefined;4948model.width = horizontal ? undefined : ipixels.size;4949},49504951/**4952* Returns the stacks based on groups and bar visibility.4953* @param {number} [last] - The dataset index4954* @returns {string[]} The list of stack IDs4955* @private4956*/4957_getStacks: function(last) {4958var me = this;4959var scale = me._getIndexScale();4960var metasets = scale._getMatchingVisibleMetas(me._type);4961var stacked = scale.options.stacked;4962var ilen = metasets.length;4963var stacks = [];4964var i, meta;49654966for (i = 0; i < ilen; ++i) {4967meta = metasets[i];4968// stacked | meta.stack4969// | found | not found | undefined4970// false | x | x | x4971// true | | x |4972// undefined | | x | x4973if (stacked === false || stacks.indexOf(meta.stack) === -1 ||4974(stacked === undefined && meta.stack === undefined)) {4975stacks.push(meta.stack);4976}4977if (meta.index === last) {4978break;4979}4980}49814982return stacks;4983},49844985/**4986* Returns the effective number of stacks based on groups and bar visibility.4987* @private4988*/4989getStackCount: function() {4990return this._getStacks().length;4991},49924993/**4994* Returns the stack index for the given dataset based on groups and bar visibility.4995* @param {number} [datasetIndex] - The dataset index4996* @param {string} [name] - The stack name to find4997* @returns {number} The stack index4998* @private4999*/5000getStackIndex: function(datasetIndex, name) {5001var stacks = this._getStacks(datasetIndex);5002var index = (name !== undefined)5003? stacks.indexOf(name)5004: -1; // indexOf returns -1 if element is not present50055006return (index === -1)5007? stacks.length - 15008: index;5009},50105011/**5012* @private5013*/5014getRuler: function() {5015var me = this;5016var scale = me._getIndexScale();5017var pixels = [];5018var i, ilen;50195020for (i = 0, ilen = me.getMeta().data.length; i < ilen; ++i) {5021pixels.push(scale.getPixelForValue(null, i, me.index));5022}50235024return {5025pixels: pixels,5026start: scale._startPixel,5027end: scale._endPixel,5028stackCount: me.getStackCount(),5029scale: scale5030};5031},50325033/**5034* Note: pixel values are not clamped to the scale area.5035* @private5036*/5037calculateBarValuePixels: function(datasetIndex, index, options) {5038var me = this;5039var chart = me.chart;5040var scale = me._getValueScale();5041var isHorizontal = scale.isHorizontal();5042var datasets = chart.data.datasets;5043var metasets = scale._getMatchingVisibleMetas(me._type);5044var value = scale._parseValue(datasets[datasetIndex].data[index]);5045var minBarLength = options.minBarLength;5046var stacked = scale.options.stacked;5047var stack = me.getMeta().stack;5048var start = value.start === undefined ? 0 : value.max >= 0 && value.min >= 0 ? value.min : value.max;5049var length = value.start === undefined ? value.end : value.max >= 0 && value.min >= 0 ? value.max - value.min : value.min - value.max;5050var ilen = metasets.length;5051var i, imeta, ivalue, base, head, size, stackLength;50525053if (stacked || (stacked === undefined && stack !== undefined)) {5054for (i = 0; i < ilen; ++i) {5055imeta = metasets[i];50565057if (imeta.index === datasetIndex) {5058break;5059}50605061if (imeta.stack === stack) {5062stackLength = scale._parseValue(datasets[imeta.index].data[index]);5063ivalue = stackLength.start === undefined ? stackLength.end : stackLength.min >= 0 && stackLength.max >= 0 ? stackLength.max : stackLength.min;50645065if ((value.min < 0 && ivalue < 0) || (value.max >= 0 && ivalue > 0)) {5066start += ivalue;5067}5068}5069}5070}50715072base = scale.getPixelForValue(start);5073head = scale.getPixelForValue(start + length);5074size = head - base;50755076if (minBarLength !== undefined && Math.abs(size) < minBarLength) {5077size = minBarLength;5078if (length >= 0 && !isHorizontal || length < 0 && isHorizontal) {5079head = base - minBarLength;5080} else {5081head = base + minBarLength;5082}5083}50845085return {5086size: size,5087base: base,5088head: head,5089center: head + size / 25090};5091},50925093/**5094* @private5095*/5096calculateBarIndexPixels: function(datasetIndex, index, ruler, options) {5097var me = this;5098var range = options.barThickness === 'flex'5099? computeFlexCategoryTraits(index, ruler, options)5100: computeFitCategoryTraits(index, ruler, options);51015102var stackIndex = me.getStackIndex(datasetIndex, me.getMeta().stack);5103var center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);5104var size = Math.min(5105valueOrDefault$3(options.maxBarThickness, Infinity),5106range.chunk * range.ratio);51075108return {5109base: center - size / 2,5110head: center + size / 2,5111center: center,5112size: size5113};5114},51155116draw: function() {5117var me = this;5118var chart = me.chart;5119var scale = me._getValueScale();5120var rects = me.getMeta().data;5121var dataset = me.getDataset();5122var ilen = rects.length;5123var i = 0;51245125helpers$1.canvas.clipArea(chart.ctx, chart.chartArea);51265127for (; i < ilen; ++i) {5128var val = scale._parseValue(dataset.data[i]);5129if (!isNaN(val.min) && !isNaN(val.max)) {5130rects[i].draw();5131}5132}51335134helpers$1.canvas.unclipArea(chart.ctx);5135},51365137/**5138* @private5139*/5140_resolveDataElementOptions: function() {5141var me = this;5142var values = helpers$1.extend({}, core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments));5143var indexOpts = me._getIndexScale().options;5144var valueOpts = me._getValueScale().options;51455146values.barPercentage = valueOrDefault$3(indexOpts.barPercentage, values.barPercentage);5147values.barThickness = valueOrDefault$3(indexOpts.barThickness, values.barThickness);5148values.categoryPercentage = valueOrDefault$3(indexOpts.categoryPercentage, values.categoryPercentage);5149values.maxBarThickness = valueOrDefault$3(indexOpts.maxBarThickness, values.maxBarThickness);5150values.minBarLength = valueOrDefault$3(valueOpts.minBarLength, values.minBarLength);51515152return values;5153}51545155});51565157var valueOrDefault$4 = helpers$1.valueOrDefault;5158var resolve$1 = helpers$1.options.resolve;51595160core_defaults._set('bubble', {5161hover: {5162mode: 'single'5163},51645165scales: {5166xAxes: [{5167type: 'linear', // bubble should probably use a linear scale by default5168position: 'bottom',5169id: 'x-axis-0' // need an ID so datasets can reference the scale5170}],5171yAxes: [{5172type: 'linear',5173position: 'left',5174id: 'y-axis-0'5175}]5176},51775178tooltips: {5179callbacks: {5180title: function() {5181// Title doesn't make sense for scatter since we format the data as a point5182return '';5183},5184label: function(item, data) {5185var datasetLabel = data.datasets[item.datasetIndex].label || '';5186var dataPoint = data.datasets[item.datasetIndex].data[item.index];5187return datasetLabel + ': (' + item.xLabel + ', ' + item.yLabel + ', ' + dataPoint.r + ')';5188}5189}5190}5191});51925193var controller_bubble = core_datasetController.extend({5194/**5195* @protected5196*/5197dataElementType: elements.Point,51985199/**5200* @private5201*/5202_dataElementOptions: [5203'backgroundColor',5204'borderColor',5205'borderWidth',5206'hoverBackgroundColor',5207'hoverBorderColor',5208'hoverBorderWidth',5209'hoverRadius',5210'hitRadius',5211'pointStyle',5212'rotation'5213],52145215/**5216* @protected5217*/5218update: function(reset) {5219var me = this;5220var meta = me.getMeta();5221var points = meta.data;52225223// Update Points5224helpers$1.each(points, function(point, index) {5225me.updateElement(point, index, reset);5226});5227},52285229/**5230* @protected5231*/5232updateElement: function(point, index, reset) {5233var me = this;5234var meta = me.getMeta();5235var custom = point.custom || {};5236var xScale = me.getScaleForId(meta.xAxisID);5237var yScale = me.getScaleForId(meta.yAxisID);5238var options = me._resolveDataElementOptions(point, index);5239var data = me.getDataset().data[index];5240var dsIndex = me.index;52415242var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(typeof data === 'object' ? data : NaN, index, dsIndex);5243var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(data, index, dsIndex);52445245point._xScale = xScale;5246point._yScale = yScale;5247point._options = options;5248point._datasetIndex = dsIndex;5249point._index = index;5250point._model = {5251backgroundColor: options.backgroundColor,5252borderColor: options.borderColor,5253borderWidth: options.borderWidth,5254hitRadius: options.hitRadius,5255pointStyle: options.pointStyle,5256rotation: options.rotation,5257radius: reset ? 0 : options.radius,5258skip: custom.skip || isNaN(x) || isNaN(y),5259x: x,5260y: y,5261};52625263point.pivot();5264},52655266/**5267* @protected5268*/5269setHoverStyle: function(point) {5270var model = point._model;5271var options = point._options;5272var getHoverColor = helpers$1.getHoverColor;52735274point.$previousStyle = {5275backgroundColor: model.backgroundColor,5276borderColor: model.borderColor,5277borderWidth: model.borderWidth,5278radius: model.radius5279};52805281model.backgroundColor = valueOrDefault$4(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));5282model.borderColor = valueOrDefault$4(options.hoverBorderColor, getHoverColor(options.borderColor));5283model.borderWidth = valueOrDefault$4(options.hoverBorderWidth, options.borderWidth);5284model.radius = options.radius + options.hoverRadius;5285},52865287/**5288* @private5289*/5290_resolveDataElementOptions: function(point, index) {5291var me = this;5292var chart = me.chart;5293var dataset = me.getDataset();5294var custom = point.custom || {};5295var data = dataset.data[index] || {};5296var values = core_datasetController.prototype._resolveDataElementOptions.apply(me, arguments);52975298// Scriptable options5299var context = {5300chart: chart,5301dataIndex: index,5302dataset: dataset,5303datasetIndex: me.index5304};53055306// In case values were cached (and thus frozen), we need to clone the values5307if (me._cachedDataOpts === values) {5308values = helpers$1.extend({}, values);5309}53105311// Custom radius resolution5312values.radius = resolve$1([5313custom.radius,5314data.r,5315me._config.radius,5316chart.options.elements.point.radius5317], context, index);53185319return values;5320}5321});53225323var valueOrDefault$5 = helpers$1.valueOrDefault;53245325var PI$1 = Math.PI;5326var DOUBLE_PI$1 = PI$1 * 2;5327var HALF_PI$1 = PI$1 / 2;53285329core_defaults._set('doughnut', {5330animation: {5331// Boolean - Whether we animate the rotation of the Doughnut5332animateRotate: true,5333// Boolean - Whether we animate scaling the Doughnut from the centre5334animateScale: false5335},5336hover: {5337mode: 'single'5338},5339legendCallback: function(chart) {5340var list = document.createElement('ul');5341var data = chart.data;5342var datasets = data.datasets;5343var labels = data.labels;5344var i, ilen, listItem, listItemSpan;53455346list.setAttribute('class', chart.id + '-legend');5347if (datasets.length) {5348for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {5349listItem = list.appendChild(document.createElement('li'));5350listItemSpan = listItem.appendChild(document.createElement('span'));5351listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];5352if (labels[i]) {5353listItem.appendChild(document.createTextNode(labels[i]));5354}5355}5356}53575358return list.outerHTML;5359},5360legend: {5361labels: {5362generateLabels: function(chart) {5363var data = chart.data;5364if (data.labels.length && data.datasets.length) {5365return data.labels.map(function(label, i) {5366var meta = chart.getDatasetMeta(0);5367var style = meta.controller.getStyle(i);53685369return {5370text: label,5371fillStyle: style.backgroundColor,5372strokeStyle: style.borderColor,5373lineWidth: style.borderWidth,5374hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,53755376// Extra data used for toggling the correct item5377index: i5378};5379});5380}5381return [];5382}5383},53845385onClick: function(e, legendItem) {5386var index = legendItem.index;5387var chart = this.chart;5388var i, ilen, meta;53895390for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {5391meta = chart.getDatasetMeta(i);5392// toggle visibility of index if exists5393if (meta.data[index]) {5394meta.data[index].hidden = !meta.data[index].hidden;5395}5396}53975398chart.update();5399}5400},54015402// The percentage of the chart that we cut out of the middle.5403cutoutPercentage: 50,54045405// The rotation of the chart, where the first data arc begins.5406rotation: -HALF_PI$1,54075408// The total circumference of the chart.5409circumference: DOUBLE_PI$1,54105411// Need to override these to give a nice default5412tooltips: {5413callbacks: {5414title: function() {5415return '';5416},5417label: function(tooltipItem, data) {5418var dataLabel = data.labels[tooltipItem.index];5419var value = ': ' + data.datasets[tooltipItem.datasetIndex].data[tooltipItem.index];54205421if (helpers$1.isArray(dataLabel)) {5422// show value on first line of multiline label5423// need to clone because we are changing the value5424dataLabel = dataLabel.slice();5425dataLabel[0] += value;5426} else {5427dataLabel += value;5428}54295430return dataLabel;5431}5432}5433}5434});54355436var controller_doughnut = core_datasetController.extend({54375438dataElementType: elements.Arc,54395440linkScales: helpers$1.noop,54415442/**5443* @private5444*/5445_dataElementOptions: [5446'backgroundColor',5447'borderColor',5448'borderWidth',5449'borderAlign',5450'hoverBackgroundColor',5451'hoverBorderColor',5452'hoverBorderWidth',5453],54545455// Get index of the dataset in relation to the visible datasets. This allows determining the inner and outer radius correctly5456getRingIndex: function(datasetIndex) {5457var ringIndex = 0;54585459for (var j = 0; j < datasetIndex; ++j) {5460if (this.chart.isDatasetVisible(j)) {5461++ringIndex;5462}5463}54645465return ringIndex;5466},54675468update: function(reset) {5469var me = this;5470var chart = me.chart;5471var chartArea = chart.chartArea;5472var opts = chart.options;5473var ratioX = 1;5474var ratioY = 1;5475var offsetX = 0;5476var offsetY = 0;5477var meta = me.getMeta();5478var arcs = meta.data;5479var cutout = opts.cutoutPercentage / 100 || 0;5480var circumference = opts.circumference;5481var chartWeight = me._getRingWeight(me.index);5482var maxWidth, maxHeight, i, ilen;54835484// If the chart's circumference isn't a full circle, calculate size as a ratio of the width/height of the arc5485if (circumference < DOUBLE_PI$1) {5486var startAngle = opts.rotation % DOUBLE_PI$1;5487startAngle += startAngle >= PI$1 ? -DOUBLE_PI$1 : startAngle < -PI$1 ? DOUBLE_PI$1 : 0;5488var endAngle = startAngle + circumference;5489var startX = Math.cos(startAngle);5490var startY = Math.sin(startAngle);5491var endX = Math.cos(endAngle);5492var endY = Math.sin(endAngle);5493var contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI$1;5494var contains90 = (startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1) || endAngle >= DOUBLE_PI$1 + HALF_PI$1;5495var contains180 = startAngle === -PI$1 || endAngle >= PI$1;5496var contains270 = (startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1) || endAngle >= PI$1 + HALF_PI$1;5497var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout);5498var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout);5499var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout);5500var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout);5501ratioX = (maxX - minX) / 2;5502ratioY = (maxY - minY) / 2;5503offsetX = -(maxX + minX) / 2;5504offsetY = -(maxY + minY) / 2;5505}55065507for (i = 0, ilen = arcs.length; i < ilen; ++i) {5508arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);5509}55105511chart.borderWidth = me.getMaxBorderWidth();5512maxWidth = (chartArea.right - chartArea.left - chart.borderWidth) / ratioX;5513maxHeight = (chartArea.bottom - chartArea.top - chart.borderWidth) / ratioY;5514chart.outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);5515chart.innerRadius = Math.max(chart.outerRadius * cutout, 0);5516chart.radiusLength = (chart.outerRadius - chart.innerRadius) / (me._getVisibleDatasetWeightTotal() || 1);5517chart.offsetX = offsetX * chart.outerRadius;5518chart.offsetY = offsetY * chart.outerRadius;55195520meta.total = me.calculateTotal();55215522me.outerRadius = chart.outerRadius - chart.radiusLength * me._getRingWeightOffset(me.index);5523me.innerRadius = Math.max(me.outerRadius - chart.radiusLength * chartWeight, 0);55245525for (i = 0, ilen = arcs.length; i < ilen; ++i) {5526me.updateElement(arcs[i], i, reset);5527}5528},55295530updateElement: function(arc, index, reset) {5531var me = this;5532var chart = me.chart;5533var chartArea = chart.chartArea;5534var opts = chart.options;5535var animationOpts = opts.animation;5536var centerX = (chartArea.left + chartArea.right) / 2;5537var centerY = (chartArea.top + chartArea.bottom) / 2;5538var startAngle = opts.rotation; // non reset case handled later5539var endAngle = opts.rotation; // non reset case handled later5540var dataset = me.getDataset();5541var circumference = reset && animationOpts.animateRotate ? 0 : arc.hidden ? 0 : me.calculateCircumference(dataset.data[index]) * (opts.circumference / DOUBLE_PI$1);5542var innerRadius = reset && animationOpts.animateScale ? 0 : me.innerRadius;5543var outerRadius = reset && animationOpts.animateScale ? 0 : me.outerRadius;5544var options = arc._options || {};55455546helpers$1.extend(arc, {5547// Utility5548_datasetIndex: me.index,5549_index: index,55505551// Desired view properties5552_model: {5553backgroundColor: options.backgroundColor,5554borderColor: options.borderColor,5555borderWidth: options.borderWidth,5556borderAlign: options.borderAlign,5557x: centerX + chart.offsetX,5558y: centerY + chart.offsetY,5559startAngle: startAngle,5560endAngle: endAngle,5561circumference: circumference,5562outerRadius: outerRadius,5563innerRadius: innerRadius,5564label: helpers$1.valueAtIndexOrDefault(dataset.label, index, chart.data.labels[index])5565}5566});55675568var model = arc._model;55695570// Set correct angles if not resetting5571if (!reset || !animationOpts.animateRotate) {5572if (index === 0) {5573model.startAngle = opts.rotation;5574} else {5575model.startAngle = me.getMeta().data[index - 1]._model.endAngle;5576}55775578model.endAngle = model.startAngle + model.circumference;5579}55805581arc.pivot();5582},55835584calculateTotal: function() {5585var dataset = this.getDataset();5586var meta = this.getMeta();5587var total = 0;5588var value;55895590helpers$1.each(meta.data, function(element, index) {5591value = dataset.data[index];5592if (!isNaN(value) && !element.hidden) {5593total += Math.abs(value);5594}5595});55965597/* if (total === 0) {5598total = NaN;5599}*/56005601return total;5602},56035604calculateCircumference: function(value) {5605var total = this.getMeta().total;5606if (total > 0 && !isNaN(value)) {5607return DOUBLE_PI$1 * (Math.abs(value) / total);5608}5609return 0;5610},56115612// gets the max border or hover width to properly scale pie charts5613getMaxBorderWidth: function(arcs) {5614var me = this;5615var max = 0;5616var chart = me.chart;5617var i, ilen, meta, arc, controller, options, borderWidth, hoverWidth;56185619if (!arcs) {5620// Find the outmost visible dataset5621for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {5622if (chart.isDatasetVisible(i)) {5623meta = chart.getDatasetMeta(i);5624arcs = meta.data;5625if (i !== me.index) {5626controller = meta.controller;5627}5628break;5629}5630}5631}56325633if (!arcs) {5634return 0;5635}56365637for (i = 0, ilen = arcs.length; i < ilen; ++i) {5638arc = arcs[i];5639if (controller) {5640controller._configure();5641options = controller._resolveDataElementOptions(arc, i);5642} else {5643options = arc._options;5644}5645if (options.borderAlign !== 'inner') {5646borderWidth = options.borderWidth;5647hoverWidth = options.hoverBorderWidth;56485649max = borderWidth > max ? borderWidth : max;5650max = hoverWidth > max ? hoverWidth : max;5651}5652}5653return max;5654},56555656/**5657* @protected5658*/5659setHoverStyle: function(arc) {5660var model = arc._model;5661var options = arc._options;5662var getHoverColor = helpers$1.getHoverColor;56635664arc.$previousStyle = {5665backgroundColor: model.backgroundColor,5666borderColor: model.borderColor,5667borderWidth: model.borderWidth,5668};56695670model.backgroundColor = valueOrDefault$5(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));5671model.borderColor = valueOrDefault$5(options.hoverBorderColor, getHoverColor(options.borderColor));5672model.borderWidth = valueOrDefault$5(options.hoverBorderWidth, options.borderWidth);5673},56745675/**5676* Get radius length offset of the dataset in relation to the visible datasets weights. This allows determining the inner and outer radius correctly5677* @private5678*/5679_getRingWeightOffset: function(datasetIndex) {5680var ringWeightOffset = 0;56815682for (var i = 0; i < datasetIndex; ++i) {5683if (this.chart.isDatasetVisible(i)) {5684ringWeightOffset += this._getRingWeight(i);5685}5686}56875688return ringWeightOffset;5689},56905691/**5692* @private5693*/5694_getRingWeight: function(dataSetIndex) {5695return Math.max(valueOrDefault$5(this.chart.data.datasets[dataSetIndex].weight, 1), 0);5696},56975698/**5699* Returns the sum of all visibile data set weights. This value can be 0.5700* @private5701*/5702_getVisibleDatasetWeightTotal: function() {5703return this._getRingWeightOffset(this.chart.data.datasets.length);5704}5705});57065707core_defaults._set('horizontalBar', {5708hover: {5709mode: 'index',5710axis: 'y'5711},57125713scales: {5714xAxes: [{5715type: 'linear',5716position: 'bottom'5717}],57185719yAxes: [{5720type: 'category',5721position: 'left',5722offset: true,5723gridLines: {5724offsetGridLines: true5725}5726}]5727},57285729elements: {5730rectangle: {5731borderSkipped: 'left'5732}5733},57345735tooltips: {5736mode: 'index',5737axis: 'y'5738}5739});57405741core_defaults._set('global', {5742datasets: {5743horizontalBar: {5744categoryPercentage: 0.8,5745barPercentage: 0.95746}5747}5748});57495750var controller_horizontalBar = controller_bar.extend({5751/**5752* @private5753*/5754_getValueScaleId: function() {5755return this.getMeta().xAxisID;5756},57575758/**5759* @private5760*/5761_getIndexScaleId: function() {5762return this.getMeta().yAxisID;5763}5764});57655766var valueOrDefault$6 = helpers$1.valueOrDefault;5767var resolve$2 = helpers$1.options.resolve;5768var isPointInArea = helpers$1.canvas._isPointInArea;57695770core_defaults._set('line', {5771showLines: true,5772spanGaps: false,57735774hover: {5775mode: 'label'5776},57775778scales: {5779xAxes: [{5780type: 'category',5781id: 'x-axis-0'5782}],5783yAxes: [{5784type: 'linear',5785id: 'y-axis-0'5786}]5787}5788});57895790function scaleClip(scale, halfBorderWidth) {5791var tickOpts = scale && scale.options.ticks || {};5792var reverse = tickOpts.reverse;5793var min = tickOpts.min === undefined ? halfBorderWidth : 0;5794var max = tickOpts.max === undefined ? halfBorderWidth : 0;5795return {5796start: reverse ? max : min,5797end: reverse ? min : max5798};5799}58005801function defaultClip(xScale, yScale, borderWidth) {5802var halfBorderWidth = borderWidth / 2;5803var x = scaleClip(xScale, halfBorderWidth);5804var y = scaleClip(yScale, halfBorderWidth);58055806return {5807top: y.end,5808right: x.end,5809bottom: y.start,5810left: x.start5811};5812}58135814function toClip(value) {5815var t, r, b, l;58165817if (helpers$1.isObject(value)) {5818t = value.top;5819r = value.right;5820b = value.bottom;5821l = value.left;5822} else {5823t = r = b = l = value;5824}58255826return {5827top: t,5828right: r,5829bottom: b,5830left: l5831};5832}583358345835var controller_line = core_datasetController.extend({58365837datasetElementType: elements.Line,58385839dataElementType: elements.Point,58405841/**5842* @private5843*/5844_datasetElementOptions: [5845'backgroundColor',5846'borderCapStyle',5847'borderColor',5848'borderDash',5849'borderDashOffset',5850'borderJoinStyle',5851'borderWidth',5852'cubicInterpolationMode',5853'fill'5854],58555856/**5857* @private5858*/5859_dataElementOptions: {5860backgroundColor: 'pointBackgroundColor',5861borderColor: 'pointBorderColor',5862borderWidth: 'pointBorderWidth',5863hitRadius: 'pointHitRadius',5864hoverBackgroundColor: 'pointHoverBackgroundColor',5865hoverBorderColor: 'pointHoverBorderColor',5866hoverBorderWidth: 'pointHoverBorderWidth',5867hoverRadius: 'pointHoverRadius',5868pointStyle: 'pointStyle',5869radius: 'pointRadius',5870rotation: 'pointRotation'5871},58725873update: function(reset) {5874var me = this;5875var meta = me.getMeta();5876var line = meta.dataset;5877var points = meta.data || [];5878var options = me.chart.options;5879var config = me._config;5880var showLine = me._showLine = valueOrDefault$6(config.showLine, options.showLines);5881var i, ilen;58825883me._xScale = me.getScaleForId(meta.xAxisID);5884me._yScale = me.getScaleForId(meta.yAxisID);58855886// Update Line5887if (showLine) {5888// Compatibility: If the properties are defined with only the old name, use those values5889if (config.tension !== undefined && config.lineTension === undefined) {5890config.lineTension = config.tension;5891}58925893// Utility5894line._scale = me._yScale;5895line._datasetIndex = me.index;5896// Data5897line._children = points;5898// Model5899line._model = me._resolveDatasetElementOptions(line);59005901line.pivot();5902}59035904// Update Points5905for (i = 0, ilen = points.length; i < ilen; ++i) {5906me.updateElement(points[i], i, reset);5907}59085909if (showLine && line._model.tension !== 0) {5910me.updateBezierControlPoints();5911}59125913// Now pivot the point for animation5914for (i = 0, ilen = points.length; i < ilen; ++i) {5915points[i].pivot();5916}5917},59185919updateElement: function(point, index, reset) {5920var me = this;5921var meta = me.getMeta();5922var custom = point.custom || {};5923var dataset = me.getDataset();5924var datasetIndex = me.index;5925var value = dataset.data[index];5926var xScale = me._xScale;5927var yScale = me._yScale;5928var lineModel = meta.dataset._model;5929var x, y;59305931var options = me._resolveDataElementOptions(point, index);59325933x = xScale.getPixelForValue(typeof value === 'object' ? value : NaN, index, datasetIndex);5934y = reset ? yScale.getBasePixel() : me.calculatePointY(value, index, datasetIndex);59355936// Utility5937point._xScale = xScale;5938point._yScale = yScale;5939point._options = options;5940point._datasetIndex = datasetIndex;5941point._index = index;59425943// Desired view properties5944point._model = {5945x: x,5946y: y,5947skip: custom.skip || isNaN(x) || isNaN(y),5948// Appearance5949radius: options.radius,5950pointStyle: options.pointStyle,5951rotation: options.rotation,5952backgroundColor: options.backgroundColor,5953borderColor: options.borderColor,5954borderWidth: options.borderWidth,5955tension: valueOrDefault$6(custom.tension, lineModel ? lineModel.tension : 0),5956steppedLine: lineModel ? lineModel.steppedLine : false,5957// Tooltip5958hitRadius: options.hitRadius5959};5960},59615962/**5963* @private5964*/5965_resolveDatasetElementOptions: function(element) {5966var me = this;5967var config = me._config;5968var custom = element.custom || {};5969var options = me.chart.options;5970var lineOptions = options.elements.line;5971var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);59725973// The default behavior of lines is to break at null values, according5974// to https://github.com/chartjs/Chart.js/issues/2435#issuecomment-2167181585975// This option gives lines the ability to span gaps5976values.spanGaps = valueOrDefault$6(config.spanGaps, options.spanGaps);5977values.tension = valueOrDefault$6(config.lineTension, lineOptions.tension);5978values.steppedLine = resolve$2([custom.steppedLine, config.steppedLine, lineOptions.stepped]);5979values.clip = toClip(valueOrDefault$6(config.clip, defaultClip(me._xScale, me._yScale, values.borderWidth)));59805981return values;5982},59835984calculatePointY: function(value, index, datasetIndex) {5985var me = this;5986var chart = me.chart;5987var yScale = me._yScale;5988var sumPos = 0;5989var sumNeg = 0;5990var i, ds, dsMeta, stackedRightValue, rightValue, metasets, ilen;59915992if (yScale.options.stacked) {5993rightValue = +yScale.getRightValue(value);5994metasets = chart._getSortedVisibleDatasetMetas();5995ilen = metasets.length;59965997for (i = 0; i < ilen; ++i) {5998dsMeta = metasets[i];5999if (dsMeta.index === datasetIndex) {6000break;6001}60026003ds = chart.data.datasets[dsMeta.index];6004if (dsMeta.type === 'line' && dsMeta.yAxisID === yScale.id) {6005stackedRightValue = +yScale.getRightValue(ds.data[index]);6006if (stackedRightValue < 0) {6007sumNeg += stackedRightValue || 0;6008} else {6009sumPos += stackedRightValue || 0;6010}6011}6012}60136014if (rightValue < 0) {6015return yScale.getPixelForValue(sumNeg + rightValue);6016}6017return yScale.getPixelForValue(sumPos + rightValue);6018}6019return yScale.getPixelForValue(value);6020},60216022updateBezierControlPoints: function() {6023var me = this;6024var chart = me.chart;6025var meta = me.getMeta();6026var lineModel = meta.dataset._model;6027var area = chart.chartArea;6028var points = meta.data || [];6029var i, ilen, model, controlPoints;60306031// Only consider points that are drawn in case the spanGaps option is used6032if (lineModel.spanGaps) {6033points = points.filter(function(pt) {6034return !pt._model.skip;6035});6036}60376038function capControlPoint(pt, min, max) {6039return Math.max(Math.min(pt, max), min);6040}60416042if (lineModel.cubicInterpolationMode === 'monotone') {6043helpers$1.splineCurveMonotone(points);6044} else {6045for (i = 0, ilen = points.length; i < ilen; ++i) {6046model = points[i]._model;6047controlPoints = helpers$1.splineCurve(6048helpers$1.previousItem(points, i)._model,6049model,6050helpers$1.nextItem(points, i)._model,6051lineModel.tension6052);6053model.controlPointPreviousX = controlPoints.previous.x;6054model.controlPointPreviousY = controlPoints.previous.y;6055model.controlPointNextX = controlPoints.next.x;6056model.controlPointNextY = controlPoints.next.y;6057}6058}60596060if (chart.options.elements.line.capBezierPoints) {6061for (i = 0, ilen = points.length; i < ilen; ++i) {6062model = points[i]._model;6063if (isPointInArea(model, area)) {6064if (i > 0 && isPointInArea(points[i - 1]._model, area)) {6065model.controlPointPreviousX = capControlPoint(model.controlPointPreviousX, area.left, area.right);6066model.controlPointPreviousY = capControlPoint(model.controlPointPreviousY, area.top, area.bottom);6067}6068if (i < points.length - 1 && isPointInArea(points[i + 1]._model, area)) {6069model.controlPointNextX = capControlPoint(model.controlPointNextX, area.left, area.right);6070model.controlPointNextY = capControlPoint(model.controlPointNextY, area.top, area.bottom);6071}6072}6073}6074}6075},60766077draw: function() {6078var me = this;6079var chart = me.chart;6080var meta = me.getMeta();6081var points = meta.data || [];6082var area = chart.chartArea;6083var canvas = chart.canvas;6084var i = 0;6085var ilen = points.length;6086var clip;60876088if (me._showLine) {6089clip = meta.dataset._model.clip;60906091helpers$1.canvas.clipArea(chart.ctx, {6092left: clip.left === false ? 0 : area.left - clip.left,6093right: clip.right === false ? canvas.width : area.right + clip.right,6094top: clip.top === false ? 0 : area.top - clip.top,6095bottom: clip.bottom === false ? canvas.height : area.bottom + clip.bottom6096});60976098meta.dataset.draw();60996100helpers$1.canvas.unclipArea(chart.ctx);6101}61026103// Draw the points6104for (; i < ilen; ++i) {6105points[i].draw(area);6106}6107},61086109/**6110* @protected6111*/6112setHoverStyle: function(point) {6113var model = point._model;6114var options = point._options;6115var getHoverColor = helpers$1.getHoverColor;61166117point.$previousStyle = {6118backgroundColor: model.backgroundColor,6119borderColor: model.borderColor,6120borderWidth: model.borderWidth,6121radius: model.radius6122};61236124model.backgroundColor = valueOrDefault$6(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));6125model.borderColor = valueOrDefault$6(options.hoverBorderColor, getHoverColor(options.borderColor));6126model.borderWidth = valueOrDefault$6(options.hoverBorderWidth, options.borderWidth);6127model.radius = valueOrDefault$6(options.hoverRadius, options.radius);6128},6129});61306131var resolve$3 = helpers$1.options.resolve;61326133core_defaults._set('polarArea', {6134scale: {6135type: 'radialLinear',6136angleLines: {6137display: false6138},6139gridLines: {6140circular: true6141},6142pointLabels: {6143display: false6144},6145ticks: {6146beginAtZero: true6147}6148},61496150// Boolean - Whether to animate the rotation of the chart6151animation: {6152animateRotate: true,6153animateScale: true6154},61556156startAngle: -0.5 * Math.PI,6157legendCallback: function(chart) {6158var list = document.createElement('ul');6159var data = chart.data;6160var datasets = data.datasets;6161var labels = data.labels;6162var i, ilen, listItem, listItemSpan;61636164list.setAttribute('class', chart.id + '-legend');6165if (datasets.length) {6166for (i = 0, ilen = datasets[0].data.length; i < ilen; ++i) {6167listItem = list.appendChild(document.createElement('li'));6168listItemSpan = listItem.appendChild(document.createElement('span'));6169listItemSpan.style.backgroundColor = datasets[0].backgroundColor[i];6170if (labels[i]) {6171listItem.appendChild(document.createTextNode(labels[i]));6172}6173}6174}61756176return list.outerHTML;6177},6178legend: {6179labels: {6180generateLabels: function(chart) {6181var data = chart.data;6182if (data.labels.length && data.datasets.length) {6183return data.labels.map(function(label, i) {6184var meta = chart.getDatasetMeta(0);6185var style = meta.controller.getStyle(i);61866187return {6188text: label,6189fillStyle: style.backgroundColor,6190strokeStyle: style.borderColor,6191lineWidth: style.borderWidth,6192hidden: isNaN(data.datasets[0].data[i]) || meta.data[i].hidden,61936194// Extra data used for toggling the correct item6195index: i6196};6197});6198}6199return [];6200}6201},62026203onClick: function(e, legendItem) {6204var index = legendItem.index;6205var chart = this.chart;6206var i, ilen, meta;62076208for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {6209meta = chart.getDatasetMeta(i);6210meta.data[index].hidden = !meta.data[index].hidden;6211}62126213chart.update();6214}6215},62166217// Need to override these to give a nice default6218tooltips: {6219callbacks: {6220title: function() {6221return '';6222},6223label: function(item, data) {6224return data.labels[item.index] + ': ' + item.yLabel;6225}6226}6227}6228});62296230var controller_polarArea = core_datasetController.extend({62316232dataElementType: elements.Arc,62336234linkScales: helpers$1.noop,62356236/**6237* @private6238*/6239_dataElementOptions: [6240'backgroundColor',6241'borderColor',6242'borderWidth',6243'borderAlign',6244'hoverBackgroundColor',6245'hoverBorderColor',6246'hoverBorderWidth',6247],62486249/**6250* @private6251*/6252_getIndexScaleId: function() {6253return this.chart.scale.id;6254},62556256/**6257* @private6258*/6259_getValueScaleId: function() {6260return this.chart.scale.id;6261},62626263update: function(reset) {6264var me = this;6265var dataset = me.getDataset();6266var meta = me.getMeta();6267var start = me.chart.options.startAngle || 0;6268var starts = me._starts = [];6269var angles = me._angles = [];6270var arcs = meta.data;6271var i, ilen, angle;62726273me._updateRadius();62746275meta.count = me.countVisibleElements();62766277for (i = 0, ilen = dataset.data.length; i < ilen; i++) {6278starts[i] = start;6279angle = me._computeAngle(i);6280angles[i] = angle;6281start += angle;6282}62836284for (i = 0, ilen = arcs.length; i < ilen; ++i) {6285arcs[i]._options = me._resolveDataElementOptions(arcs[i], i);6286me.updateElement(arcs[i], i, reset);6287}6288},62896290/**6291* @private6292*/6293_updateRadius: function() {6294var me = this;6295var chart = me.chart;6296var chartArea = chart.chartArea;6297var opts = chart.options;6298var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);62996300chart.outerRadius = Math.max(minSize / 2, 0);6301chart.innerRadius = Math.max(opts.cutoutPercentage ? (chart.outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);6302chart.radiusLength = (chart.outerRadius - chart.innerRadius) / chart.getVisibleDatasetCount();63036304me.outerRadius = chart.outerRadius - (chart.radiusLength * me.index);6305me.innerRadius = me.outerRadius - chart.radiusLength;6306},63076308updateElement: function(arc, index, reset) {6309var me = this;6310var chart = me.chart;6311var dataset = me.getDataset();6312var opts = chart.options;6313var animationOpts = opts.animation;6314var scale = chart.scale;6315var labels = chart.data.labels;63166317var centerX = scale.xCenter;6318var centerY = scale.yCenter;63196320// var negHalfPI = -0.5 * Math.PI;6321var datasetStartAngle = opts.startAngle;6322var distance = arc.hidden ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);6323var startAngle = me._starts[index];6324var endAngle = startAngle + (arc.hidden ? 0 : me._angles[index]);63256326var resetRadius = animationOpts.animateScale ? 0 : scale.getDistanceFromCenterForValue(dataset.data[index]);6327var options = arc._options || {};63286329helpers$1.extend(arc, {6330// Utility6331_datasetIndex: me.index,6332_index: index,6333_scale: scale,63346335// Desired view properties6336_model: {6337backgroundColor: options.backgroundColor,6338borderColor: options.borderColor,6339borderWidth: options.borderWidth,6340borderAlign: options.borderAlign,6341x: centerX,6342y: centerY,6343innerRadius: 0,6344outerRadius: reset ? resetRadius : distance,6345startAngle: reset && animationOpts.animateRotate ? datasetStartAngle : startAngle,6346endAngle: reset && animationOpts.animateRotate ? datasetStartAngle : endAngle,6347label: helpers$1.valueAtIndexOrDefault(labels, index, labels[index])6348}6349});63506351arc.pivot();6352},63536354countVisibleElements: function() {6355var dataset = this.getDataset();6356var meta = this.getMeta();6357var count = 0;63586359helpers$1.each(meta.data, function(element, index) {6360if (!isNaN(dataset.data[index]) && !element.hidden) {6361count++;6362}6363});63646365return count;6366},63676368/**6369* @protected6370*/6371setHoverStyle: function(arc) {6372var model = arc._model;6373var options = arc._options;6374var getHoverColor = helpers$1.getHoverColor;6375var valueOrDefault = helpers$1.valueOrDefault;63766377arc.$previousStyle = {6378backgroundColor: model.backgroundColor,6379borderColor: model.borderColor,6380borderWidth: model.borderWidth,6381};63826383model.backgroundColor = valueOrDefault(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));6384model.borderColor = valueOrDefault(options.hoverBorderColor, getHoverColor(options.borderColor));6385model.borderWidth = valueOrDefault(options.hoverBorderWidth, options.borderWidth);6386},63876388/**6389* @private6390*/6391_computeAngle: function(index) {6392var me = this;6393var count = this.getMeta().count;6394var dataset = me.getDataset();6395var meta = me.getMeta();63966397if (isNaN(dataset.data[index]) || meta.data[index].hidden) {6398return 0;6399}64006401// Scriptable options6402var context = {6403chart: me.chart,6404dataIndex: index,6405dataset: dataset,6406datasetIndex: me.index6407};64086409return resolve$3([6410me.chart.options.elements.arc.angle,6411(2 * Math.PI) / count6412], context, index);6413}6414});64156416core_defaults._set('pie', helpers$1.clone(core_defaults.doughnut));6417core_defaults._set('pie', {6418cutoutPercentage: 06419});64206421// Pie charts are Doughnut chart with different defaults6422var controller_pie = controller_doughnut;64236424var valueOrDefault$7 = helpers$1.valueOrDefault;64256426core_defaults._set('radar', {6427spanGaps: false,6428scale: {6429type: 'radialLinear'6430},6431elements: {6432line: {6433fill: 'start',6434tension: 0 // no bezier in radar6435}6436}6437});64386439var controller_radar = core_datasetController.extend({6440datasetElementType: elements.Line,64416442dataElementType: elements.Point,64436444linkScales: helpers$1.noop,64456446/**6447* @private6448*/6449_datasetElementOptions: [6450'backgroundColor',6451'borderWidth',6452'borderColor',6453'borderCapStyle',6454'borderDash',6455'borderDashOffset',6456'borderJoinStyle',6457'fill'6458],64596460/**6461* @private6462*/6463_dataElementOptions: {6464backgroundColor: 'pointBackgroundColor',6465borderColor: 'pointBorderColor',6466borderWidth: 'pointBorderWidth',6467hitRadius: 'pointHitRadius',6468hoverBackgroundColor: 'pointHoverBackgroundColor',6469hoverBorderColor: 'pointHoverBorderColor',6470hoverBorderWidth: 'pointHoverBorderWidth',6471hoverRadius: 'pointHoverRadius',6472pointStyle: 'pointStyle',6473radius: 'pointRadius',6474rotation: 'pointRotation'6475},64766477/**6478* @private6479*/6480_getIndexScaleId: function() {6481return this.chart.scale.id;6482},64836484/**6485* @private6486*/6487_getValueScaleId: function() {6488return this.chart.scale.id;6489},64906491update: function(reset) {6492var me = this;6493var meta = me.getMeta();6494var line = meta.dataset;6495var points = meta.data || [];6496var scale = me.chart.scale;6497var config = me._config;6498var i, ilen;64996500// Compatibility: If the properties are defined with only the old name, use those values6501if (config.tension !== undefined && config.lineTension === undefined) {6502config.lineTension = config.tension;6503}65046505// Utility6506line._scale = scale;6507line._datasetIndex = me.index;6508// Data6509line._children = points;6510line._loop = true;6511// Model6512line._model = me._resolveDatasetElementOptions(line);65136514line.pivot();65156516// Update Points6517for (i = 0, ilen = points.length; i < ilen; ++i) {6518me.updateElement(points[i], i, reset);6519}65206521// Update bezier control points6522me.updateBezierControlPoints();65236524// Now pivot the point for animation6525for (i = 0, ilen = points.length; i < ilen; ++i) {6526points[i].pivot();6527}6528},65296530updateElement: function(point, index, reset) {6531var me = this;6532var custom = point.custom || {};6533var dataset = me.getDataset();6534var scale = me.chart.scale;6535var pointPosition = scale.getPointPositionForValue(index, dataset.data[index]);6536var options = me._resolveDataElementOptions(point, index);6537var lineModel = me.getMeta().dataset._model;6538var x = reset ? scale.xCenter : pointPosition.x;6539var y = reset ? scale.yCenter : pointPosition.y;65406541// Utility6542point._scale = scale;6543point._options = options;6544point._datasetIndex = me.index;6545point._index = index;65466547// Desired view properties6548point._model = {6549x: x, // value not used in dataset scale, but we want a consistent API between scales6550y: y,6551skip: custom.skip || isNaN(x) || isNaN(y),6552// Appearance6553radius: options.radius,6554pointStyle: options.pointStyle,6555rotation: options.rotation,6556backgroundColor: options.backgroundColor,6557borderColor: options.borderColor,6558borderWidth: options.borderWidth,6559tension: valueOrDefault$7(custom.tension, lineModel ? lineModel.tension : 0),65606561// Tooltip6562hitRadius: options.hitRadius6563};6564},65656566/**6567* @private6568*/6569_resolveDatasetElementOptions: function() {6570var me = this;6571var config = me._config;6572var options = me.chart.options;6573var values = core_datasetController.prototype._resolveDatasetElementOptions.apply(me, arguments);65746575values.spanGaps = valueOrDefault$7(config.spanGaps, options.spanGaps);6576values.tension = valueOrDefault$7(config.lineTension, options.elements.line.tension);65776578return values;6579},65806581updateBezierControlPoints: function() {6582var me = this;6583var meta = me.getMeta();6584var area = me.chart.chartArea;6585var points = meta.data || [];6586var i, ilen, model, controlPoints;65876588// Only consider points that are drawn in case the spanGaps option is used6589if (meta.dataset._model.spanGaps) {6590points = points.filter(function(pt) {6591return !pt._model.skip;6592});6593}65946595function capControlPoint(pt, min, max) {6596return Math.max(Math.min(pt, max), min);6597}65986599for (i = 0, ilen = points.length; i < ilen; ++i) {6600model = points[i]._model;6601controlPoints = helpers$1.splineCurve(6602helpers$1.previousItem(points, i, true)._model,6603model,6604helpers$1.nextItem(points, i, true)._model,6605model.tension6606);66076608// Prevent the bezier going outside of the bounds of the graph6609model.controlPointPreviousX = capControlPoint(controlPoints.previous.x, area.left, area.right);6610model.controlPointPreviousY = capControlPoint(controlPoints.previous.y, area.top, area.bottom);6611model.controlPointNextX = capControlPoint(controlPoints.next.x, area.left, area.right);6612model.controlPointNextY = capControlPoint(controlPoints.next.y, area.top, area.bottom);6613}6614},66156616setHoverStyle: function(point) {6617var model = point._model;6618var options = point._options;6619var getHoverColor = helpers$1.getHoverColor;66206621point.$previousStyle = {6622backgroundColor: model.backgroundColor,6623borderColor: model.borderColor,6624borderWidth: model.borderWidth,6625radius: model.radius6626};66276628model.backgroundColor = valueOrDefault$7(options.hoverBackgroundColor, getHoverColor(options.backgroundColor));6629model.borderColor = valueOrDefault$7(options.hoverBorderColor, getHoverColor(options.borderColor));6630model.borderWidth = valueOrDefault$7(options.hoverBorderWidth, options.borderWidth);6631model.radius = valueOrDefault$7(options.hoverRadius, options.radius);6632}6633});66346635core_defaults._set('scatter', {6636hover: {6637mode: 'single'6638},66396640scales: {6641xAxes: [{6642id: 'x-axis-1', // need an ID so datasets can reference the scale6643type: 'linear', // scatter should not use a category axis6644position: 'bottom'6645}],6646yAxes: [{6647id: 'y-axis-1',6648type: 'linear',6649position: 'left'6650}]6651},66526653tooltips: {6654callbacks: {6655title: function() {6656return ''; // doesn't make sense for scatter since data are formatted as a point6657},6658label: function(item) {6659return '(' + item.xLabel + ', ' + item.yLabel + ')';6660}6661}6662}6663});66646665core_defaults._set('global', {6666datasets: {6667scatter: {6668showLine: false6669}6670}6671});66726673// Scatter charts use line controllers6674var controller_scatter = controller_line;66756676// NOTE export a map in which the key represents the controller type, not6677// the class, and so must be CamelCase in order to be correctly retrieved6678// by the controller in core.controller.js (`controllers[meta.type]`).66796680var controllers = {6681bar: controller_bar,6682bubble: controller_bubble,6683doughnut: controller_doughnut,6684horizontalBar: controller_horizontalBar,6685line: controller_line,6686polarArea: controller_polarArea,6687pie: controller_pie,6688radar: controller_radar,6689scatter: controller_scatter6690};66916692/**6693* Helper function to get relative position for an event6694* @param {Event|IEvent} event - The event to get the position for6695* @param {Chart} chart - The chart6696* @returns {object} the event position6697*/6698function getRelativePosition(e, chart) {6699if (e.native) {6700return {6701x: e.x,6702y: e.y6703};6704}67056706return helpers$1.getRelativePosition(e, chart);6707}67086709/**6710* Helper function to traverse all of the visible elements in the chart6711* @param {Chart} chart - the chart6712* @param {function} handler - the callback to execute for each visible item6713*/6714function parseVisibleItems(chart, handler) {6715var metasets = chart._getSortedVisibleDatasetMetas();6716var metadata, i, j, ilen, jlen, element;67176718for (i = 0, ilen = metasets.length; i < ilen; ++i) {6719metadata = metasets[i].data;6720for (j = 0, jlen = metadata.length; j < jlen; ++j) {6721element = metadata[j];6722if (!element._view.skip) {6723handler(element);6724}6725}6726}6727}67286729/**6730* Helper function to get the items that intersect the event position6731* @param {ChartElement[]} items - elements to filter6732* @param {object} position - the point to be nearest to6733* @return {ChartElement[]} the nearest items6734*/6735function getIntersectItems(chart, position) {6736var elements = [];67376738parseVisibleItems(chart, function(element) {6739if (element.inRange(position.x, position.y)) {6740elements.push(element);6741}6742});67436744return elements;6745}67466747/**6748* Helper function to get the items nearest to the event position considering all visible items in teh chart6749* @param {Chart} chart - the chart to look at elements from6750* @param {object} position - the point to be nearest to6751* @param {boolean} intersect - if true, only consider items that intersect the position6752* @param {function} distanceMetric - function to provide the distance between points6753* @return {ChartElement[]} the nearest items6754*/6755function getNearestItems(chart, position, intersect, distanceMetric) {6756var minDistance = Number.POSITIVE_INFINITY;6757var nearestItems = [];67586759parseVisibleItems(chart, function(element) {6760if (intersect && !element.inRange(position.x, position.y)) {6761return;6762}67636764var center = element.getCenterPoint();6765var distance = distanceMetric(position, center);6766if (distance < minDistance) {6767nearestItems = [element];6768minDistance = distance;6769} else if (distance === minDistance) {6770// Can have multiple items at the same distance in which case we sort by size6771nearestItems.push(element);6772}6773});67746775return nearestItems;6776}67776778/**6779* Get a distance metric function for two points based on the6780* axis mode setting6781* @param {string} axis - the axis mode. x|y|xy6782*/6783function getDistanceMetricForAxis(axis) {6784var useX = axis.indexOf('x') !== -1;6785var useY = axis.indexOf('y') !== -1;67866787return function(pt1, pt2) {6788var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;6789var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;6790return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));6791};6792}67936794function indexMode(chart, e, options) {6795var position = getRelativePosition(e, chart);6796// Default axis for index mode is 'x' to match old behaviour6797options.axis = options.axis || 'x';6798var distanceMetric = getDistanceMetricForAxis(options.axis);6799var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);6800var elements = [];68016802if (!items.length) {6803return [];6804}68056806chart._getSortedVisibleDatasetMetas().forEach(function(meta) {6807var element = meta.data[items[0]._index];68086809// don't count items that are skipped (null data)6810if (element && !element._view.skip) {6811elements.push(element);6812}6813});68146815return elements;6816}68176818/**6819* @interface IInteractionOptions6820*/6821/**6822* If true, only consider items that intersect the point6823* @name IInterfaceOptions#boolean6824* @type Boolean6825*/68266827/**6828* Contains interaction related functions6829* @namespace Chart.Interaction6830*/6831var core_interaction = {6832// Helper function for different modes6833modes: {6834single: function(chart, e) {6835var position = getRelativePosition(e, chart);6836var elements = [];68376838parseVisibleItems(chart, function(element) {6839if (element.inRange(position.x, position.y)) {6840elements.push(element);6841return elements;6842}6843});68446845return elements.slice(0, 1);6846},68476848/**6849* @function Chart.Interaction.modes.label6850* @deprecated since version 2.4.06851* @todo remove at version 36852* @private6853*/6854label: indexMode,68556856/**6857* Returns items at the same index. If the options.intersect parameter is true, we only return items if we intersect something6858* If the options.intersect mode is false, we find the nearest item and return the items at the same index as that item6859* @function Chart.Interaction.modes.index6860* @since v2.4.06861* @param {Chart} chart - the chart we are returning items from6862* @param {Event} e - the event we are find things at6863* @param {IInteractionOptions} options - options to use during interaction6864* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned6865*/6866index: indexMode,68676868/**6869* Returns items in the same dataset. If the options.intersect parameter is true, we only return items if we intersect something6870* If the options.intersect is false, we find the nearest item and return the items in that dataset6871* @function Chart.Interaction.modes.dataset6872* @param {Chart} chart - the chart we are returning items from6873* @param {Event} e - the event we are find things at6874* @param {IInteractionOptions} options - options to use during interaction6875* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned6876*/6877dataset: function(chart, e, options) {6878var position = getRelativePosition(e, chart);6879options.axis = options.axis || 'xy';6880var distanceMetric = getDistanceMetricForAxis(options.axis);6881var items = options.intersect ? getIntersectItems(chart, position) : getNearestItems(chart, position, false, distanceMetric);68826883if (items.length > 0) {6884items = chart.getDatasetMeta(items[0]._datasetIndex).data;6885}68866887return items;6888},68896890/**6891* @function Chart.Interaction.modes.x-axis6892* @deprecated since version 2.4.0. Use index mode and intersect == true6893* @todo remove at version 36894* @private6895*/6896'x-axis': function(chart, e) {6897return indexMode(chart, e, {intersect: false});6898},68996900/**6901* Point mode returns all elements that hit test based on the event position6902* of the event6903* @function Chart.Interaction.modes.intersect6904* @param {Chart} chart - the chart we are returning items from6905* @param {Event} e - the event we are find things at6906* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned6907*/6908point: function(chart, e) {6909var position = getRelativePosition(e, chart);6910return getIntersectItems(chart, position);6911},69126913/**6914* nearest mode returns the element closest to the point6915* @function Chart.Interaction.modes.intersect6916* @param {Chart} chart - the chart we are returning items from6917* @param {Event} e - the event we are find things at6918* @param {IInteractionOptions} options - options to use6919* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned6920*/6921nearest: function(chart, e, options) {6922var position = getRelativePosition(e, chart);6923options.axis = options.axis || 'xy';6924var distanceMetric = getDistanceMetricForAxis(options.axis);6925return getNearestItems(chart, position, options.intersect, distanceMetric);6926},69276928/**6929* x mode returns the elements that hit-test at the current x coordinate6930* @function Chart.Interaction.modes.x6931* @param {Chart} chart - the chart we are returning items from6932* @param {Event} e - the event we are find things at6933* @param {IInteractionOptions} options - options to use6934* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned6935*/6936x: function(chart, e, options) {6937var position = getRelativePosition(e, chart);6938var items = [];6939var intersectsItem = false;69406941parseVisibleItems(chart, function(element) {6942if (element.inXRange(position.x)) {6943items.push(element);6944}69456946if (element.inRange(position.x, position.y)) {6947intersectsItem = true;6948}6949});69506951// If we want to trigger on an intersect and we don't have any items6952// that intersect the position, return nothing6953if (options.intersect && !intersectsItem) {6954items = [];6955}6956return items;6957},69586959/**6960* y mode returns the elements that hit-test at the current y coordinate6961* @function Chart.Interaction.modes.y6962* @param {Chart} chart - the chart we are returning items from6963* @param {Event} e - the event we are find things at6964* @param {IInteractionOptions} options - options to use6965* @return {Chart.Element[]} Array of elements that are under the point. If none are found, an empty array is returned6966*/6967y: function(chart, e, options) {6968var position = getRelativePosition(e, chart);6969var items = [];6970var intersectsItem = false;69716972parseVisibleItems(chart, function(element) {6973if (element.inYRange(position.y)) {6974items.push(element);6975}69766977if (element.inRange(position.x, position.y)) {6978intersectsItem = true;6979}6980});69816982// If we want to trigger on an intersect and we don't have any items6983// that intersect the position, return nothing6984if (options.intersect && !intersectsItem) {6985items = [];6986}6987return items;6988}6989}6990};69916992var extend = helpers$1.extend;69936994function filterByPosition(array, position) {6995return helpers$1.where(array, function(v) {6996return v.pos === position;6997});6998}69997000function sortByWeight(array, reverse) {7001return array.sort(function(a, b) {7002var v0 = reverse ? b : a;7003var v1 = reverse ? a : b;7004return v0.weight === v1.weight ?7005v0.index - v1.index :7006v0.weight - v1.weight;7007});7008}70097010function wrapBoxes(boxes) {7011var layoutBoxes = [];7012var i, ilen, box;70137014for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {7015box = boxes[i];7016layoutBoxes.push({7017index: i,7018box: box,7019pos: box.position,7020horizontal: box.isHorizontal(),7021weight: box.weight7022});7023}7024return layoutBoxes;7025}70267027function setLayoutDims(layouts, params) {7028var i, ilen, layout;7029for (i = 0, ilen = layouts.length; i < ilen; ++i) {7030layout = layouts[i];7031// store width used instead of chartArea.w in fitBoxes7032layout.width = layout.horizontal7033? layout.box.fullWidth && params.availableWidth7034: params.vBoxMaxWidth;7035// store height used instead of chartArea.h in fitBoxes7036layout.height = layout.horizontal && params.hBoxMaxHeight;7037}7038}70397040function buildLayoutBoxes(boxes) {7041var layoutBoxes = wrapBoxes(boxes);7042var left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);7043var right = sortByWeight(filterByPosition(layoutBoxes, 'right'));7044var top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);7045var bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));70467047return {7048leftAndTop: left.concat(top),7049rightAndBottom: right.concat(bottom),7050chartArea: filterByPosition(layoutBoxes, 'chartArea'),7051vertical: left.concat(right),7052horizontal: top.concat(bottom)7053};7054}70557056function getCombinedMax(maxPadding, chartArea, a, b) {7057return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);7058}70597060function updateDims(chartArea, params, layout) {7061var box = layout.box;7062var maxPadding = chartArea.maxPadding;7063var newWidth, newHeight;70647065if (layout.size) {7066// this layout was already counted for, lets first reduce old size7067chartArea[layout.pos] -= layout.size;7068}7069layout.size = layout.horizontal ? box.height : box.width;7070chartArea[layout.pos] += layout.size;70717072if (box.getPadding) {7073var boxPadding = box.getPadding();7074maxPadding.top = Math.max(maxPadding.top, boxPadding.top);7075maxPadding.left = Math.max(maxPadding.left, boxPadding.left);7076maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);7077maxPadding.right = Math.max(maxPadding.right, boxPadding.right);7078}70797080newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right');7081newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom');70827083if (newWidth !== chartArea.w || newHeight !== chartArea.h) {7084chartArea.w = newWidth;7085chartArea.h = newHeight;70867087// return true if chart area changed in layout's direction7088return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h;7089}7090}70917092function handleMaxPadding(chartArea) {7093var maxPadding = chartArea.maxPadding;70947095function updatePos(pos) {7096var change = Math.max(maxPadding[pos] - chartArea[pos], 0);7097chartArea[pos] += change;7098return change;7099}7100chartArea.y += updatePos('top');7101chartArea.x += updatePos('left');7102updatePos('right');7103updatePos('bottom');7104}71057106function getMargins(horizontal, chartArea) {7107var maxPadding = chartArea.maxPadding;71087109function marginForPositions(positions) {7110var margin = {left: 0, top: 0, right: 0, bottom: 0};7111positions.forEach(function(pos) {7112margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);7113});7114return margin;7115}71167117return horizontal7118? marginForPositions(['left', 'right'])7119: marginForPositions(['top', 'bottom']);7120}71217122function fitBoxes(boxes, chartArea, params) {7123var refitBoxes = [];7124var i, ilen, layout, box, refit, changed;71257126for (i = 0, ilen = boxes.length; i < ilen; ++i) {7127layout = boxes[i];7128box = layout.box;71297130box.update(7131layout.width || chartArea.w,7132layout.height || chartArea.h,7133getMargins(layout.horizontal, chartArea)7134);7135if (updateDims(chartArea, params, layout)) {7136changed = true;7137if (refitBoxes.length) {7138// Dimensions changed and there were non full width boxes before this7139// -> we have to refit those7140refit = true;7141}7142}7143if (!box.fullWidth) { // fullWidth boxes don't need to be re-fitted in any case7144refitBoxes.push(layout);7145}7146}71477148return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed;7149}71507151function placeBoxes(boxes, chartArea, params) {7152var userPadding = params.padding;7153var x = chartArea.x;7154var y = chartArea.y;7155var i, ilen, layout, box;71567157for (i = 0, ilen = boxes.length; i < ilen; ++i) {7158layout = boxes[i];7159box = layout.box;7160if (layout.horizontal) {7161box.left = box.fullWidth ? userPadding.left : chartArea.left;7162box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w;7163box.top = y;7164box.bottom = y + box.height;7165box.width = box.right - box.left;7166y = box.bottom;7167} else {7168box.left = x;7169box.right = x + box.width;7170box.top = chartArea.top;7171box.bottom = chartArea.top + chartArea.h;7172box.height = box.bottom - box.top;7173x = box.right;7174}7175}71767177chartArea.x = x;7178chartArea.y = y;7179}71807181core_defaults._set('global', {7182layout: {7183padding: {7184top: 0,7185right: 0,7186bottom: 0,7187left: 07188}7189}7190});71917192/**7193* @interface ILayoutItem7194* @prop {string} position - The position of the item in the chart layout. Possible values are7195* 'left', 'top', 'right', 'bottom', and 'chartArea'7196* @prop {number} weight - The weight used to sort the item. Higher weights are further away from the chart area7197* @prop {boolean} fullWidth - if true, and the item is horizontal, then push vertical boxes down7198* @prop {function} isHorizontal - returns true if the layout item is horizontal (ie. top or bottom)7199* @prop {function} update - Takes two parameters: width and height. Returns size of item7200* @prop {function} getPadding - Returns an object with padding on the edges7201* @prop {number} width - Width of item. Must be valid after update()7202* @prop {number} height - Height of item. Must be valid after update()7203* @prop {number} left - Left edge of the item. Set by layout system and cannot be used in update7204* @prop {number} top - Top edge of the item. Set by layout system and cannot be used in update7205* @prop {number} right - Right edge of the item. Set by layout system and cannot be used in update7206* @prop {number} bottom - Bottom edge of the item. Set by layout system and cannot be used in update7207*/72087209// The layout service is very self explanatory. It's responsible for the layout within a chart.7210// Scales, Legends and Plugins all rely on the layout service and can easily register to be placed anywhere they need7211// It is this service's responsibility of carrying out that layout.7212var core_layouts = {7213defaults: {},72147215/**7216* Register a box to a chart.7217* A box is simply a reference to an object that requires layout. eg. Scales, Legend, Title.7218* @param {Chart} chart - the chart to use7219* @param {ILayoutItem} item - the item to add to be layed out7220*/7221addBox: function(chart, item) {7222if (!chart.boxes) {7223chart.boxes = [];7224}72257226// initialize item with default values7227item.fullWidth = item.fullWidth || false;7228item.position = item.position || 'top';7229item.weight = item.weight || 0;7230item._layers = item._layers || function() {7231return [{7232z: 0,7233draw: function() {7234item.draw.apply(item, arguments);7235}7236}];7237};72387239chart.boxes.push(item);7240},72417242/**7243* Remove a layoutItem from a chart7244* @param {Chart} chart - the chart to remove the box from7245* @param {ILayoutItem} layoutItem - the item to remove from the layout7246*/7247removeBox: function(chart, layoutItem) {7248var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;7249if (index !== -1) {7250chart.boxes.splice(index, 1);7251}7252},72537254/**7255* Sets (or updates) options on the given `item`.7256* @param {Chart} chart - the chart in which the item lives (or will be added to)7257* @param {ILayoutItem} item - the item to configure with the given options7258* @param {object} options - the new item options.7259*/7260configure: function(chart, item, options) {7261var props = ['fullWidth', 'position', 'weight'];7262var ilen = props.length;7263var i = 0;7264var prop;72657266for (; i < ilen; ++i) {7267prop = props[i];7268if (options.hasOwnProperty(prop)) {7269item[prop] = options[prop];7270}7271}7272},72737274/**7275* Fits boxes of the given chart into the given size by having each box measure itself7276* then running a fitting algorithm7277* @param {Chart} chart - the chart7278* @param {number} width - the width to fit into7279* @param {number} height - the height to fit into7280*/7281update: function(chart, width, height) {7282if (!chart) {7283return;7284}72857286var layoutOptions = chart.options.layout || {};7287var padding = helpers$1.options.toPadding(layoutOptions.padding);72887289var availableWidth = width - padding.width;7290var availableHeight = height - padding.height;7291var boxes = buildLayoutBoxes(chart.boxes);7292var verticalBoxes = boxes.vertical;7293var horizontalBoxes = boxes.horizontal;72947295// Essentially we now have any number of boxes on each of the 4 sides.7296// Our canvas looks like the following.7297// The areas L1 and L2 are the left axes. R1 is the right axis, T1 is the top axis and7298// B1 is the bottom axis7299// There are also 4 quadrant-like locations (left to right instead of clockwise) reserved for chart overlays7300// These locations are single-box locations only, when trying to register a chartArea location that is already taken,7301// an error will be thrown.7302//7303// |----------------------------------------------------|7304// | T1 (Full Width) |7305// |----------------------------------------------------|7306// | | | T2 | |7307// | |----|-------------------------------------|----|7308// | | | C1 | | C2 | |7309// | | |----| |----| |7310// | | | | |7311// | L1 | L2 | ChartArea (C0) | R1 |7312// | | | | |7313// | | |----| |----| |7314// | | | C3 | | C4 | |7315// | |----|-------------------------------------|----|7316// | | | B1 | |7317// |----------------------------------------------------|7318// | B2 (Full Width) |7319// |----------------------------------------------------|7320//73217322var params = Object.freeze({7323outerWidth: width,7324outerHeight: height,7325padding: padding,7326availableWidth: availableWidth,7327vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length,7328hBoxMaxHeight: availableHeight / 27329});7330var chartArea = extend({7331maxPadding: extend({}, padding),7332w: availableWidth,7333h: availableHeight,7334x: padding.left,7335y: padding.top7336}, padding);73377338setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);73397340// First fit vertical boxes7341fitBoxes(verticalBoxes, chartArea, params);73427343// Then fit horizontal boxes7344if (fitBoxes(horizontalBoxes, chartArea, params)) {7345// if the area changed, re-fit vertical boxes7346fitBoxes(verticalBoxes, chartArea, params);7347}73487349handleMaxPadding(chartArea);73507351// Finally place the boxes to correct coordinates7352placeBoxes(boxes.leftAndTop, chartArea, params);73537354// Move to opposite side of chart7355chartArea.x += chartArea.w;7356chartArea.y += chartArea.h;73577358placeBoxes(boxes.rightAndBottom, chartArea, params);73597360chart.chartArea = {7361left: chartArea.left,7362top: chartArea.top,7363right: chartArea.left + chartArea.w,7364bottom: chartArea.top + chartArea.h7365};73667367// Finally update boxes in chartArea (radial scale for example)7368helpers$1.each(boxes.chartArea, function(layout) {7369var box = layout.box;7370extend(box, chart.chartArea);7371box.update(chartArea.w, chartArea.h);7372});7373}7374};73757376/**7377* Platform fallback implementation (minimal).7378* @see https://github.com/chartjs/Chart.js/pull/4591#issuecomment-3195759397379*/73807381var platform_basic = {7382acquireContext: function(item) {7383if (item && item.canvas) {7384// Support for any object associated to a canvas (including a context2d)7385item = item.canvas;7386}73877388return item && item.getContext('2d') || null;7389}7390};73917392var platform_dom = "/*\n * DOM element rendering detection\n * https://davidwalsh.name/detect-node-insertion\n */\n@keyframes chartjs-render-animation {\n\tfrom { opacity: 0.99; }\n\tto { opacity: 1; }\n}\n\n.chartjs-render-monitor {\n\tanimation: chartjs-render-animation 0.001s;\n}\n\n/*\n * DOM element resizing detection\n * https://github.com/marcj/css-element-queries\n */\n.chartjs-size-monitor,\n.chartjs-size-monitor-expand,\n.chartjs-size-monitor-shrink {\n\tposition: absolute;\n\tdirection: ltr;\n\tleft: 0;\n\ttop: 0;\n\tright: 0;\n\tbottom: 0;\n\toverflow: hidden;\n\tpointer-events: none;\n\tvisibility: hidden;\n\tz-index: -1;\n}\n\n.chartjs-size-monitor-expand > div {\n\tposition: absolute;\n\twidth: 1000000px;\n\theight: 1000000px;\n\tleft: 0;\n\ttop: 0;\n}\n\n.chartjs-size-monitor-shrink > div {\n\tposition: absolute;\n\twidth: 200%;\n\theight: 200%;\n\tleft: 0;\n\ttop: 0;\n}\n";73937394var platform_dom$1 = /*#__PURE__*/Object.freeze({7395__proto__: null,7396'default': platform_dom7397});73987399var stylesheet = getCjsExportFromNamespace(platform_dom$1);74007401var EXPANDO_KEY = '$chartjs';7402var CSS_PREFIX = 'chartjs-';7403var CSS_SIZE_MONITOR = CSS_PREFIX + 'size-monitor';7404var CSS_RENDER_MONITOR = CSS_PREFIX + 'render-monitor';7405var CSS_RENDER_ANIMATION = CSS_PREFIX + 'render-animation';7406var ANIMATION_START_EVENTS = ['animationstart', 'webkitAnimationStart'];74077408/**7409* DOM event types -> Chart.js event types.7410* Note: only events with different types are mapped.7411* @see https://developer.mozilla.org/en-US/docs/Web/Events7412*/7413var EVENT_TYPES = {7414touchstart: 'mousedown',7415touchmove: 'mousemove',7416touchend: 'mouseup',7417pointerenter: 'mouseenter',7418pointerdown: 'mousedown',7419pointermove: 'mousemove',7420pointerup: 'mouseup',7421pointerleave: 'mouseout',7422pointerout: 'mouseout'7423};74247425/**7426* The "used" size is the final value of a dimension property after all calculations have7427* been performed. This method uses the computed style of `element` but returns undefined7428* if the computed style is not expressed in pixels. That can happen in some cases where7429* `element` has a size relative to its parent and this last one is not yet displayed,7430* for example because of `display: none` on a parent node.7431* @see https://developer.mozilla.org/en-US/docs/Web/CSS/used_value7432* @returns {number} Size in pixels or undefined if unknown.7433*/7434function readUsedSize(element, property) {7435var value = helpers$1.getStyle(element, property);7436var matches = value && value.match(/^(\d+)(\.\d+)?px$/);7437return matches ? Number(matches[1]) : undefined;7438}74397440/**7441* Initializes the canvas style and render size without modifying the canvas display size,7442* since responsiveness is handled by the controller.resize() method. The config is used7443* to determine the aspect ratio to apply in case no explicit height has been specified.7444*/7445function initCanvas(canvas, config) {7446var style = canvas.style;74477448// NOTE(SB) canvas.getAttribute('width') !== canvas.width: in the first case it7449// returns null or '' if no explicit value has been set to the canvas attribute.7450var renderHeight = canvas.getAttribute('height');7451var renderWidth = canvas.getAttribute('width');74527453// Chart.js modifies some canvas values that we want to restore on destroy7454canvas[EXPANDO_KEY] = {7455initial: {7456height: renderHeight,7457width: renderWidth,7458style: {7459display: style.display,7460height: style.height,7461width: style.width7462}7463}7464};74657466// Force canvas to display as block to avoid extra space caused by inline7467// elements, which would interfere with the responsive resize process.7468// https://github.com/chartjs/Chart.js/issues/25387469style.display = style.display || 'block';74707471if (renderWidth === null || renderWidth === '') {7472var displayWidth = readUsedSize(canvas, 'width');7473if (displayWidth !== undefined) {7474canvas.width = displayWidth;7475}7476}74777478if (renderHeight === null || renderHeight === '') {7479if (canvas.style.height === '') {7480// If no explicit render height and style height, let's apply the aspect ratio,7481// which one can be specified by the user but also by charts as default option7482// (i.e. options.aspectRatio). If not specified, use canvas aspect ratio of 2.7483canvas.height = canvas.width / (config.options.aspectRatio || 2);7484} else {7485var displayHeight = readUsedSize(canvas, 'height');7486if (displayWidth !== undefined) {7487canvas.height = displayHeight;7488}7489}7490}74917492return canvas;7493}74947495/**7496* Detects support for options object argument in addEventListener.7497* https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#Safely_detecting_option_support7498* @private7499*/7500var supportsEventListenerOptions = (function() {7501var supports = false;7502try {7503var options = Object.defineProperty({}, 'passive', {7504// eslint-disable-next-line getter-return7505get: function() {7506supports = true;7507}7508});7509window.addEventListener('e', null, options);7510} catch (e) {7511// continue regardless of error7512}7513return supports;7514}());75157516// Default passive to true as expected by Chrome for 'touchstart' and 'touchend' events.7517// https://github.com/chartjs/Chart.js/issues/42877518var eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;75197520function addListener(node, type, listener) {7521node.addEventListener(type, listener, eventListenerOptions);7522}75237524function removeListener(node, type, listener) {7525node.removeEventListener(type, listener, eventListenerOptions);7526}75277528function createEvent(type, chart, x, y, nativeEvent) {7529return {7530type: type,7531chart: chart,7532native: nativeEvent || null,7533x: x !== undefined ? x : null,7534y: y !== undefined ? y : null,7535};7536}75377538function fromNativeEvent(event, chart) {7539var type = EVENT_TYPES[event.type] || event.type;7540var pos = helpers$1.getRelativePosition(event, chart);7541return createEvent(type, chart, pos.x, pos.y, event);7542}75437544function throttled(fn, thisArg) {7545var ticking = false;7546var args = [];75477548return function() {7549args = Array.prototype.slice.call(arguments);7550thisArg = thisArg || this;75517552if (!ticking) {7553ticking = true;7554helpers$1.requestAnimFrame.call(window, function() {7555ticking = false;7556fn.apply(thisArg, args);7557});7558}7559};7560}75617562function createDiv(cls) {7563var el = document.createElement('div');7564el.className = cls || '';7565return el;7566}75677568// Implementation based on https://github.com/marcj/css-element-queries7569function createResizer(handler) {7570var maxSize = 1000000;75717572// NOTE(SB) Don't use innerHTML because it could be considered unsafe.7573// https://github.com/chartjs/Chart.js/issues/59027574var resizer = createDiv(CSS_SIZE_MONITOR);7575var expand = createDiv(CSS_SIZE_MONITOR + '-expand');7576var shrink = createDiv(CSS_SIZE_MONITOR + '-shrink');75777578expand.appendChild(createDiv());7579shrink.appendChild(createDiv());75807581resizer.appendChild(expand);7582resizer.appendChild(shrink);7583resizer._reset = function() {7584expand.scrollLeft = maxSize;7585expand.scrollTop = maxSize;7586shrink.scrollLeft = maxSize;7587shrink.scrollTop = maxSize;7588};75897590var onScroll = function() {7591resizer._reset();7592handler();7593};75947595addListener(expand, 'scroll', onScroll.bind(expand, 'expand'));7596addListener(shrink, 'scroll', onScroll.bind(shrink, 'shrink'));75977598return resizer;7599}76007601// https://davidwalsh.name/detect-node-insertion7602function watchForRender(node, handler) {7603var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});7604var proxy = expando.renderProxy = function(e) {7605if (e.animationName === CSS_RENDER_ANIMATION) {7606handler();7607}7608};76097610helpers$1.each(ANIMATION_START_EVENTS, function(type) {7611addListener(node, type, proxy);7612});76137614// #4737: Chrome might skip the CSS animation when the CSS_RENDER_MONITOR class7615// is removed then added back immediately (same animation frame?). Accessing the7616// `offsetParent` property will force a reflow and re-evaluate the CSS animation.7617// https://gist.github.com/paulirish/5d52fb081b3570c81e3a#box-metrics7618// https://github.com/chartjs/Chart.js/issues/47377619expando.reflow = !!node.offsetParent;76207621node.classList.add(CSS_RENDER_MONITOR);7622}76237624function unwatchForRender(node) {7625var expando = node[EXPANDO_KEY] || {};7626var proxy = expando.renderProxy;76277628if (proxy) {7629helpers$1.each(ANIMATION_START_EVENTS, function(type) {7630removeListener(node, type, proxy);7631});76327633delete expando.renderProxy;7634}76357636node.classList.remove(CSS_RENDER_MONITOR);7637}76387639function addResizeListener(node, listener, chart) {7640var expando = node[EXPANDO_KEY] || (node[EXPANDO_KEY] = {});76417642// Let's keep track of this added resizer and thus avoid DOM query when removing it.7643var resizer = expando.resizer = createResizer(throttled(function() {7644if (expando.resizer) {7645var container = chart.options.maintainAspectRatio && node.parentNode;7646var w = container ? container.clientWidth : 0;7647listener(createEvent('resize', chart));7648if (container && container.clientWidth < w && chart.canvas) {7649// If the container size shrank during chart resize, let's assume7650// scrollbar appeared. So we resize again with the scrollbar visible -7651// effectively making chart smaller and the scrollbar hidden again.7652// Because we are inside `throttled`, and currently `ticking`, scroll7653// events are ignored during this whole 2 resize process.7654// If we assumed wrong and something else happened, we are resizing7655// twice in a frame (potential performance issue)7656listener(createEvent('resize', chart));7657}7658}7659}));76607661// The resizer needs to be attached to the node parent, so we first need to be7662// sure that `node` is attached to the DOM before injecting the resizer element.7663watchForRender(node, function() {7664if (expando.resizer) {7665var container = node.parentNode;7666if (container && container !== resizer.parentNode) {7667container.insertBefore(resizer, container.firstChild);7668}76697670// The container size might have changed, let's reset the resizer state.7671resizer._reset();7672}7673});7674}76757676function removeResizeListener(node) {7677var expando = node[EXPANDO_KEY] || {};7678var resizer = expando.resizer;76797680delete expando.resizer;7681unwatchForRender(node);76827683if (resizer && resizer.parentNode) {7684resizer.parentNode.removeChild(resizer);7685}7686}76877688/**7689* Injects CSS styles inline if the styles are not already present.7690* @param {HTMLDocument|ShadowRoot} rootNode - the node to contain the <style>.7691* @param {string} css - the CSS to be injected.7692*/7693function injectCSS(rootNode, css) {7694// https://stackoverflow.com/q/39221397695var expando = rootNode[EXPANDO_KEY] || (rootNode[EXPANDO_KEY] = {});7696if (!expando.containsStyles) {7697expando.containsStyles = true;7698css = '/* Chart.js */\n' + css;7699var style = document.createElement('style');7700style.setAttribute('type', 'text/css');7701style.appendChild(document.createTextNode(css));7702rootNode.appendChild(style);7703}7704}77057706var platform_dom$2 = {7707/**7708* When `true`, prevents the automatic injection of the stylesheet required to7709* correctly detect when the chart is added to the DOM and then resized. This7710* switch has been added to allow external stylesheet (`dist/Chart(.min)?.js`)7711* to be manually imported to make this library compatible with any CSP.7712* See https://github.com/chartjs/Chart.js/issues/52087713*/7714disableCSSInjection: false,77157716/**7717* This property holds whether this platform is enabled for the current environment.7718* Currently used by platform.js to select the proper implementation.7719* @private7720*/7721_enabled: typeof window !== 'undefined' && typeof document !== 'undefined',77227723/**7724* Initializes resources that depend on platform options.7725* @param {HTMLCanvasElement} canvas - The Canvas element.7726* @private7727*/7728_ensureLoaded: function(canvas) {7729if (!this.disableCSSInjection) {7730// If the canvas is in a shadow DOM, then the styles must also be inserted7731// into the same shadow DOM.7732// https://github.com/chartjs/Chart.js/issues/57637733var root = canvas.getRootNode ? canvas.getRootNode() : document;7734var targetNode = root.host ? root : document.head;7735injectCSS(targetNode, stylesheet);7736}7737},77387739acquireContext: function(item, config) {7740if (typeof item === 'string') {7741item = document.getElementById(item);7742} else if (item.length) {7743// Support for array based queries (such as jQuery)7744item = item[0];7745}77467747if (item && item.canvas) {7748// Support for any object associated to a canvas (including a context2d)7749item = item.canvas;7750}77517752// To prevent canvas fingerprinting, some add-ons undefine the getContext7753// method, for example: https://github.com/kkapsner/CanvasBlocker7754// https://github.com/chartjs/Chart.js/issues/28077755var context = item && item.getContext && item.getContext('2d');77567757// `instanceof HTMLCanvasElement/CanvasRenderingContext2D` fails when the item is7758// inside an iframe or when running in a protected environment. We could guess the7759// types from their toString() value but let's keep things flexible and assume it's7760// a sufficient condition if the item has a context2D which has item as `canvas`.7761// https://github.com/chartjs/Chart.js/issues/38877762// https://github.com/chartjs/Chart.js/issues/41027763// https://github.com/chartjs/Chart.js/issues/41527764if (context && context.canvas === item) {7765// Load platform resources on first chart creation, to make it possible to7766// import the library before setting platform options.7767this._ensureLoaded(item);7768initCanvas(item, config);7769return context;7770}77717772return null;7773},77747775releaseContext: function(context) {7776var canvas = context.canvas;7777if (!canvas[EXPANDO_KEY]) {7778return;7779}77807781var initial = canvas[EXPANDO_KEY].initial;7782['height', 'width'].forEach(function(prop) {7783var value = initial[prop];7784if (helpers$1.isNullOrUndef(value)) {7785canvas.removeAttribute(prop);7786} else {7787canvas.setAttribute(prop, value);7788}7789});77907791helpers$1.each(initial.style || {}, function(value, key) {7792canvas.style[key] = value;7793});77947795// The canvas render size might have been changed (and thus the state stack discarded),7796// we can't use save() and restore() to restore the initial state. So make sure that at7797// least the canvas context is reset to the default state by setting the canvas width.7798// https://www.w3.org/TR/2011/WD-html5-20110525/the-canvas-element.html7799// eslint-disable-next-line no-self-assign7800canvas.width = canvas.width;78017802delete canvas[EXPANDO_KEY];7803},78047805addEventListener: function(chart, type, listener) {7806var canvas = chart.canvas;7807if (type === 'resize') {7808// Note: the resize event is not supported on all browsers.7809addResizeListener(canvas, listener, chart);7810return;7811}78127813var expando = listener[EXPANDO_KEY] || (listener[EXPANDO_KEY] = {});7814var proxies = expando.proxies || (expando.proxies = {});7815var proxy = proxies[chart.id + '_' + type] = function(event) {7816listener(fromNativeEvent(event, chart));7817};78187819addListener(canvas, type, proxy);7820},78217822removeEventListener: function(chart, type, listener) {7823var canvas = chart.canvas;7824if (type === 'resize') {7825// Note: the resize event is not supported on all browsers.7826removeResizeListener(canvas);7827return;7828}78297830var expando = listener[EXPANDO_KEY] || {};7831var proxies = expando.proxies || {};7832var proxy = proxies[chart.id + '_' + type];7833if (!proxy) {7834return;7835}78367837removeListener(canvas, type, proxy);7838}7839};78407841// DEPRECATIONS78427843/**7844* Provided for backward compatibility, use EventTarget.addEventListener instead.7845* EventTarget.addEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+7846* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener7847* @function Chart.helpers.addEvent7848* @deprecated since version 2.7.07849* @todo remove at version 37850* @private7851*/7852helpers$1.addEvent = addListener;78537854/**7855* Provided for backward compatibility, use EventTarget.removeEventListener instead.7856* EventTarget.removeEventListener compatibility: Chrome, Opera 7, Safari, FF1.5+, IE9+7857* @see https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener7858* @function Chart.helpers.removeEvent7859* @deprecated since version 2.7.07860* @todo remove at version 37861* @private7862*/7863helpers$1.removeEvent = removeListener;78647865// @TODO Make possible to select another platform at build time.7866var implementation = platform_dom$2._enabled ? platform_dom$2 : platform_basic;78677868/**7869* @namespace Chart.platform7870* @see https://chartjs.gitbooks.io/proposals/content/Platform.html7871* @since 2.4.07872*/7873var platform = helpers$1.extend({7874/**7875* @since 2.7.07876*/7877initialize: function() {},78787879/**7880* Called at chart construction time, returns a context2d instance implementing7881* the [W3C Canvas 2D Context API standard]{@link https://www.w3.org/TR/2dcontext/}.7882* @param {*} item - The native item from which to acquire context (platform specific)7883* @param {object} options - The chart options7884* @returns {CanvasRenderingContext2D} context2d instance7885*/7886acquireContext: function() {},78877888/**7889* Called at chart destruction time, releases any resources associated to the context7890* previously returned by the acquireContext() method.7891* @param {CanvasRenderingContext2D} context - The context2d instance7892* @returns {boolean} true if the method succeeded, else false7893*/7894releaseContext: function() {},78957896/**7897* Registers the specified listener on the given chart.7898* @param {Chart} chart - Chart from which to listen for event7899* @param {string} type - The ({@link IEvent}) type to listen for7900* @param {function} listener - Receives a notification (an object that implements7901* the {@link IEvent} interface) when an event of the specified type occurs.7902*/7903addEventListener: function() {},79047905/**7906* Removes the specified listener previously registered with addEventListener.7907* @param {Chart} chart - Chart from which to remove the listener7908* @param {string} type - The ({@link IEvent}) type to remove7909* @param {function} listener - The listener function to remove from the event target.7910*/7911removeEventListener: function() {}79127913}, implementation);79147915core_defaults._set('global', {7916plugins: {}7917});79187919/**7920* The plugin service singleton7921* @namespace Chart.plugins7922* @since 2.1.07923*/7924var core_plugins = {7925/**7926* Globally registered plugins.7927* @private7928*/7929_plugins: [],79307931/**7932* This identifier is used to invalidate the descriptors cache attached to each chart7933* when a global plugin is registered or unregistered. In this case, the cache ID is7934* incremented and descriptors are regenerated during following API calls.7935* @private7936*/7937_cacheId: 0,79387939/**7940* Registers the given plugin(s) if not already registered.7941* @param {IPlugin[]|IPlugin} plugins plugin instance(s).7942*/7943register: function(plugins) {7944var p = this._plugins;7945([]).concat(plugins).forEach(function(plugin) {7946if (p.indexOf(plugin) === -1) {7947p.push(plugin);7948}7949});79507951this._cacheId++;7952},79537954/**7955* Unregisters the given plugin(s) only if registered.7956* @param {IPlugin[]|IPlugin} plugins plugin instance(s).7957*/7958unregister: function(plugins) {7959var p = this._plugins;7960([]).concat(plugins).forEach(function(plugin) {7961var idx = p.indexOf(plugin);7962if (idx !== -1) {7963p.splice(idx, 1);7964}7965});79667967this._cacheId++;7968},79697970/**7971* Remove all registered plugins.7972* @since 2.1.57973*/7974clear: function() {7975this._plugins = [];7976this._cacheId++;7977},79787979/**7980* Returns the number of registered plugins?7981* @returns {number}7982* @since 2.1.57983*/7984count: function() {7985return this._plugins.length;7986},79877988/**7989* Returns all registered plugin instances.7990* @returns {IPlugin[]} array of plugin objects.7991* @since 2.1.57992*/7993getAll: function() {7994return this._plugins;7995},79967997/**7998* Calls enabled plugins for `chart` on the specified hook and with the given args.7999* This method immediately returns as soon as a plugin explicitly returns false. The8000* returned value can be used, for instance, to interrupt the current action.8001* @param {Chart} chart - The chart instance for which plugins should be called.8002* @param {string} hook - The name of the plugin method to call (e.g. 'beforeUpdate').8003* @param {Array} [args] - Extra arguments to apply to the hook call.8004* @returns {boolean} false if any of the plugins return false, else returns true.8005*/8006notify: function(chart, hook, args) {8007var descriptors = this.descriptors(chart);8008var ilen = descriptors.length;8009var i, descriptor, plugin, params, method;80108011for (i = 0; i < ilen; ++i) {8012descriptor = descriptors[i];8013plugin = descriptor.plugin;8014method = plugin[hook];8015if (typeof method === 'function') {8016params = [chart].concat(args || []);8017params.push(descriptor.options);8018if (method.apply(plugin, params) === false) {8019return false;8020}8021}8022}80238024return true;8025},80268027/**8028* Returns descriptors of enabled plugins for the given chart.8029* @returns {object[]} [{ plugin, options }]8030* @private8031*/8032descriptors: function(chart) {8033var cache = chart.$plugins || (chart.$plugins = {});8034if (cache.id === this._cacheId) {8035return cache.descriptors;8036}80378038var plugins = [];8039var descriptors = [];8040var config = (chart && chart.config) || {};8041var options = (config.options && config.options.plugins) || {};80428043this._plugins.concat(config.plugins || []).forEach(function(plugin) {8044var idx = plugins.indexOf(plugin);8045if (idx !== -1) {8046return;8047}80488049var id = plugin.id;8050var opts = options[id];8051if (opts === false) {8052return;8053}80548055if (opts === true) {8056opts = helpers$1.clone(core_defaults.global.plugins[id]);8057}80588059plugins.push(plugin);8060descriptors.push({8061plugin: plugin,8062options: opts || {}8063});8064});80658066cache.descriptors = descriptors;8067cache.id = this._cacheId;8068return descriptors;8069},80708071/**8072* Invalidates cache for the given chart: descriptors hold a reference on plugin option,8073* but in some cases, this reference can be changed by the user when updating options.8074* https://github.com/chartjs/Chart.js/issues/5111#issuecomment-3559341678075* @private8076*/8077_invalidate: function(chart) {8078delete chart.$plugins;8079}8080};80818082var core_scaleService = {8083// Scale registration object. Extensions can register new scale types (such as log or DB scales) and then8084// use the new chart options to grab the correct scale8085constructors: {},8086// Use a registration function so that we can move to an ES6 map when we no longer need to support8087// old browsers80888089// Scale config defaults8090defaults: {},8091registerScaleType: function(type, scaleConstructor, scaleDefaults) {8092this.constructors[type] = scaleConstructor;8093this.defaults[type] = helpers$1.clone(scaleDefaults);8094},8095getScaleConstructor: function(type) {8096return this.constructors.hasOwnProperty(type) ? this.constructors[type] : undefined;8097},8098getScaleDefaults: function(type) {8099// Return the scale defaults merged with the global settings so that we always use the latest ones8100return this.defaults.hasOwnProperty(type) ? helpers$1.merge({}, [core_defaults.scale, this.defaults[type]]) : {};8101},8102updateScaleDefaults: function(type, additions) {8103var me = this;8104if (me.defaults.hasOwnProperty(type)) {8105me.defaults[type] = helpers$1.extend(me.defaults[type], additions);8106}8107},8108addScalesToLayout: function(chart) {8109// Adds each scale to the chart.boxes array to be sized accordingly8110helpers$1.each(chart.scales, function(scale) {8111// Set ILayoutItem parameters for backwards compatibility8112scale.fullWidth = scale.options.fullWidth;8113scale.position = scale.options.position;8114scale.weight = scale.options.weight;8115core_layouts.addBox(chart, scale);8116});8117}8118};81198120var valueOrDefault$8 = helpers$1.valueOrDefault;8121var getRtlHelper = helpers$1.rtl.getRtlAdapter;81228123core_defaults._set('global', {8124tooltips: {8125enabled: true,8126custom: null,8127mode: 'nearest',8128position: 'average',8129intersect: true,8130backgroundColor: 'rgba(0,0,0,0.8)',8131titleFontStyle: 'bold',8132titleSpacing: 2,8133titleMarginBottom: 6,8134titleFontColor: '#fff',8135titleAlign: 'left',8136bodySpacing: 2,8137bodyFontColor: '#fff',8138bodyAlign: 'left',8139footerFontStyle: 'bold',8140footerSpacing: 2,8141footerMarginTop: 6,8142footerFontColor: '#fff',8143footerAlign: 'left',8144yPadding: 6,8145xPadding: 6,8146caretPadding: 2,8147caretSize: 5,8148cornerRadius: 6,8149multiKeyBackground: '#fff',8150displayColors: true,8151borderColor: 'rgba(0,0,0,0)',8152borderWidth: 0,8153callbacks: {8154// Args are: (tooltipItems, data)8155beforeTitle: helpers$1.noop,8156title: function(tooltipItems, data) {8157var title = '';8158var labels = data.labels;8159var labelCount = labels ? labels.length : 0;81608161if (tooltipItems.length > 0) {8162var item = tooltipItems[0];8163if (item.label) {8164title = item.label;8165} else if (item.xLabel) {8166title = item.xLabel;8167} else if (labelCount > 0 && item.index < labelCount) {8168title = labels[item.index];8169}8170}81718172return title;8173},8174afterTitle: helpers$1.noop,81758176// Args are: (tooltipItems, data)8177beforeBody: helpers$1.noop,81788179// Args are: (tooltipItem, data)8180beforeLabel: helpers$1.noop,8181label: function(tooltipItem, data) {8182var label = data.datasets[tooltipItem.datasetIndex].label || '';81838184if (label) {8185label += ': ';8186}8187if (!helpers$1.isNullOrUndef(tooltipItem.value)) {8188label += tooltipItem.value;8189} else {8190label += tooltipItem.yLabel;8191}8192return label;8193},8194labelColor: function(tooltipItem, chart) {8195var meta = chart.getDatasetMeta(tooltipItem.datasetIndex);8196var activeElement = meta.data[tooltipItem.index];8197var view = activeElement._view;8198return {8199borderColor: view.borderColor,8200backgroundColor: view.backgroundColor8201};8202},8203labelTextColor: function() {8204return this._options.bodyFontColor;8205},8206afterLabel: helpers$1.noop,82078208// Args are: (tooltipItems, data)8209afterBody: helpers$1.noop,82108211// Args are: (tooltipItems, data)8212beforeFooter: helpers$1.noop,8213footer: helpers$1.noop,8214afterFooter: helpers$1.noop8215}8216}8217});82188219var positioners = {8220/**8221* Average mode places the tooltip at the average position of the elements shown8222* @function Chart.Tooltip.positioners.average8223* @param elements {ChartElement[]} the elements being displayed in the tooltip8224* @returns {object} tooltip position8225*/8226average: function(elements) {8227if (!elements.length) {8228return false;8229}82308231var i, len;8232var x = 0;8233var y = 0;8234var count = 0;82358236for (i = 0, len = elements.length; i < len; ++i) {8237var el = elements[i];8238if (el && el.hasValue()) {8239var pos = el.tooltipPosition();8240x += pos.x;8241y += pos.y;8242++count;8243}8244}82458246return {8247x: x / count,8248y: y / count8249};8250},82518252/**8253* Gets the tooltip position nearest of the item nearest to the event position8254* @function Chart.Tooltip.positioners.nearest8255* @param elements {Chart.Element[]} the tooltip elements8256* @param eventPosition {object} the position of the event in canvas coordinates8257* @returns {object} the tooltip position8258*/8259nearest: function(elements, eventPosition) {8260var x = eventPosition.x;8261var y = eventPosition.y;8262var minDistance = Number.POSITIVE_INFINITY;8263var i, len, nearestElement;82648265for (i = 0, len = elements.length; i < len; ++i) {8266var el = elements[i];8267if (el && el.hasValue()) {8268var center = el.getCenterPoint();8269var d = helpers$1.distanceBetweenPoints(eventPosition, center);82708271if (d < minDistance) {8272minDistance = d;8273nearestElement = el;8274}8275}8276}82778278if (nearestElement) {8279var tp = nearestElement.tooltipPosition();8280x = tp.x;8281y = tp.y;8282}82838284return {8285x: x,8286y: y8287};8288}8289};82908291// Helper to push or concat based on if the 2nd parameter is an array or not8292function pushOrConcat(base, toPush) {8293if (toPush) {8294if (helpers$1.isArray(toPush)) {8295// base = base.concat(toPush);8296Array.prototype.push.apply(base, toPush);8297} else {8298base.push(toPush);8299}8300}83018302return base;8303}83048305/**8306* Returns array of strings split by newline8307* @param {string} value - The value to split by newline.8308* @returns {string[]} value if newline present - Returned from String split() method8309* @function8310*/8311function splitNewlines(str) {8312if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {8313return str.split('\n');8314}8315return str;8316}831783188319/**8320* Private helper to create a tooltip item model8321* @param element - the chart element (point, arc, bar) to create the tooltip item for8322* @return new tooltip item8323*/8324function createTooltipItem(element) {8325var xScale = element._xScale;8326var yScale = element._yScale || element._scale; // handle radar || polarArea charts8327var index = element._index;8328var datasetIndex = element._datasetIndex;8329var controller = element._chart.getDatasetMeta(datasetIndex).controller;8330var indexScale = controller._getIndexScale();8331var valueScale = controller._getValueScale();83328333return {8334xLabel: xScale ? xScale.getLabelForIndex(index, datasetIndex) : '',8335yLabel: yScale ? yScale.getLabelForIndex(index, datasetIndex) : '',8336label: indexScale ? '' + indexScale.getLabelForIndex(index, datasetIndex) : '',8337value: valueScale ? '' + valueScale.getLabelForIndex(index, datasetIndex) : '',8338index: index,8339datasetIndex: datasetIndex,8340x: element._model.x,8341y: element._model.y8342};8343}83448345/**8346* Helper to get the reset model for the tooltip8347* @param tooltipOpts {object} the tooltip options8348*/8349function getBaseModel(tooltipOpts) {8350var globalDefaults = core_defaults.global;83518352return {8353// Positioning8354xPadding: tooltipOpts.xPadding,8355yPadding: tooltipOpts.yPadding,8356xAlign: tooltipOpts.xAlign,8357yAlign: tooltipOpts.yAlign,83588359// Drawing direction and text direction8360rtl: tooltipOpts.rtl,8361textDirection: tooltipOpts.textDirection,83628363// Body8364bodyFontColor: tooltipOpts.bodyFontColor,8365_bodyFontFamily: valueOrDefault$8(tooltipOpts.bodyFontFamily, globalDefaults.defaultFontFamily),8366_bodyFontStyle: valueOrDefault$8(tooltipOpts.bodyFontStyle, globalDefaults.defaultFontStyle),8367_bodyAlign: tooltipOpts.bodyAlign,8368bodyFontSize: valueOrDefault$8(tooltipOpts.bodyFontSize, globalDefaults.defaultFontSize),8369bodySpacing: tooltipOpts.bodySpacing,83708371// Title8372titleFontColor: tooltipOpts.titleFontColor,8373_titleFontFamily: valueOrDefault$8(tooltipOpts.titleFontFamily, globalDefaults.defaultFontFamily),8374_titleFontStyle: valueOrDefault$8(tooltipOpts.titleFontStyle, globalDefaults.defaultFontStyle),8375titleFontSize: valueOrDefault$8(tooltipOpts.titleFontSize, globalDefaults.defaultFontSize),8376_titleAlign: tooltipOpts.titleAlign,8377titleSpacing: tooltipOpts.titleSpacing,8378titleMarginBottom: tooltipOpts.titleMarginBottom,83798380// Footer8381footerFontColor: tooltipOpts.footerFontColor,8382_footerFontFamily: valueOrDefault$8(tooltipOpts.footerFontFamily, globalDefaults.defaultFontFamily),8383_footerFontStyle: valueOrDefault$8(tooltipOpts.footerFontStyle, globalDefaults.defaultFontStyle),8384footerFontSize: valueOrDefault$8(tooltipOpts.footerFontSize, globalDefaults.defaultFontSize),8385_footerAlign: tooltipOpts.footerAlign,8386footerSpacing: tooltipOpts.footerSpacing,8387footerMarginTop: tooltipOpts.footerMarginTop,83888389// Appearance8390caretSize: tooltipOpts.caretSize,8391cornerRadius: tooltipOpts.cornerRadius,8392backgroundColor: tooltipOpts.backgroundColor,8393opacity: 0,8394legendColorBackground: tooltipOpts.multiKeyBackground,8395displayColors: tooltipOpts.displayColors,8396borderColor: tooltipOpts.borderColor,8397borderWidth: tooltipOpts.borderWidth8398};8399}84008401/**8402* Get the size of the tooltip8403*/8404function getTooltipSize(tooltip, model) {8405var ctx = tooltip._chart.ctx;84068407var height = model.yPadding * 2; // Tooltip Padding8408var width = 0;84098410// Count of all lines in the body8411var body = model.body;8412var combinedBodyLength = body.reduce(function(count, bodyItem) {8413return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length;8414}, 0);8415combinedBodyLength += model.beforeBody.length + model.afterBody.length;84168417var titleLineCount = model.title.length;8418var footerLineCount = model.footer.length;8419var titleFontSize = model.titleFontSize;8420var bodyFontSize = model.bodyFontSize;8421var footerFontSize = model.footerFontSize;84228423height += titleLineCount * titleFontSize; // Title Lines8424height += titleLineCount ? (titleLineCount - 1) * model.titleSpacing : 0; // Title Line Spacing8425height += titleLineCount ? model.titleMarginBottom : 0; // Title's bottom Margin8426height += combinedBodyLength * bodyFontSize; // Body Lines8427height += combinedBodyLength ? (combinedBodyLength - 1) * model.bodySpacing : 0; // Body Line Spacing8428height += footerLineCount ? model.footerMarginTop : 0; // Footer Margin8429height += footerLineCount * (footerFontSize); // Footer Lines8430height += footerLineCount ? (footerLineCount - 1) * model.footerSpacing : 0; // Footer Line Spacing84318432// Title width8433var widthPadding = 0;8434var maxLineWidth = function(line) {8435width = Math.max(width, ctx.measureText(line).width + widthPadding);8436};84378438ctx.font = helpers$1.fontString(titleFontSize, model._titleFontStyle, model._titleFontFamily);8439helpers$1.each(model.title, maxLineWidth);84408441// Body width8442ctx.font = helpers$1.fontString(bodyFontSize, model._bodyFontStyle, model._bodyFontFamily);8443helpers$1.each(model.beforeBody.concat(model.afterBody), maxLineWidth);84448445// Body lines may include some extra width due to the color box8446widthPadding = model.displayColors ? (bodyFontSize + 2) : 0;8447helpers$1.each(body, function(bodyItem) {8448helpers$1.each(bodyItem.before, maxLineWidth);8449helpers$1.each(bodyItem.lines, maxLineWidth);8450helpers$1.each(bodyItem.after, maxLineWidth);8451});84528453// Reset back to 08454widthPadding = 0;84558456// Footer width8457ctx.font = helpers$1.fontString(footerFontSize, model._footerFontStyle, model._footerFontFamily);8458helpers$1.each(model.footer, maxLineWidth);84598460// Add padding8461width += 2 * model.xPadding;84628463return {8464width: width,8465height: height8466};8467}84688469/**8470* Helper to get the alignment of a tooltip given the size8471*/8472function determineAlignment(tooltip, size) {8473var model = tooltip._model;8474var chart = tooltip._chart;8475var chartArea = tooltip._chart.chartArea;8476var xAlign = 'center';8477var yAlign = 'center';84788479if (model.y < size.height) {8480yAlign = 'top';8481} else if (model.y > (chart.height - size.height)) {8482yAlign = 'bottom';8483}84848485var lf, rf; // functions to determine left, right alignment8486var olf, orf; // functions to determine if left/right alignment causes tooltip to go outside chart8487var yf; // function to get the y alignment if the tooltip goes outside of the left or right edges8488var midX = (chartArea.left + chartArea.right) / 2;8489var midY = (chartArea.top + chartArea.bottom) / 2;84908491if (yAlign === 'center') {8492lf = function(x) {8493return x <= midX;8494};8495rf = function(x) {8496return x > midX;8497};8498} else {8499lf = function(x) {8500return x <= (size.width / 2);8501};8502rf = function(x) {8503return x >= (chart.width - (size.width / 2));8504};8505}85068507olf = function(x) {8508return x + size.width + model.caretSize + model.caretPadding > chart.width;8509};8510orf = function(x) {8511return x - size.width - model.caretSize - model.caretPadding < 0;8512};8513yf = function(y) {8514return y <= midY ? 'top' : 'bottom';8515};85168517if (lf(model.x)) {8518xAlign = 'left';85198520// Is tooltip too wide and goes over the right side of the chart.?8521if (olf(model.x)) {8522xAlign = 'center';8523yAlign = yf(model.y);8524}8525} else if (rf(model.x)) {8526xAlign = 'right';85278528// Is tooltip too wide and goes outside left edge of canvas?8529if (orf(model.x)) {8530xAlign = 'center';8531yAlign = yf(model.y);8532}8533}85348535var opts = tooltip._options;8536return {8537xAlign: opts.xAlign ? opts.xAlign : xAlign,8538yAlign: opts.yAlign ? opts.yAlign : yAlign8539};8540}85418542/**8543* Helper to get the location a tooltip needs to be placed at given the initial position (via the vm) and the size and alignment8544*/8545function getBackgroundPoint(vm, size, alignment, chart) {8546// Background Position8547var x = vm.x;8548var y = vm.y;85498550var caretSize = vm.caretSize;8551var caretPadding = vm.caretPadding;8552var cornerRadius = vm.cornerRadius;8553var xAlign = alignment.xAlign;8554var yAlign = alignment.yAlign;8555var paddingAndSize = caretSize + caretPadding;8556var radiusAndPadding = cornerRadius + caretPadding;85578558if (xAlign === 'right') {8559x -= size.width;8560} else if (xAlign === 'center') {8561x -= (size.width / 2);8562if (x + size.width > chart.width) {8563x = chart.width - size.width;8564}8565if (x < 0) {8566x = 0;8567}8568}85698570if (yAlign === 'top') {8571y += paddingAndSize;8572} else if (yAlign === 'bottom') {8573y -= size.height + paddingAndSize;8574} else {8575y -= (size.height / 2);8576}85778578if (yAlign === 'center') {8579if (xAlign === 'left') {8580x += paddingAndSize;8581} else if (xAlign === 'right') {8582x -= paddingAndSize;8583}8584} else if (xAlign === 'left') {8585x -= radiusAndPadding;8586} else if (xAlign === 'right') {8587x += radiusAndPadding;8588}85898590return {8591x: x,8592y: y8593};8594}85958596function getAlignedX(vm, align) {8597return align === 'center'8598? vm.x + vm.width / 28599: align === 'right'8600? vm.x + vm.width - vm.xPadding8601: vm.x + vm.xPadding;8602}86038604/**8605* Helper to build before and after body lines8606*/8607function getBeforeAfterBodyLines(callback) {8608return pushOrConcat([], splitNewlines(callback));8609}86108611var exports$4 = core_element.extend({8612initialize: function() {8613this._model = getBaseModel(this._options);8614this._lastActive = [];8615},86168617// Get the title8618// Args are: (tooltipItem, data)8619getTitle: function() {8620var me = this;8621var opts = me._options;8622var callbacks = opts.callbacks;86238624var beforeTitle = callbacks.beforeTitle.apply(me, arguments);8625var title = callbacks.title.apply(me, arguments);8626var afterTitle = callbacks.afterTitle.apply(me, arguments);86278628var lines = [];8629lines = pushOrConcat(lines, splitNewlines(beforeTitle));8630lines = pushOrConcat(lines, splitNewlines(title));8631lines = pushOrConcat(lines, splitNewlines(afterTitle));86328633return lines;8634},86358636// Args are: (tooltipItem, data)8637getBeforeBody: function() {8638return getBeforeAfterBodyLines(this._options.callbacks.beforeBody.apply(this, arguments));8639},86408641// Args are: (tooltipItem, data)8642getBody: function(tooltipItems, data) {8643var me = this;8644var callbacks = me._options.callbacks;8645var bodyItems = [];86468647helpers$1.each(tooltipItems, function(tooltipItem) {8648var bodyItem = {8649before: [],8650lines: [],8651after: []8652};8653pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, tooltipItem, data)));8654pushOrConcat(bodyItem.lines, callbacks.label.call(me, tooltipItem, data));8655pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, tooltipItem, data)));86568657bodyItems.push(bodyItem);8658});86598660return bodyItems;8661},86628663// Args are: (tooltipItem, data)8664getAfterBody: function() {8665return getBeforeAfterBodyLines(this._options.callbacks.afterBody.apply(this, arguments));8666},86678668// Get the footer and beforeFooter and afterFooter lines8669// Args are: (tooltipItem, data)8670getFooter: function() {8671var me = this;8672var callbacks = me._options.callbacks;86738674var beforeFooter = callbacks.beforeFooter.apply(me, arguments);8675var footer = callbacks.footer.apply(me, arguments);8676var afterFooter = callbacks.afterFooter.apply(me, arguments);86778678var lines = [];8679lines = pushOrConcat(lines, splitNewlines(beforeFooter));8680lines = pushOrConcat(lines, splitNewlines(footer));8681lines = pushOrConcat(lines, splitNewlines(afterFooter));86828683return lines;8684},86858686update: function(changed) {8687var me = this;8688var opts = me._options;86898690// Need to regenerate the model because its faster than using extend and it is necessary due to the optimization in Chart.Element.transition8691// 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 time8692// which breaks any animations.8693var existingModel = me._model;8694var model = me._model = getBaseModel(opts);8695var active = me._active;86968697var data = me._data;86988699// In the case where active.length === 0 we need to keep these at existing values for good animations8700var alignment = {8701xAlign: existingModel.xAlign,8702yAlign: existingModel.yAlign8703};8704var backgroundPoint = {8705x: existingModel.x,8706y: existingModel.y8707};8708var tooltipSize = {8709width: existingModel.width,8710height: existingModel.height8711};8712var tooltipPosition = {8713x: existingModel.caretX,8714y: existingModel.caretY8715};87168717var i, len;87188719if (active.length) {8720model.opacity = 1;87218722var labelColors = [];8723var labelTextColors = [];8724tooltipPosition = positioners[opts.position].call(me, active, me._eventPosition);87258726var tooltipItems = [];8727for (i = 0, len = active.length; i < len; ++i) {8728tooltipItems.push(createTooltipItem(active[i]));8729}87308731// If the user provided a filter function, use it to modify the tooltip items8732if (opts.filter) {8733tooltipItems = tooltipItems.filter(function(a) {8734return opts.filter(a, data);8735});8736}87378738// If the user provided a sorting function, use it to modify the tooltip items8739if (opts.itemSort) {8740tooltipItems = tooltipItems.sort(function(a, b) {8741return opts.itemSort(a, b, data);8742});8743}87448745// Determine colors for boxes8746helpers$1.each(tooltipItems, function(tooltipItem) {8747labelColors.push(opts.callbacks.labelColor.call(me, tooltipItem, me._chart));8748labelTextColors.push(opts.callbacks.labelTextColor.call(me, tooltipItem, me._chart));8749});875087518752// Build the Text Lines8753model.title = me.getTitle(tooltipItems, data);8754model.beforeBody = me.getBeforeBody(tooltipItems, data);8755model.body = me.getBody(tooltipItems, data);8756model.afterBody = me.getAfterBody(tooltipItems, data);8757model.footer = me.getFooter(tooltipItems, data);87588759// Initial positioning and colors8760model.x = tooltipPosition.x;8761model.y = tooltipPosition.y;8762model.caretPadding = opts.caretPadding;8763model.labelColors = labelColors;8764model.labelTextColors = labelTextColors;87658766// data points8767model.dataPoints = tooltipItems;87688769// We need to determine alignment of the tooltip8770tooltipSize = getTooltipSize(this, model);8771alignment = determineAlignment(this, tooltipSize);8772// Final Size and Position8773backgroundPoint = getBackgroundPoint(model, tooltipSize, alignment, me._chart);8774} else {8775model.opacity = 0;8776}87778778model.xAlign = alignment.xAlign;8779model.yAlign = alignment.yAlign;8780model.x = backgroundPoint.x;8781model.y = backgroundPoint.y;8782model.width = tooltipSize.width;8783model.height = tooltipSize.height;87848785// Point where the caret on the tooltip points to8786model.caretX = tooltipPosition.x;8787model.caretY = tooltipPosition.y;87888789me._model = model;87908791if (changed && opts.custom) {8792opts.custom.call(me, model);8793}87948795return me;8796},87978798drawCaret: function(tooltipPoint, size) {8799var ctx = this._chart.ctx;8800var vm = this._view;8801var caretPosition = this.getCaretPosition(tooltipPoint, size, vm);88028803ctx.lineTo(caretPosition.x1, caretPosition.y1);8804ctx.lineTo(caretPosition.x2, caretPosition.y2);8805ctx.lineTo(caretPosition.x3, caretPosition.y3);8806},8807getCaretPosition: function(tooltipPoint, size, vm) {8808var x1, x2, x3, y1, y2, y3;8809var caretSize = vm.caretSize;8810var cornerRadius = vm.cornerRadius;8811var xAlign = vm.xAlign;8812var yAlign = vm.yAlign;8813var ptX = tooltipPoint.x;8814var ptY = tooltipPoint.y;8815var width = size.width;8816var height = size.height;88178818if (yAlign === 'center') {8819y2 = ptY + (height / 2);88208821if (xAlign === 'left') {8822x1 = ptX;8823x2 = x1 - caretSize;8824x3 = x1;88258826y1 = y2 + caretSize;8827y3 = y2 - caretSize;8828} else {8829x1 = ptX + width;8830x2 = x1 + caretSize;8831x3 = x1;88328833y1 = y2 - caretSize;8834y3 = y2 + caretSize;8835}8836} else {8837if (xAlign === 'left') {8838x2 = ptX + cornerRadius + (caretSize);8839x1 = x2 - caretSize;8840x3 = x2 + caretSize;8841} else if (xAlign === 'right') {8842x2 = ptX + width - cornerRadius - caretSize;8843x1 = x2 - caretSize;8844x3 = x2 + caretSize;8845} else {8846x2 = vm.caretX;8847x1 = x2 - caretSize;8848x3 = x2 + caretSize;8849}8850if (yAlign === 'top') {8851y1 = ptY;8852y2 = y1 - caretSize;8853y3 = y1;8854} else {8855y1 = ptY + height;8856y2 = y1 + caretSize;8857y3 = y1;8858// invert drawing order8859var tmp = x3;8860x3 = x1;8861x1 = tmp;8862}8863}8864return {x1: x1, x2: x2, x3: x3, y1: y1, y2: y2, y3: y3};8865},88668867drawTitle: function(pt, vm, ctx) {8868var title = vm.title;8869var length = title.length;8870var titleFontSize, titleSpacing, i;88718872if (length) {8873var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);88748875pt.x = getAlignedX(vm, vm._titleAlign);88768877ctx.textAlign = rtlHelper.textAlign(vm._titleAlign);8878ctx.textBaseline = 'middle';88798880titleFontSize = vm.titleFontSize;8881titleSpacing = vm.titleSpacing;88828883ctx.fillStyle = vm.titleFontColor;8884ctx.font = helpers$1.fontString(titleFontSize, vm._titleFontStyle, vm._titleFontFamily);88858886for (i = 0; i < length; ++i) {8887ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFontSize / 2);8888pt.y += titleFontSize + titleSpacing; // Line Height and spacing88898890if (i + 1 === length) {8891pt.y += vm.titleMarginBottom - titleSpacing; // If Last, add margin, remove spacing8892}8893}8894}8895},88968897drawBody: function(pt, vm, ctx) {8898var bodyFontSize = vm.bodyFontSize;8899var bodySpacing = vm.bodySpacing;8900var bodyAlign = vm._bodyAlign;8901var body = vm.body;8902var drawColorBoxes = vm.displayColors;8903var xLinePadding = 0;8904var colorX = drawColorBoxes ? getAlignedX(vm, 'left') : 0;89058906var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);89078908var fillLineOfText = function(line) {8909ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyFontSize / 2);8910pt.y += bodyFontSize + bodySpacing;8911};89128913var bodyItem, textColor, labelColors, lines, i, j, ilen, jlen;8914var bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);89158916ctx.textAlign = bodyAlign;8917ctx.textBaseline = 'middle';8918ctx.font = helpers$1.fontString(bodyFontSize, vm._bodyFontStyle, vm._bodyFontFamily);89198920pt.x = getAlignedX(vm, bodyAlignForCalculation);89218922// Before body lines8923ctx.fillStyle = vm.bodyFontColor;8924helpers$1.each(vm.beforeBody, fillLineOfText);89258926xLinePadding = drawColorBoxes && bodyAlignForCalculation !== 'right'8927? bodyAlign === 'center' ? (bodyFontSize / 2 + 1) : (bodyFontSize + 2)8928: 0;89298930// Draw body lines now8931for (i = 0, ilen = body.length; i < ilen; ++i) {8932bodyItem = body[i];8933textColor = vm.labelTextColors[i];8934labelColors = vm.labelColors[i];89358936ctx.fillStyle = textColor;8937helpers$1.each(bodyItem.before, fillLineOfText);89388939lines = bodyItem.lines;8940for (j = 0, jlen = lines.length; j < jlen; ++j) {8941// Draw Legend-like boxes if needed8942if (drawColorBoxes) {8943var rtlColorX = rtlHelper.x(colorX);89448945// Fill a white rect so that colours merge nicely if the opacity is < 18946ctx.fillStyle = vm.legendColorBackground;8947ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);89488949// Border8950ctx.lineWidth = 1;8951ctx.strokeStyle = labelColors.borderColor;8952ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, bodyFontSize), pt.y, bodyFontSize, bodyFontSize);89538954// Inner square8955ctx.fillStyle = labelColors.backgroundColor;8956ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), bodyFontSize - 2), pt.y + 1, bodyFontSize - 2, bodyFontSize - 2);8957ctx.fillStyle = textColor;8958}89598960fillLineOfText(lines[j]);8961}89628963helpers$1.each(bodyItem.after, fillLineOfText);8964}89658966// Reset back to 0 for after body8967xLinePadding = 0;89688969// After body lines8970helpers$1.each(vm.afterBody, fillLineOfText);8971pt.y -= bodySpacing; // Remove last body spacing8972},89738974drawFooter: function(pt, vm, ctx) {8975var footer = vm.footer;8976var length = footer.length;8977var footerFontSize, i;89788979if (length) {8980var rtlHelper = getRtlHelper(vm.rtl, vm.x, vm.width);89818982pt.x = getAlignedX(vm, vm._footerAlign);8983pt.y += vm.footerMarginTop;89848985ctx.textAlign = rtlHelper.textAlign(vm._footerAlign);8986ctx.textBaseline = 'middle';89878988footerFontSize = vm.footerFontSize;89898990ctx.fillStyle = vm.footerFontColor;8991ctx.font = helpers$1.fontString(footerFontSize, vm._footerFontStyle, vm._footerFontFamily);89928993for (i = 0; i < length; ++i) {8994ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFontSize / 2);8995pt.y += footerFontSize + vm.footerSpacing;8996}8997}8998},89999000drawBackground: function(pt, vm, ctx, tooltipSize) {9001ctx.fillStyle = vm.backgroundColor;9002ctx.strokeStyle = vm.borderColor;9003ctx.lineWidth = vm.borderWidth;9004var xAlign = vm.xAlign;9005var yAlign = vm.yAlign;9006var x = pt.x;9007var y = pt.y;9008var width = tooltipSize.width;9009var height = tooltipSize.height;9010var radius = vm.cornerRadius;90119012ctx.beginPath();9013ctx.moveTo(x + radius, y);9014if (yAlign === 'top') {9015this.drawCaret(pt, tooltipSize);9016}9017ctx.lineTo(x + width - radius, y);9018ctx.quadraticCurveTo(x + width, y, x + width, y + radius);9019if (yAlign === 'center' && xAlign === 'right') {9020this.drawCaret(pt, tooltipSize);9021}9022ctx.lineTo(x + width, y + height - radius);9023ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);9024if (yAlign === 'bottom') {9025this.drawCaret(pt, tooltipSize);9026}9027ctx.lineTo(x + radius, y + height);9028ctx.quadraticCurveTo(x, y + height, x, y + height - radius);9029if (yAlign === 'center' && xAlign === 'left') {9030this.drawCaret(pt, tooltipSize);9031}9032ctx.lineTo(x, y + radius);9033ctx.quadraticCurveTo(x, y, x + radius, y);9034ctx.closePath();90359036ctx.fill();90379038if (vm.borderWidth > 0) {9039ctx.stroke();9040}9041},90429043draw: function() {9044var ctx = this._chart.ctx;9045var vm = this._view;90469047if (vm.opacity === 0) {9048return;9049}90509051var tooltipSize = {9052width: vm.width,9053height: vm.height9054};9055var pt = {9056x: vm.x,9057y: vm.y9058};90599060// IE11/Edge does not like very small opacities, so snap to 09061var opacity = Math.abs(vm.opacity < 1e-3) ? 0 : vm.opacity;90629063// Truthy/falsey value for empty tooltip9064var hasTooltipContent = vm.title.length || vm.beforeBody.length || vm.body.length || vm.afterBody.length || vm.footer.length;90659066if (this._options.enabled && hasTooltipContent) {9067ctx.save();9068ctx.globalAlpha = opacity;90699070// Draw Background9071this.drawBackground(pt, vm, ctx, tooltipSize);90729073// Draw Title, Body, and Footer9074pt.y += vm.yPadding;90759076helpers$1.rtl.overrideTextDirection(ctx, vm.textDirection);90779078// Titles9079this.drawTitle(pt, vm, ctx);90809081// Body9082this.drawBody(pt, vm, ctx);90839084// Footer9085this.drawFooter(pt, vm, ctx);90869087helpers$1.rtl.restoreTextDirection(ctx, vm.textDirection);90889089ctx.restore();9090}9091},90929093/**9094* Handle an event9095* @private9096* @param {IEvent} event - The event to handle9097* @returns {boolean} true if the tooltip changed9098*/9099handleEvent: function(e) {9100var me = this;9101var options = me._options;9102var changed = false;91039104me._lastActive = me._lastActive || [];91059106// Find Active Elements for tooltips9107if (e.type === 'mouseout') {9108me._active = [];9109} else {9110me._active = me._chart.getElementsAtEventForMode(e, options.mode, options);9111if (options.reverse) {9112me._active.reverse();9113}9114}91159116// Remember Last Actives9117changed = !helpers$1.arrayEquals(me._active, me._lastActive);91189119// Only handle target event on tooltip change9120if (changed) {9121me._lastActive = me._active;91229123if (options.enabled || options.custom) {9124me._eventPosition = {9125x: e.x,9126y: e.y9127};91289129me.update(true);9130me.pivot();9131}9132}91339134return changed;9135}9136});91379138/**9139* @namespace Chart.Tooltip.positioners9140*/9141var positioners_1 = positioners;91429143var core_tooltip = exports$4;9144core_tooltip.positioners = positioners_1;91459146var valueOrDefault$9 = helpers$1.valueOrDefault;91479148core_defaults._set('global', {9149elements: {},9150events: [9151'mousemove',9152'mouseout',9153'click',9154'touchstart',9155'touchmove'9156],9157hover: {9158onHover: null,9159mode: 'nearest',9160intersect: true,9161animationDuration: 4009162},9163onClick: null,9164maintainAspectRatio: true,9165responsive: true,9166responsiveAnimationDuration: 09167});91689169/**9170* Recursively merge the given config objects representing the `scales` option9171* by incorporating scale defaults in `xAxes` and `yAxes` array items, then9172* returns a deep copy of the result, thus doesn't alter inputs.9173*/9174function mergeScaleConfig(/* config objects ... */) {9175return helpers$1.merge({}, [].slice.call(arguments), {9176merger: function(key, target, source, options) {9177if (key === 'xAxes' || key === 'yAxes') {9178var slen = source[key].length;9179var i, type, scale;91809181if (!target[key]) {9182target[key] = [];9183}91849185for (i = 0; i < slen; ++i) {9186scale = source[key][i];9187type = valueOrDefault$9(scale.type, key === 'xAxes' ? 'category' : 'linear');91889189if (i >= target[key].length) {9190target[key].push({});9191}91929193if (!target[key][i].type || (scale.type && scale.type !== target[key][i].type)) {9194// new/untyped scale or type changed: let's apply the new defaults9195// then merge source scale to correctly overwrite the defaults.9196helpers$1.merge(target[key][i], [core_scaleService.getScaleDefaults(type), scale]);9197} else {9198// scales type are the same9199helpers$1.merge(target[key][i], scale);9200}9201}9202} else {9203helpers$1._merger(key, target, source, options);9204}9205}9206});9207}92089209/**9210* Recursively merge the given config objects as the root options by handling9211* default scale options for the `scales` and `scale` properties, then returns9212* a deep copy of the result, thus doesn't alter inputs.9213*/9214function mergeConfig(/* config objects ... */) {9215return helpers$1.merge({}, [].slice.call(arguments), {9216merger: function(key, target, source, options) {9217var tval = target[key] || {};9218var sval = source[key];92199220if (key === 'scales') {9221// scale config merging is complex. Add our own function here for that9222target[key] = mergeScaleConfig(tval, sval);9223} else if (key === 'scale') {9224// used in polar area & radar charts since there is only one scale9225target[key] = helpers$1.merge(tval, [core_scaleService.getScaleDefaults(sval.type), sval]);9226} else {9227helpers$1._merger(key, target, source, options);9228}9229}9230});9231}92329233function initConfig(config) {9234config = config || {};92359236// Do NOT use mergeConfig for the data object because this method merges arrays9237// and so would change references to labels and datasets, preventing data updates.9238var data = config.data = config.data || {};9239data.datasets = data.datasets || [];9240data.labels = data.labels || [];92419242config.options = mergeConfig(9243core_defaults.global,9244core_defaults[config.type],9245config.options || {});92469247return config;9248}92499250function updateConfig(chart) {9251var newOptions = chart.options;92529253helpers$1.each(chart.scales, function(scale) {9254core_layouts.removeBox(chart, scale);9255});92569257newOptions = mergeConfig(9258core_defaults.global,9259core_defaults[chart.config.type],9260newOptions);92619262chart.options = chart.config.options = newOptions;9263chart.ensureScalesHaveIDs();9264chart.buildOrUpdateScales();92659266// Tooltip9267chart.tooltip._options = newOptions.tooltips;9268chart.tooltip.initialize();9269}92709271function nextAvailableScaleId(axesOpts, prefix, index) {9272var id;9273var hasId = function(obj) {9274return obj.id === id;9275};92769277do {9278id = prefix + index++;9279} while (helpers$1.findIndex(axesOpts, hasId) >= 0);92809281return id;9282}92839284function positionIsHorizontal(position) {9285return position === 'top' || position === 'bottom';9286}92879288function compare2Level(l1, l2) {9289return function(a, b) {9290return a[l1] === b[l1]9291? a[l2] - b[l2]9292: a[l1] - b[l1];9293};9294}92959296var Chart = function(item, config) {9297this.construct(item, config);9298return this;9299};93009301helpers$1.extend(Chart.prototype, /** @lends Chart */ {9302/**9303* @private9304*/9305construct: function(item, config) {9306var me = this;93079308config = initConfig(config);93099310var context = platform.acquireContext(item, config);9311var canvas = context && context.canvas;9312var height = canvas && canvas.height;9313var width = canvas && canvas.width;93149315me.id = helpers$1.uid();9316me.ctx = context;9317me.canvas = canvas;9318me.config = config;9319me.width = width;9320me.height = height;9321me.aspectRatio = height ? width / height : null;9322me.options = config.options;9323me._bufferedRender = false;9324me._layers = [];93259326/**9327* Provided for backward compatibility, Chart and Chart.Controller have been merged,9328* the "instance" still need to be defined since it might be called from plugins.9329* @prop Chart#chart9330* @deprecated since version 2.6.09331* @todo remove at version 39332* @private9333*/9334me.chart = me;9335me.controller = me; // chart.chart.controller #inception93369337// Add the chart instance to the global namespace9338Chart.instances[me.id] = me;93399340// Define alias to the config data: `chart.data === chart.config.data`9341Object.defineProperty(me, 'data', {9342get: function() {9343return me.config.data;9344},9345set: function(value) {9346me.config.data = value;9347}9348});93499350if (!context || !canvas) {9351// The given item is not a compatible context2d element, let's return before finalizing9352// the chart initialization but after setting basic chart / controller properties that9353// can help to figure out that the chart is not valid (e.g chart.canvas !== null);9354// https://github.com/chartjs/Chart.js/issues/28079355console.error("Failed to create chart: can't acquire context from the given item");9356return;9357}93589359me.initialize();9360me.update();9361},93629363/**9364* @private9365*/9366initialize: function() {9367var me = this;93689369// Before init plugin notification9370core_plugins.notify(me, 'beforeInit');93719372helpers$1.retinaScale(me, me.options.devicePixelRatio);93739374me.bindEvents();93759376if (me.options.responsive) {9377// Initial resize before chart draws (must be silent to preserve initial animations).9378me.resize(true);9379}93809381me.initToolTip();93829383// After init plugin notification9384core_plugins.notify(me, 'afterInit');93859386return me;9387},93889389clear: function() {9390helpers$1.canvas.clear(this);9391return this;9392},93939394stop: function() {9395// Stops any current animation loop occurring9396core_animations.cancelAnimation(this);9397return this;9398},93999400resize: function(silent) {9401var me = this;9402var options = me.options;9403var canvas = me.canvas;9404var aspectRatio = (options.maintainAspectRatio && me.aspectRatio) || null;94059406// the canvas render width and height will be casted to integers so make sure that9407// the canvas display style uses the same integer values to avoid blurring effect.94089409// Set to 0 instead of canvas.size because the size defaults to 300x150 if the element is collapsed9410var newWidth = Math.max(0, Math.floor(helpers$1.getMaximumWidth(canvas)));9411var newHeight = Math.max(0, Math.floor(aspectRatio ? newWidth / aspectRatio : helpers$1.getMaximumHeight(canvas)));94129413if (me.width === newWidth && me.height === newHeight) {9414return;9415}94169417canvas.width = me.width = newWidth;9418canvas.height = me.height = newHeight;9419canvas.style.width = newWidth + 'px';9420canvas.style.height = newHeight + 'px';94219422helpers$1.retinaScale(me, options.devicePixelRatio);94239424if (!silent) {9425// Notify any plugins about the resize9426var newSize = {width: newWidth, height: newHeight};9427core_plugins.notify(me, 'resize', [newSize]);94289429// Notify of resize9430if (options.onResize) {9431options.onResize(me, newSize);9432}94339434me.stop();9435me.update({9436duration: options.responsiveAnimationDuration9437});9438}9439},94409441ensureScalesHaveIDs: function() {9442var options = this.options;9443var scalesOptions = options.scales || {};9444var scaleOptions = options.scale;94459446helpers$1.each(scalesOptions.xAxes, function(xAxisOptions, index) {9447if (!xAxisOptions.id) {9448xAxisOptions.id = nextAvailableScaleId(scalesOptions.xAxes, 'x-axis-', index);9449}9450});94519452helpers$1.each(scalesOptions.yAxes, function(yAxisOptions, index) {9453if (!yAxisOptions.id) {9454yAxisOptions.id = nextAvailableScaleId(scalesOptions.yAxes, 'y-axis-', index);9455}9456});94579458if (scaleOptions) {9459scaleOptions.id = scaleOptions.id || 'scale';9460}9461},94629463/**9464* Builds a map of scale ID to scale object for future lookup.9465*/9466buildOrUpdateScales: function() {9467var me = this;9468var options = me.options;9469var scales = me.scales || {};9470var items = [];9471var updated = Object.keys(scales).reduce(function(obj, id) {9472obj[id] = false;9473return obj;9474}, {});94759476if (options.scales) {9477items = items.concat(9478(options.scales.xAxes || []).map(function(xAxisOptions) {9479return {options: xAxisOptions, dtype: 'category', dposition: 'bottom'};9480}),9481(options.scales.yAxes || []).map(function(yAxisOptions) {9482return {options: yAxisOptions, dtype: 'linear', dposition: 'left'};9483})9484);9485}94869487if (options.scale) {9488items.push({9489options: options.scale,9490dtype: 'radialLinear',9491isDefault: true,9492dposition: 'chartArea'9493});9494}94959496helpers$1.each(items, function(item) {9497var scaleOptions = item.options;9498var id = scaleOptions.id;9499var scaleType = valueOrDefault$9(scaleOptions.type, item.dtype);95009501if (positionIsHorizontal(scaleOptions.position) !== positionIsHorizontal(item.dposition)) {9502scaleOptions.position = item.dposition;9503}95049505updated[id] = true;9506var scale = null;9507if (id in scales && scales[id].type === scaleType) {9508scale = scales[id];9509scale.options = scaleOptions;9510scale.ctx = me.ctx;9511scale.chart = me;9512} else {9513var scaleClass = core_scaleService.getScaleConstructor(scaleType);9514if (!scaleClass) {9515return;9516}9517scale = new scaleClass({9518id: id,9519type: scaleType,9520options: scaleOptions,9521ctx: me.ctx,9522chart: me9523});9524scales[scale.id] = scale;9525}95269527scale.mergeTicksOptions();95289529// TODO(SB): I think we should be able to remove this custom case (options.scale)9530// and consider it as a regular scale part of the "scales"" map only! This would9531// make the logic easier and remove some useless? custom code.9532if (item.isDefault) {9533me.scale = scale;9534}9535});9536// clear up discarded scales9537helpers$1.each(updated, function(hasUpdated, id) {9538if (!hasUpdated) {9539delete scales[id];9540}9541});95429543me.scales = scales;95449545core_scaleService.addScalesToLayout(this);9546},95479548buildOrUpdateControllers: function() {9549var me = this;9550var newControllers = [];9551var datasets = me.data.datasets;9552var i, ilen;95539554for (i = 0, ilen = datasets.length; i < ilen; i++) {9555var dataset = datasets[i];9556var meta = me.getDatasetMeta(i);9557var type = dataset.type || me.config.type;95589559if (meta.type && meta.type !== type) {9560me.destroyDatasetMeta(i);9561meta = me.getDatasetMeta(i);9562}9563meta.type = type;9564meta.order = dataset.order || 0;9565meta.index = i;95669567if (meta.controller) {9568meta.controller.updateIndex(i);9569meta.controller.linkScales();9570} else {9571var ControllerClass = controllers[meta.type];9572if (ControllerClass === undefined) {9573throw new Error('"' + meta.type + '" is not a chart type.');9574}95759576meta.controller = new ControllerClass(me, i);9577newControllers.push(meta.controller);9578}9579}95809581return newControllers;9582},95839584/**9585* Reset the elements of all datasets9586* @private9587*/9588resetElements: function() {9589var me = this;9590helpers$1.each(me.data.datasets, function(dataset, datasetIndex) {9591me.getDatasetMeta(datasetIndex).controller.reset();9592}, me);9593},95949595/**9596* Resets the chart back to it's state before the initial animation9597*/9598reset: function() {9599this.resetElements();9600this.tooltip.initialize();9601},96029603update: function(config) {9604var me = this;9605var i, ilen;96069607if (!config || typeof config !== 'object') {9608// backwards compatibility9609config = {9610duration: config,9611lazy: arguments[1]9612};9613}96149615updateConfig(me);96169617// plugins options references might have change, let's invalidate the cache9618// https://github.com/chartjs/Chart.js/issues/5111#issuecomment-3559341679619core_plugins._invalidate(me);96209621if (core_plugins.notify(me, 'beforeUpdate') === false) {9622return;9623}96249625// In case the entire data object changed9626me.tooltip._data = me.data;96279628// Make sure dataset controllers are updated and new controllers are reset9629var newControllers = me.buildOrUpdateControllers();96309631// Make sure all dataset controllers have correct meta data counts9632for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) {9633me.getDatasetMeta(i).controller.buildOrUpdateElements();9634}96359636me.updateLayout();96379638// Can only reset the new controllers after the scales have been updated9639if (me.options.animation && me.options.animation.duration) {9640helpers$1.each(newControllers, function(controller) {9641controller.reset();9642});9643}96449645me.updateDatasets();96469647// Need to reset tooltip in case it is displayed with elements that are removed9648// after update.9649me.tooltip.initialize();96509651// Last active contains items that were previously in the tooltip.9652// When we reset the tooltip, we need to clear it9653me.lastActive = [];96549655// Do this before render so that any plugins that need final scale updates can use it9656core_plugins.notify(me, 'afterUpdate');96579658me._layers.sort(compare2Level('z', '_idx'));96599660if (me._bufferedRender) {9661me._bufferedRequest = {9662duration: config.duration,9663easing: config.easing,9664lazy: config.lazy9665};9666} else {9667me.render(config);9668}9669},96709671/**9672* Updates the chart layout unless a plugin returns `false` to the `beforeLayout`9673* hook, in which case, plugins will not be called on `afterLayout`.9674* @private9675*/9676updateLayout: function() {9677var me = this;96789679if (core_plugins.notify(me, 'beforeLayout') === false) {9680return;9681}96829683core_layouts.update(this, this.width, this.height);96849685me._layers = [];9686helpers$1.each(me.boxes, function(box) {9687// _configure is called twice, once in core.scale.update and once here.9688// Here the boxes are fully updated and at their final positions.9689if (box._configure) {9690box._configure();9691}9692me._layers.push.apply(me._layers, box._layers());9693}, me);96949695me._layers.forEach(function(item, index) {9696item._idx = index;9697});96989699/**9700* Provided for backward compatibility, use `afterLayout` instead.9701* @method IPlugin#afterScaleUpdate9702* @deprecated since version 2.5.09703* @todo remove at version 39704* @private9705*/9706core_plugins.notify(me, 'afterScaleUpdate');9707core_plugins.notify(me, 'afterLayout');9708},97099710/**9711* Updates all datasets unless a plugin returns `false` to the `beforeDatasetsUpdate`9712* hook, in which case, plugins will not be called on `afterDatasetsUpdate`.9713* @private9714*/9715updateDatasets: function() {9716var me = this;97179718if (core_plugins.notify(me, 'beforeDatasetsUpdate') === false) {9719return;9720}97219722for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {9723me.updateDataset(i);9724}97259726core_plugins.notify(me, 'afterDatasetsUpdate');9727},97289729/**9730* Updates dataset at index unless a plugin returns `false` to the `beforeDatasetUpdate`9731* hook, in which case, plugins will not be called on `afterDatasetUpdate`.9732* @private9733*/9734updateDataset: function(index) {9735var me = this;9736var meta = me.getDatasetMeta(index);9737var args = {9738meta: meta,9739index: index9740};97419742if (core_plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) {9743return;9744}97459746meta.controller._update();97479748core_plugins.notify(me, 'afterDatasetUpdate', [args]);9749},97509751render: function(config) {9752var me = this;97539754if (!config || typeof config !== 'object') {9755// backwards compatibility9756config = {9757duration: config,9758lazy: arguments[1]9759};9760}97619762var animationOptions = me.options.animation;9763var duration = valueOrDefault$9(config.duration, animationOptions && animationOptions.duration);9764var lazy = config.lazy;97659766if (core_plugins.notify(me, 'beforeRender') === false) {9767return;9768}97699770var onComplete = function(animation) {9771core_plugins.notify(me, 'afterRender');9772helpers$1.callback(animationOptions && animationOptions.onComplete, [animation], me);9773};97749775if (animationOptions && duration) {9776var animation = new core_animation({9777numSteps: duration / 16.66, // 60 fps9778easing: config.easing || animationOptions.easing,97799780render: function(chart, animationObject) {9781var easingFunction = helpers$1.easing.effects[animationObject.easing];9782var currentStep = animationObject.currentStep;9783var stepDecimal = currentStep / animationObject.numSteps;97849785chart.draw(easingFunction(stepDecimal), stepDecimal, currentStep);9786},97879788onAnimationProgress: animationOptions.onProgress,9789onAnimationComplete: onComplete9790});97919792core_animations.addAnimation(me, animation, duration, lazy);9793} else {9794me.draw();97959796// See https://github.com/chartjs/Chart.js/issues/37819797onComplete(new core_animation({numSteps: 0, chart: me}));9798}97999800return me;9801},98029803draw: function(easingValue) {9804var me = this;9805var i, layers;98069807me.clear();98089809if (helpers$1.isNullOrUndef(easingValue)) {9810easingValue = 1;9811}98129813me.transition(easingValue);98149815if (me.width <= 0 || me.height <= 0) {9816return;9817}98189819if (core_plugins.notify(me, 'beforeDraw', [easingValue]) === false) {9820return;9821}98229823// Because of plugin hooks (before/afterDatasetsDraw), datasets can't9824// currently be part of layers. Instead, we draw9825// layers <= 0 before(default, backward compat), and the rest after9826layers = me._layers;9827for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {9828layers[i].draw(me.chartArea);9829}98309831me.drawDatasets(easingValue);98329833// Rest of layers9834for (; i < layers.length; ++i) {9835layers[i].draw(me.chartArea);9836}98379838me._drawTooltip(easingValue);98399840core_plugins.notify(me, 'afterDraw', [easingValue]);9841},98429843/**9844* @private9845*/9846transition: function(easingValue) {9847var me = this;98489849for (var i = 0, ilen = (me.data.datasets || []).length; i < ilen; ++i) {9850if (me.isDatasetVisible(i)) {9851me.getDatasetMeta(i).controller.transition(easingValue);9852}9853}98549855me.tooltip.transition(easingValue);9856},98579858/**9859* @private9860*/9861_getSortedDatasetMetas: function(filterVisible) {9862var me = this;9863var datasets = me.data.datasets || [];9864var result = [];9865var i, ilen;98669867for (i = 0, ilen = datasets.length; i < ilen; ++i) {9868if (!filterVisible || me.isDatasetVisible(i)) {9869result.push(me.getDatasetMeta(i));9870}9871}98729873result.sort(compare2Level('order', 'index'));98749875return result;9876},98779878/**9879* @private9880*/9881_getSortedVisibleDatasetMetas: function() {9882return this._getSortedDatasetMetas(true);9883},98849885/**9886* Draws all datasets unless a plugin returns `false` to the `beforeDatasetsDraw`9887* hook, in which case, plugins will not be called on `afterDatasetsDraw`.9888* @private9889*/9890drawDatasets: function(easingValue) {9891var me = this;9892var metasets, i;98939894if (core_plugins.notify(me, 'beforeDatasetsDraw', [easingValue]) === false) {9895return;9896}98979898metasets = me._getSortedVisibleDatasetMetas();9899for (i = metasets.length - 1; i >= 0; --i) {9900me.drawDataset(metasets[i], easingValue);9901}99029903core_plugins.notify(me, 'afterDatasetsDraw', [easingValue]);9904},99059906/**9907* Draws dataset at index unless a plugin returns `false` to the `beforeDatasetDraw`9908* hook, in which case, plugins will not be called on `afterDatasetDraw`.9909* @private9910*/9911drawDataset: function(meta, easingValue) {9912var me = this;9913var args = {9914meta: meta,9915index: meta.index,9916easingValue: easingValue9917};99189919if (core_plugins.notify(me, 'beforeDatasetDraw', [args]) === false) {9920return;9921}99229923meta.controller.draw(easingValue);99249925core_plugins.notify(me, 'afterDatasetDraw', [args]);9926},99279928/**9929* Draws tooltip unless a plugin returns `false` to the `beforeTooltipDraw`9930* hook, in which case, plugins will not be called on `afterTooltipDraw`.9931* @private9932*/9933_drawTooltip: function(easingValue) {9934var me = this;9935var tooltip = me.tooltip;9936var args = {9937tooltip: tooltip,9938easingValue: easingValue9939};99409941if (core_plugins.notify(me, 'beforeTooltipDraw', [args]) === false) {9942return;9943}99449945tooltip.draw();99469947core_plugins.notify(me, 'afterTooltipDraw', [args]);9948},99499950/**9951* Get the single element that was clicked on9952* @return An object containing the dataset index and element index of the matching element. Also contains the rectangle that was draw9953*/9954getElementAtEvent: function(e) {9955return core_interaction.modes.single(this, e);9956},99579958getElementsAtEvent: function(e) {9959return core_interaction.modes.label(this, e, {intersect: true});9960},99619962getElementsAtXAxis: function(e) {9963return core_interaction.modes['x-axis'](this, e, {intersect: true});9964},99659966getElementsAtEventForMode: function(e, mode, options) {9967var method = core_interaction.modes[mode];9968if (typeof method === 'function') {9969return method(this, e, options);9970}99719972return [];9973},99749975getDatasetAtEvent: function(e) {9976return core_interaction.modes.dataset(this, e, {intersect: true});9977},99789979getDatasetMeta: function(datasetIndex) {9980var me = this;9981var dataset = me.data.datasets[datasetIndex];9982if (!dataset._meta) {9983dataset._meta = {};9984}99859986var meta = dataset._meta[me.id];9987if (!meta) {9988meta = dataset._meta[me.id] = {9989type: null,9990data: [],9991dataset: null,9992controller: null,9993hidden: null, // See isDatasetVisible() comment9994xAxisID: null,9995yAxisID: null,9996order: dataset.order || 0,9997index: datasetIndex9998};9999}1000010001return meta;10002},1000310004getVisibleDatasetCount: function() {10005var count = 0;10006for (var i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {10007if (this.isDatasetVisible(i)) {10008count++;10009}10010}10011return count;10012},1001310014isDatasetVisible: function(datasetIndex) {10015var meta = this.getDatasetMeta(datasetIndex);1001610017// meta.hidden is a per chart dataset hidden flag override with 3 states: if true or false,10018// the dataset.hidden value is ignored, else if null, the dataset hidden state is returned.10019return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden;10020},1002110022generateLegend: function() {10023return this.options.legendCallback(this);10024},1002510026/**10027* @private10028*/10029destroyDatasetMeta: function(datasetIndex) {10030var id = this.id;10031var dataset = this.data.datasets[datasetIndex];10032var meta = dataset._meta && dataset._meta[id];1003310034if (meta) {10035meta.controller.destroy();10036delete dataset._meta[id];10037}10038},1003910040destroy: function() {10041var me = this;10042var canvas = me.canvas;10043var i, ilen;1004410045me.stop();1004610047// dataset controllers need to cleanup associated data10048for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) {10049me.destroyDatasetMeta(i);10050}1005110052if (canvas) {10053me.unbindEvents();10054helpers$1.canvas.clear(me);10055platform.releaseContext(me.ctx);10056me.canvas = null;10057me.ctx = null;10058}1005910060core_plugins.notify(me, 'destroy');1006110062delete Chart.instances[me.id];10063},1006410065toBase64Image: function() {10066return this.canvas.toDataURL.apply(this.canvas, arguments);10067},1006810069initToolTip: function() {10070var me = this;10071me.tooltip = new core_tooltip({10072_chart: me,10073_chartInstance: me, // deprecated, backward compatibility10074_data: me.data,10075_options: me.options.tooltips10076}, me);10077},1007810079/**10080* @private10081*/10082bindEvents: function() {10083var me = this;10084var listeners = me._listeners = {};10085var listener = function() {10086me.eventHandler.apply(me, arguments);10087};1008810089helpers$1.each(me.options.events, function(type) {10090platform.addEventListener(me, type, listener);10091listeners[type] = listener;10092});1009310094// Elements used to detect size change should not be injected for non responsive charts.10095// See https://github.com/chartjs/Chart.js/issues/221010096if (me.options.responsive) {10097listener = function() {10098me.resize();10099};1010010101platform.addEventListener(me, 'resize', listener);10102listeners.resize = listener;10103}10104},1010510106/**10107* @private10108*/10109unbindEvents: function() {10110var me = this;10111var listeners = me._listeners;10112if (!listeners) {10113return;10114}1011510116delete me._listeners;10117helpers$1.each(listeners, function(listener, type) {10118platform.removeEventListener(me, type, listener);10119});10120},1012110122updateHoverStyle: function(elements, mode, enabled) {10123var prefix = enabled ? 'set' : 'remove';10124var element, i, ilen;1012510126for (i = 0, ilen = elements.length; i < ilen; ++i) {10127element = elements[i];10128if (element) {10129this.getDatasetMeta(element._datasetIndex).controller[prefix + 'HoverStyle'](element);10130}10131}1013210133if (mode === 'dataset') {10134this.getDatasetMeta(elements[0]._datasetIndex).controller['_' + prefix + 'DatasetHoverStyle']();10135}10136},1013710138/**10139* @private10140*/10141eventHandler: function(e) {10142var me = this;10143var tooltip = me.tooltip;1014410145if (core_plugins.notify(me, 'beforeEvent', [e]) === false) {10146return;10147}1014810149// Buffer any update calls so that renders do not occur10150me._bufferedRender = true;10151me._bufferedRequest = null;1015210153var changed = me.handleEvent(e);10154// for smooth tooltip animations issue #498910155// the tooltip should be the source of change10156// Animation check workaround:10157// tooltip._start will be null when tooltip isn't animating10158if (tooltip) {10159changed = tooltip._start10160? tooltip.handleEvent(e)10161: changed | tooltip.handleEvent(e);10162}1016310164core_plugins.notify(me, 'afterEvent', [e]);1016510166var bufferedRequest = me._bufferedRequest;10167if (bufferedRequest) {10168// If we have an update that was triggered, we need to do a normal render10169me.render(bufferedRequest);10170} else if (changed && !me.animating) {10171// If entering, leaving, or changing elements, animate the change via pivot10172me.stop();1017310174// We only need to render at this point. Updating will cause scales to be10175// recomputed generating flicker & using more memory than necessary.10176me.render({10177duration: me.options.hover.animationDuration,10178lazy: true10179});10180}1018110182me._bufferedRender = false;10183me._bufferedRequest = null;1018410185return me;10186},1018710188/**10189* Handle an event10190* @private10191* @param {IEvent} event the event to handle10192* @return {boolean} true if the chart needs to re-render10193*/10194handleEvent: function(e) {10195var me = this;10196var options = me.options || {};10197var hoverOptions = options.hover;10198var changed = false;1019910200me.lastActive = me.lastActive || [];1020110202// Find Active Elements for hover and tooltips10203if (e.type === 'mouseout') {10204me.active = [];10205} else {10206me.active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions);10207}1020810209// Invoke onHover hook10210// Need to call with native event here to not break backwards compatibility10211helpers$1.callback(options.onHover || options.hover.onHover, [e.native, me.active], me);1021210213if (e.type === 'mouseup' || e.type === 'click') {10214if (options.onClick) {10215// Use e.native here for backwards compatibility10216options.onClick.call(me, e.native, me.active);10217}10218}1021910220// Remove styling for last active (even if it may still be active)10221if (me.lastActive.length) {10222me.updateHoverStyle(me.lastActive, hoverOptions.mode, false);10223}1022410225// Built in hover styling10226if (me.active.length && hoverOptions.mode) {10227me.updateHoverStyle(me.active, hoverOptions.mode, true);10228}1022910230changed = !helpers$1.arrayEquals(me.active, me.lastActive);1023110232// Remember Last Actives10233me.lastActive = me.active;1023410235return changed;10236}10237});1023810239/**10240* NOTE(SB) We actually don't use this container anymore but we need to keep it10241* for backward compatibility. Though, it can still be useful for plugins that10242* would need to work on multiple charts?!10243*/10244Chart.instances = {};1024510246var core_controller = Chart;1024710248// DEPRECATIONS1024910250/**10251* Provided for backward compatibility, use Chart instead.10252* @class Chart.Controller10253* @deprecated since version 2.610254* @todo remove at version 310255* @private10256*/10257Chart.Controller = Chart;1025810259/**10260* Provided for backward compatibility, not available anymore.10261* @namespace Chart10262* @deprecated since version 2.810263* @todo remove at version 310264* @private10265*/10266Chart.types = {};1026710268/**10269* Provided for backward compatibility, not available anymore.10270* @namespace Chart.helpers.configMerge10271* @deprecated since version 2.8.010272* @todo remove at version 310273* @private10274*/10275helpers$1.configMerge = mergeConfig;1027610277/**10278* Provided for backward compatibility, not available anymore.10279* @namespace Chart.helpers.scaleMerge10280* @deprecated since version 2.8.010281* @todo remove at version 310282* @private10283*/10284helpers$1.scaleMerge = mergeScaleConfig;1028510286var core_helpers = function() {1028710288// -- Basic js utility methods1028910290helpers$1.where = function(collection, filterCallback) {10291if (helpers$1.isArray(collection) && Array.prototype.filter) {10292return collection.filter(filterCallback);10293}10294var filtered = [];1029510296helpers$1.each(collection, function(item) {10297if (filterCallback(item)) {10298filtered.push(item);10299}10300});1030110302return filtered;10303};10304helpers$1.findIndex = Array.prototype.findIndex ?10305function(array, callback, scope) {10306return array.findIndex(callback, scope);10307} :10308function(array, callback, scope) {10309scope = scope === undefined ? array : scope;10310for (var i = 0, ilen = array.length; i < ilen; ++i) {10311if (callback.call(scope, array[i], i, array)) {10312return i;10313}10314}10315return -1;10316};10317helpers$1.findNextWhere = function(arrayToSearch, filterCallback, startIndex) {10318// Default to start of the array10319if (helpers$1.isNullOrUndef(startIndex)) {10320startIndex = -1;10321}10322for (var i = startIndex + 1; i < arrayToSearch.length; i++) {10323var currentItem = arrayToSearch[i];10324if (filterCallback(currentItem)) {10325return currentItem;10326}10327}10328};10329helpers$1.findPreviousWhere = function(arrayToSearch, filterCallback, startIndex) {10330// Default to end of the array10331if (helpers$1.isNullOrUndef(startIndex)) {10332startIndex = arrayToSearch.length;10333}10334for (var i = startIndex - 1; i >= 0; i--) {10335var currentItem = arrayToSearch[i];10336if (filterCallback(currentItem)) {10337return currentItem;10338}10339}10340};1034110342// -- Math methods10343helpers$1.isNumber = function(n) {10344return !isNaN(parseFloat(n)) && isFinite(n);10345};10346helpers$1.almostEquals = function(x, y, epsilon) {10347return Math.abs(x - y) < epsilon;10348};10349helpers$1.almostWhole = function(x, epsilon) {10350var rounded = Math.round(x);10351return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);10352};10353helpers$1.max = function(array) {10354return array.reduce(function(max, value) {10355if (!isNaN(value)) {10356return Math.max(max, value);10357}10358return max;10359}, Number.NEGATIVE_INFINITY);10360};10361helpers$1.min = function(array) {10362return array.reduce(function(min, value) {10363if (!isNaN(value)) {10364return Math.min(min, value);10365}10366return min;10367}, Number.POSITIVE_INFINITY);10368};10369helpers$1.sign = Math.sign ?10370function(x) {10371return Math.sign(x);10372} :10373function(x) {10374x = +x; // convert to a number10375if (x === 0 || isNaN(x)) {10376return x;10377}10378return x > 0 ? 1 : -1;10379};10380helpers$1.toRadians = function(degrees) {10381return degrees * (Math.PI / 180);10382};10383helpers$1.toDegrees = function(radians) {10384return radians * (180 / Math.PI);10385};1038610387/**10388* Returns the number of decimal places10389* i.e. the number of digits after the decimal point, of the value of this Number.10390* @param {number} x - A number.10391* @returns {number} The number of decimal places.10392* @private10393*/10394helpers$1._decimalPlaces = function(x) {10395if (!helpers$1.isFinite(x)) {10396return;10397}10398var e = 1;10399var p = 0;10400while (Math.round(x * e) / e !== x) {10401e *= 10;10402p++;10403}10404return p;10405};1040610407// Gets the angle from vertical upright to the point about a centre.10408helpers$1.getAngleFromPoint = function(centrePoint, anglePoint) {10409var distanceFromXCenter = anglePoint.x - centrePoint.x;10410var distanceFromYCenter = anglePoint.y - centrePoint.y;10411var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);1041210413var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);1041410415if (angle < (-0.5 * Math.PI)) {10416angle += 2.0 * Math.PI; // make sure the returned angle is in the range of (-PI/2, 3PI/2]10417}1041810419return {10420angle: angle,10421distance: radialDistanceFromCenter10422};10423};10424helpers$1.distanceBetweenPoints = function(pt1, pt2) {10425return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));10426};1042710428/**10429* Provided for backward compatibility, not available anymore10430* @function Chart.helpers.aliasPixel10431* @deprecated since version 2.8.010432* @todo remove at version 310433*/10434helpers$1.aliasPixel = function(pixelWidth) {10435return (pixelWidth % 2 === 0) ? 0 : 0.5;10436};1043710438/**10439* Returns the aligned pixel value to avoid anti-aliasing blur10440* @param {Chart} chart - The chart instance.10441* @param {number} pixel - A pixel value.10442* @param {number} width - The width of the element.10443* @returns {number} The aligned pixel value.10444* @private10445*/10446helpers$1._alignPixel = function(chart, pixel, width) {10447var devicePixelRatio = chart.currentDevicePixelRatio;10448var halfWidth = width / 2;10449return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;10450};1045110452helpers$1.splineCurve = function(firstPoint, middlePoint, afterPoint, t) {10453// Props to Rob Spencer at scaled innovation for his post on splining between points10454// http://scaledinnovation.com/analytics/splines/aboutSplines.html1045510456// This function must also respect "skipped" points1045710458var previous = firstPoint.skip ? middlePoint : firstPoint;10459var current = middlePoint;10460var next = afterPoint.skip ? middlePoint : afterPoint;1046110462var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2));10463var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2));1046410465var s01 = d01 / (d01 + d12);10466var s12 = d12 / (d01 + d12);1046710468// If all points are the same, s01 & s02 will be inf10469s01 = isNaN(s01) ? 0 : s01;10470s12 = isNaN(s12) ? 0 : s12;1047110472var fa = t * s01; // scaling factor for triangle Ta10473var fb = t * s12;1047410475return {10476previous: {10477x: current.x - fa * (next.x - previous.x),10478y: current.y - fa * (next.y - previous.y)10479},10480next: {10481x: current.x + fb * (next.x - previous.x),10482y: current.y + fb * (next.y - previous.y)10483}10484};10485};10486helpers$1.EPSILON = Number.EPSILON || 1e-14;10487helpers$1.splineCurveMonotone = function(points) {10488// This function calculates Bézier control points in a similar way than |splineCurve|,10489// but preserves monotonicity of the provided data and ensures no local extremums are added10490// between the dataset discrete points due to the interpolation.10491// See : https://en.wikipedia.org/wiki/Monotone_cubic_interpolation1049210493var pointsWithTangents = (points || []).map(function(point) {10494return {10495model: point._model,10496deltaK: 0,10497mK: 010498};10499});1050010501// Calculate slopes (deltaK) and initialize tangents (mK)10502var pointsLen = pointsWithTangents.length;10503var i, pointBefore, pointCurrent, pointAfter;10504for (i = 0; i < pointsLen; ++i) {10505pointCurrent = pointsWithTangents[i];10506if (pointCurrent.model.skip) {10507continue;10508}1050910510pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;10511pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;10512if (pointAfter && !pointAfter.model.skip) {10513var slopeDeltaX = (pointAfter.model.x - pointCurrent.model.x);1051410515// In the case of two points that appear at the same x pixel, slopeDeltaX is 010516pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0;10517}1051810519if (!pointBefore || pointBefore.model.skip) {10520pointCurrent.mK = pointCurrent.deltaK;10521} else if (!pointAfter || pointAfter.model.skip) {10522pointCurrent.mK = pointBefore.deltaK;10523} else if (this.sign(pointBefore.deltaK) !== this.sign(pointCurrent.deltaK)) {10524pointCurrent.mK = 0;10525} else {10526pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2;10527}10528}1052910530// Adjust tangents to ensure monotonic properties10531var alphaK, betaK, tauK, squaredMagnitude;10532for (i = 0; i < pointsLen - 1; ++i) {10533pointCurrent = pointsWithTangents[i];10534pointAfter = pointsWithTangents[i + 1];10535if (pointCurrent.model.skip || pointAfter.model.skip) {10536continue;10537}1053810539if (helpers$1.almostEquals(pointCurrent.deltaK, 0, this.EPSILON)) {10540pointCurrent.mK = pointAfter.mK = 0;10541continue;10542}1054310544alphaK = pointCurrent.mK / pointCurrent.deltaK;10545betaK = pointAfter.mK / pointCurrent.deltaK;10546squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);10547if (squaredMagnitude <= 9) {10548continue;10549}1055010551tauK = 3 / Math.sqrt(squaredMagnitude);10552pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK;10553pointAfter.mK = betaK * tauK * pointCurrent.deltaK;10554}1055510556// Compute control points10557var deltaX;10558for (i = 0; i < pointsLen; ++i) {10559pointCurrent = pointsWithTangents[i];10560if (pointCurrent.model.skip) {10561continue;10562}1056310564pointBefore = i > 0 ? pointsWithTangents[i - 1] : null;10565pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null;10566if (pointBefore && !pointBefore.model.skip) {10567deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3;10568pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX;10569pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK;10570}10571if (pointAfter && !pointAfter.model.skip) {10572deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3;10573pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX;10574pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK;10575}10576}10577};10578helpers$1.nextItem = function(collection, index, loop) {10579if (loop) {10580return index >= collection.length - 1 ? collection[0] : collection[index + 1];10581}10582return index >= collection.length - 1 ? collection[collection.length - 1] : collection[index + 1];10583};10584helpers$1.previousItem = function(collection, index, loop) {10585if (loop) {10586return index <= 0 ? collection[collection.length - 1] : collection[index - 1];10587}10588return index <= 0 ? collection[0] : collection[index - 1];10589};10590// Implementation of the nice number algorithm used in determining where axis labels will go10591helpers$1.niceNum = function(range, round) {10592var exponent = Math.floor(helpers$1.log10(range));10593var fraction = range / Math.pow(10, exponent);10594var niceFraction;1059510596if (round) {10597if (fraction < 1.5) {10598niceFraction = 1;10599} else if (fraction < 3) {10600niceFraction = 2;10601} else if (fraction < 7) {10602niceFraction = 5;10603} else {10604niceFraction = 10;10605}10606} else if (fraction <= 1.0) {10607niceFraction = 1;10608} else if (fraction <= 2) {10609niceFraction = 2;10610} else if (fraction <= 5) {10611niceFraction = 5;10612} else {10613niceFraction = 10;10614}1061510616return niceFraction * Math.pow(10, exponent);10617};10618// Request animation polyfill - https://www.paulirish.com/2011/requestanimationframe-for-smart-animating/10619helpers$1.requestAnimFrame = (function() {10620if (typeof window === 'undefined') {10621return function(callback) {10622callback();10623};10624}10625return window.requestAnimationFrame ||10626window.webkitRequestAnimationFrame ||10627window.mozRequestAnimationFrame ||10628window.oRequestAnimationFrame ||10629window.msRequestAnimationFrame ||10630function(callback) {10631return window.setTimeout(callback, 1000 / 60);10632};10633}());10634// -- DOM methods10635helpers$1.getRelativePosition = function(evt, chart) {10636var mouseX, mouseY;10637var e = evt.originalEvent || evt;10638var canvas = evt.target || evt.srcElement;10639var boundingRect = canvas.getBoundingClientRect();1064010641var touches = e.touches;10642if (touches && touches.length > 0) {10643mouseX = touches[0].clientX;10644mouseY = touches[0].clientY;1064510646} else {10647mouseX = e.clientX;10648mouseY = e.clientY;10649}1065010651// Scale mouse coordinates into canvas coordinates10652// by following the pattern laid out by 'jerryj' in the comments of10653// https://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/10654var paddingLeft = parseFloat(helpers$1.getStyle(canvas, 'padding-left'));10655var paddingTop = parseFloat(helpers$1.getStyle(canvas, 'padding-top'));10656var paddingRight = parseFloat(helpers$1.getStyle(canvas, 'padding-right'));10657var paddingBottom = parseFloat(helpers$1.getStyle(canvas, 'padding-bottom'));10658var width = boundingRect.right - boundingRect.left - paddingLeft - paddingRight;10659var height = boundingRect.bottom - boundingRect.top - paddingTop - paddingBottom;1066010661// We divide by the current device pixel ratio, because the canvas is scaled up by that amount in each direction. However10662// the backend model is in unscaled coordinates. Since we are going to deal with our model coordinates, we go back here10663mouseX = Math.round((mouseX - boundingRect.left - paddingLeft) / (width) * canvas.width / chart.currentDevicePixelRatio);10664mouseY = Math.round((mouseY - boundingRect.top - paddingTop) / (height) * canvas.height / chart.currentDevicePixelRatio);1066510666return {10667x: mouseX,10668y: mouseY10669};1067010671};1067210673// Private helper function to convert max-width/max-height values that may be percentages into a number10674function parseMaxStyle(styleValue, node, parentProperty) {10675var valueInPixels;10676if (typeof styleValue === 'string') {10677valueInPixels = parseInt(styleValue, 10);1067810679if (styleValue.indexOf('%') !== -1) {10680// percentage * size in dimension10681valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];10682}10683} else {10684valueInPixels = styleValue;10685}1068610687return valueInPixels;10688}1068910690/**10691* Returns if the given value contains an effective constraint.10692* @private10693*/10694function isConstrainedValue(value) {10695return value !== undefined && value !== null && value !== 'none';10696}1069710698/**10699* Returns the max width or height of the given DOM node in a cross-browser compatible fashion10700* @param {HTMLElement} domNode - the node to check the constraint on10701* @param {string} maxStyle - the style that defines the maximum for the direction we are using ('max-width' / 'max-height')10702* @param {string} percentageProperty - property of parent to use when calculating width as a percentage10703* @see {@link https://www.nathanaeljones.com/blog/2013/reading-max-width-cross-browser}10704*/10705function getConstraintDimension(domNode, maxStyle, percentageProperty) {10706var view = document.defaultView;10707var parentNode = helpers$1._getParentNode(domNode);10708var constrainedNode = view.getComputedStyle(domNode)[maxStyle];10709var constrainedContainer = view.getComputedStyle(parentNode)[maxStyle];10710var hasCNode = isConstrainedValue(constrainedNode);10711var hasCContainer = isConstrainedValue(constrainedContainer);10712var infinity = Number.POSITIVE_INFINITY;1071310714if (hasCNode || hasCContainer) {10715return Math.min(10716hasCNode ? parseMaxStyle(constrainedNode, domNode, percentageProperty) : infinity,10717hasCContainer ? parseMaxStyle(constrainedContainer, parentNode, percentageProperty) : infinity);10718}1071910720return 'none';10721}10722// returns Number or undefined if no constraint10723helpers$1.getConstraintWidth = function(domNode) {10724return getConstraintDimension(domNode, 'max-width', 'clientWidth');10725};10726// returns Number or undefined if no constraint10727helpers$1.getConstraintHeight = function(domNode) {10728return getConstraintDimension(domNode, 'max-height', 'clientHeight');10729};10730/**10731* @private10732*/10733helpers$1._calculatePadding = function(container, padding, parentDimension) {10734padding = helpers$1.getStyle(container, padding);1073510736return padding.indexOf('%') > -1 ? parentDimension * parseInt(padding, 10) / 100 : parseInt(padding, 10);10737};10738/**10739* @private10740*/10741helpers$1._getParentNode = function(domNode) {10742var parent = domNode.parentNode;10743if (parent && parent.toString() === '[object ShadowRoot]') {10744parent = parent.host;10745}10746return parent;10747};10748helpers$1.getMaximumWidth = function(domNode) {10749var container = helpers$1._getParentNode(domNode);10750if (!container) {10751return domNode.clientWidth;10752}1075310754var clientWidth = container.clientWidth;10755var paddingLeft = helpers$1._calculatePadding(container, 'padding-left', clientWidth);10756var paddingRight = helpers$1._calculatePadding(container, 'padding-right', clientWidth);1075710758var w = clientWidth - paddingLeft - paddingRight;10759var cw = helpers$1.getConstraintWidth(domNode);10760return isNaN(cw) ? w : Math.min(w, cw);10761};10762helpers$1.getMaximumHeight = function(domNode) {10763var container = helpers$1._getParentNode(domNode);10764if (!container) {10765return domNode.clientHeight;10766}1076710768var clientHeight = container.clientHeight;10769var paddingTop = helpers$1._calculatePadding(container, 'padding-top', clientHeight);10770var paddingBottom = helpers$1._calculatePadding(container, 'padding-bottom', clientHeight);1077110772var h = clientHeight - paddingTop - paddingBottom;10773var ch = helpers$1.getConstraintHeight(domNode);10774return isNaN(ch) ? h : Math.min(h, ch);10775};10776helpers$1.getStyle = function(el, property) {10777return el.currentStyle ?10778el.currentStyle[property] :10779document.defaultView.getComputedStyle(el, null).getPropertyValue(property);10780};10781helpers$1.retinaScale = function(chart, forceRatio) {10782var pixelRatio = chart.currentDevicePixelRatio = forceRatio || (typeof window !== 'undefined' && window.devicePixelRatio) || 1;10783if (pixelRatio === 1) {10784return;10785}1078610787var canvas = chart.canvas;10788var height = chart.height;10789var width = chart.width;1079010791canvas.height = height * pixelRatio;10792canvas.width = width * pixelRatio;10793chart.ctx.scale(pixelRatio, pixelRatio);1079410795// If no style has been set on the canvas, the render size is used as display size,10796// making the chart visually bigger, so let's enforce it to the "correct" values.10797// See https://github.com/chartjs/Chart.js/issues/357510798if (!canvas.style.height && !canvas.style.width) {10799canvas.style.height = height + 'px';10800canvas.style.width = width + 'px';10801}10802};10803// -- Canvas methods10804helpers$1.fontString = function(pixelSize, fontStyle, fontFamily) {10805return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;10806};10807helpers$1.longestText = function(ctx, font, arrayOfThings, cache) {10808cache = cache || {};10809var data = cache.data = cache.data || {};10810var gc = cache.garbageCollect = cache.garbageCollect || [];1081110812if (cache.font !== font) {10813data = cache.data = {};10814gc = cache.garbageCollect = [];10815cache.font = font;10816}1081710818ctx.font = font;10819var longest = 0;10820var ilen = arrayOfThings.length;10821var i, j, jlen, thing, nestedThing;10822for (i = 0; i < ilen; i++) {10823thing = arrayOfThings[i];1082410825// Undefined strings and arrays should not be measured10826if (thing !== undefined && thing !== null && helpers$1.isArray(thing) !== true) {10827longest = helpers$1.measureText(ctx, data, gc, longest, thing);10828} else if (helpers$1.isArray(thing)) {10829// if it is an array lets measure each element10830// to do maybe simplify this function a bit so we can do this more recursively?10831for (j = 0, jlen = thing.length; j < jlen; j++) {10832nestedThing = thing[j];10833// Undefined strings and arrays should not be measured10834if (nestedThing !== undefined && nestedThing !== null && !helpers$1.isArray(nestedThing)) {10835longest = helpers$1.measureText(ctx, data, gc, longest, nestedThing);10836}10837}10838}10839}1084010841var gcLen = gc.length / 2;10842if (gcLen > arrayOfThings.length) {10843for (i = 0; i < gcLen; i++) {10844delete data[gc[i]];10845}10846gc.splice(0, gcLen);10847}10848return longest;10849};10850helpers$1.measureText = function(ctx, data, gc, longest, string) {10851var textWidth = data[string];10852if (!textWidth) {10853textWidth = data[string] = ctx.measureText(string).width;10854gc.push(string);10855}10856if (textWidth > longest) {10857longest = textWidth;10858}10859return longest;10860};1086110862/**10863* @deprecated10864*/10865helpers$1.numberOfLabelLines = function(arrayOfThings) {10866var numberOfLines = 1;10867helpers$1.each(arrayOfThings, function(thing) {10868if (helpers$1.isArray(thing)) {10869if (thing.length > numberOfLines) {10870numberOfLines = thing.length;10871}10872}10873});10874return numberOfLines;10875};1087610877helpers$1.color = !chartjsColor ?10878function(value) {10879console.error('Color.js not found!');10880return value;10881} :10882function(value) {10883/* global CanvasGradient */10884if (value instanceof CanvasGradient) {10885value = core_defaults.global.defaultColor;10886}1088710888return chartjsColor(value);10889};1089010891helpers$1.getHoverColor = function(colorValue) {10892/* global CanvasPattern */10893return (colorValue instanceof CanvasPattern || colorValue instanceof CanvasGradient) ?10894colorValue :10895helpers$1.color(colorValue).saturate(0.5).darken(0.1).rgbString();10896};10897};1089810899function abstract() {10900throw new Error(10901'This method is not implemented: either no adapter can ' +10902'be found or an incomplete integration was provided.'10903);10904}1090510906/**10907* Date adapter (current used by the time scale)10908* @namespace Chart._adapters._date10909* @memberof Chart._adapters10910* @private10911*/1091210913/**10914* Currently supported unit string values.10915* @typedef {('millisecond'|'second'|'minute'|'hour'|'day'|'week'|'month'|'quarter'|'year')}10916* @memberof Chart._adapters._date10917* @name Unit10918*/1091910920/**10921* @class10922*/10923function DateAdapter(options) {10924this.options = options || {};10925}1092610927helpers$1.extend(DateAdapter.prototype, /** @lends DateAdapter */ {10928/**10929* Returns a map of time formats for the supported formatting units defined10930* in Unit as well as 'datetime' representing a detailed date/time string.10931* @returns {{string: string}}10932*/10933formats: abstract,1093410935/**10936* Parses the given `value` and return the associated timestamp.10937* @param {any} value - the value to parse (usually comes from the data)10938* @param {string} [format] - the expected data format10939* @returns {(number|null)}10940* @function10941*/10942parse: abstract,1094310944/**10945* Returns the formatted date in the specified `format` for a given `timestamp`.10946* @param {number} timestamp - the timestamp to format10947* @param {string} format - the date/time token10948* @return {string}10949* @function10950*/10951format: abstract,1095210953/**10954* Adds the specified `amount` of `unit` to the given `timestamp`.10955* @param {number} timestamp - the input timestamp10956* @param {number} amount - the amount to add10957* @param {Unit} unit - the unit as string10958* @return {number}10959* @function10960*/10961add: abstract,1096210963/**10964* Returns the number of `unit` between the given timestamps.10965* @param {number} max - the input timestamp (reference)10966* @param {number} min - the timestamp to substract10967* @param {Unit} unit - the unit as string10968* @return {number}10969* @function10970*/10971diff: abstract,1097210973/**10974* Returns start of `unit` for the given `timestamp`.10975* @param {number} timestamp - the input timestamp10976* @param {Unit} unit - the unit as string10977* @param {number} [weekday] - the ISO day of the week with 1 being Monday10978* and 7 being Sunday (only needed if param *unit* is `isoWeek`).10979* @function10980*/10981startOf: abstract,1098210983/**10984* Returns end of `unit` for the given `timestamp`.10985* @param {number} timestamp - the input timestamp10986* @param {Unit} unit - the unit as string10987* @function10988*/10989endOf: abstract,1099010991// DEPRECATIONS1099210993/**10994* Provided for backward compatibility for scale.getValueForPixel(),10995* this method should be overridden only by the moment adapter.10996* @deprecated since version 2.8.010997* @todo remove at version 310998* @private10999*/11000_create: function(value) {11001return value;11002}11003});1100411005DateAdapter.override = function(members) {11006helpers$1.extend(DateAdapter.prototype, members);11007};1100811009var _date = DateAdapter;1101011011var core_adapters = {11012_date: _date11013};1101411015/**11016* Namespace to hold static tick generation functions11017* @namespace Chart.Ticks11018*/11019var core_ticks = {11020/**11021* Namespace to hold formatters for different types of ticks11022* @namespace Chart.Ticks.formatters11023*/11024formatters: {11025/**11026* Formatter for value labels11027* @method Chart.Ticks.formatters.values11028* @param value the value to display11029* @return {string|string[]} the label to display11030*/11031values: function(value) {11032return helpers$1.isArray(value) ? value : '' + value;11033},1103411035/**11036* Formatter for linear numeric ticks11037* @method Chart.Ticks.formatters.linear11038* @param tickValue {number} the value to be formatted11039* @param index {number} the position of the tickValue parameter in the ticks array11040* @param ticks {number[]} the list of ticks being converted11041* @return {string} string representation of the tickValue parameter11042*/11043linear: function(tickValue, index, ticks) {11044// If we have lots of ticks, don't use the ones11045var delta = ticks.length > 3 ? ticks[2] - ticks[1] : ticks[1] - ticks[0];1104611047// If we have a number like 2.5 as the delta, figure out how many decimal places we need11048if (Math.abs(delta) > 1) {11049if (tickValue !== Math.floor(tickValue)) {11050// not an integer11051delta = tickValue - Math.floor(tickValue);11052}11053}1105411055var logDelta = helpers$1.log10(Math.abs(delta));11056var tickString = '';1105711058if (tickValue !== 0) {11059var maxTick = Math.max(Math.abs(ticks[0]), Math.abs(ticks[ticks.length - 1]));11060if (maxTick < 1e-4) { // all ticks are small numbers; use scientific notation11061var logTick = helpers$1.log10(Math.abs(tickValue));11062var numExponential = Math.floor(logTick) - Math.floor(logDelta);11063numExponential = Math.max(Math.min(numExponential, 20), 0);11064tickString = tickValue.toExponential(numExponential);11065} else {11066var numDecimal = -1 * Math.floor(logDelta);11067numDecimal = Math.max(Math.min(numDecimal, 20), 0); // toFixed has a max of 20 decimal places11068tickString = tickValue.toFixed(numDecimal);11069}11070} else {11071tickString = '0'; // never show decimal places for 011072}1107311074return tickString;11075},1107611077logarithmic: function(tickValue, index, ticks) {11078var remain = tickValue / (Math.pow(10, Math.floor(helpers$1.log10(tickValue))));1107911080if (tickValue === 0) {11081return '0';11082} else if (remain === 1 || remain === 2 || remain === 5 || index === 0 || index === ticks.length - 1) {11083return tickValue.toExponential();11084}11085return '';11086}11087}11088};1108911090var isArray = helpers$1.isArray;11091var isNullOrUndef = helpers$1.isNullOrUndef;11092var valueOrDefault$a = helpers$1.valueOrDefault;11093var valueAtIndexOrDefault = helpers$1.valueAtIndexOrDefault;1109411095core_defaults._set('scale', {11096display: true,11097position: 'left',11098offset: false,1109911100// grid line settings11101gridLines: {11102display: true,11103color: 'rgba(0,0,0,0.1)',11104lineWidth: 1,11105drawBorder: true,11106drawOnChartArea: true,11107drawTicks: true,11108tickMarkLength: 10,11109zeroLineWidth: 1,11110zeroLineColor: 'rgba(0,0,0,0.25)',11111zeroLineBorderDash: [],11112zeroLineBorderDashOffset: 0.0,11113offsetGridLines: false,11114borderDash: [],11115borderDashOffset: 0.011116},1111711118// scale label11119scaleLabel: {11120// display property11121display: false,1112211123// actual label11124labelString: '',1112511126// top/bottom padding11127padding: {11128top: 4,11129bottom: 411130}11131},1113211133// label settings11134ticks: {11135beginAtZero: false,11136minRotation: 0,11137maxRotation: 50,11138mirror: false,11139padding: 0,11140reverse: false,11141display: true,11142autoSkip: true,11143autoSkipPadding: 0,11144labelOffset: 0,11145// We pass through arrays to be rendered as multiline labels, we convert Others to strings here.11146callback: core_ticks.formatters.values,11147minor: {},11148major: {}11149}11150});1115111152/** Returns a new array containing numItems from arr */11153function sample(arr, numItems) {11154var result = [];11155var increment = arr.length / numItems;11156var i = 0;11157var len = arr.length;1115811159for (; i < len; i += increment) {11160result.push(arr[Math.floor(i)]);11161}11162return result;11163}1116411165function getPixelForGridLine(scale, index, offsetGridLines) {11166var length = scale.getTicks().length;11167var validIndex = Math.min(index, length - 1);11168var lineValue = scale.getPixelForTick(validIndex);11169var start = scale._startPixel;11170var end = scale._endPixel;11171var epsilon = 1e-6; // 1e-6 is margin in pixels for accumulated error.11172var offset;1117311174if (offsetGridLines) {11175if (length === 1) {11176offset = Math.max(lineValue - start, end - lineValue);11177} else if (index === 0) {11178offset = (scale.getPixelForTick(1) - lineValue) / 2;11179} else {11180offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;11181}11182lineValue += validIndex < index ? offset : -offset;1118311184// Return undefined if the pixel is out of the range11185if (lineValue < start - epsilon || lineValue > end + epsilon) {11186return;11187}11188}11189return lineValue;11190}1119111192function garbageCollect(caches, length) {11193helpers$1.each(caches, function(cache) {11194var gc = cache.gc;11195var gcLen = gc.length / 2;11196var i;11197if (gcLen > length) {11198for (i = 0; i < gcLen; ++i) {11199delete cache.data[gc[i]];11200}11201gc.splice(0, gcLen);11202}11203});11204}1120511206/**11207* Returns {width, height, offset} objects for the first, last, widest, highest tick11208* labels where offset indicates the anchor point offset from the top in pixels.11209*/11210function computeLabelSizes(ctx, tickFonts, ticks, caches) {11211var length = ticks.length;11212var widths = [];11213var heights = [];11214var offsets = [];11215var i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel, widest, highest;1121611217for (i = 0; i < length; ++i) {11218label = ticks[i].label;11219tickFont = ticks[i].major ? tickFonts.major : tickFonts.minor;11220ctx.font = fontString = tickFont.string;11221cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};11222lineHeight = tickFont.lineHeight;11223width = height = 0;11224// Undefined labels and arrays should not be measured11225if (!isNullOrUndef(label) && !isArray(label)) {11226width = helpers$1.measureText(ctx, cache.data, cache.gc, width, label);11227height = lineHeight;11228} else if (isArray(label)) {11229// if it is an array let's measure each element11230for (j = 0, jlen = label.length; j < jlen; ++j) {11231nestedLabel = label[j];11232// Undefined labels and arrays should not be measured11233if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {11234width = helpers$1.measureText(ctx, cache.data, cache.gc, width, nestedLabel);11235height += lineHeight;11236}11237}11238}11239widths.push(width);11240heights.push(height);11241offsets.push(lineHeight / 2);11242}11243garbageCollect(caches, length);1124411245widest = widths.indexOf(Math.max.apply(null, widths));11246highest = heights.indexOf(Math.max.apply(null, heights));1124711248function valueAt(idx) {11249return {11250width: widths[idx] || 0,11251height: heights[idx] || 0,11252offset: offsets[idx] || 011253};11254}1125511256return {11257first: valueAt(0),11258last: valueAt(length - 1),11259widest: valueAt(widest),11260highest: valueAt(highest)11261};11262}1126311264function getTickMarkLength(options) {11265return options.drawTicks ? options.tickMarkLength : 0;11266}1126711268function getScaleLabelHeight(options) {11269var font, padding;1127011271if (!options.display) {11272return 0;11273}1127411275font = helpers$1.options._parseFont(options);11276padding = helpers$1.options.toPadding(options.padding);1127711278return font.lineHeight + padding.height;11279}1128011281function parseFontOptions(options, nestedOpts) {11282return helpers$1.extend(helpers$1.options._parseFont({11283fontFamily: valueOrDefault$a(nestedOpts.fontFamily, options.fontFamily),11284fontSize: valueOrDefault$a(nestedOpts.fontSize, options.fontSize),11285fontStyle: valueOrDefault$a(nestedOpts.fontStyle, options.fontStyle),11286lineHeight: valueOrDefault$a(nestedOpts.lineHeight, options.lineHeight)11287}), {11288color: helpers$1.options.resolve([nestedOpts.fontColor, options.fontColor, core_defaults.global.defaultFontColor])11289});11290}1129111292function parseTickFontOptions(options) {11293var minor = parseFontOptions(options, options.minor);11294var major = options.major.enabled ? parseFontOptions(options, options.major) : minor;1129511296return {minor: minor, major: major};11297}1129811299function nonSkipped(ticksToFilter) {11300var filtered = [];11301var item, index, len;11302for (index = 0, len = ticksToFilter.length; index < len; ++index) {11303item = ticksToFilter[index];11304if (typeof item._index !== 'undefined') {11305filtered.push(item);11306}11307}11308return filtered;11309}1131011311function getEvenSpacing(arr) {11312var len = arr.length;11313var i, diff;1131411315if (len < 2) {11316return false;11317}1131811319for (diff = arr[0], i = 1; i < len; ++i) {11320if (arr[i] - arr[i - 1] !== diff) {11321return false;11322}11323}11324return diff;11325}1132611327function calculateSpacing(majorIndices, ticks, axisLength, ticksLimit) {11328var evenMajorSpacing = getEvenSpacing(majorIndices);11329var spacing = (ticks.length - 1) / ticksLimit;11330var factors, factor, i, ilen;1133111332// If the major ticks are evenly spaced apart, place the minor ticks11333// so that they divide the major ticks into even chunks11334if (!evenMajorSpacing) {11335return Math.max(spacing, 1);11336}1133711338factors = helpers$1.math._factorize(evenMajorSpacing);11339for (i = 0, ilen = factors.length - 1; i < ilen; i++) {11340factor = factors[i];11341if (factor > spacing) {11342return factor;11343}11344}11345return Math.max(spacing, 1);11346}1134711348function getMajorIndices(ticks) {11349var result = [];11350var i, ilen;11351for (i = 0, ilen = ticks.length; i < ilen; i++) {11352if (ticks[i].major) {11353result.push(i);11354}11355}11356return result;11357}1135811359function skipMajors(ticks, majorIndices, spacing) {11360var count = 0;11361var next = majorIndices[0];11362var i, tick;1136311364spacing = Math.ceil(spacing);11365for (i = 0; i < ticks.length; i++) {11366tick = ticks[i];11367if (i === next) {11368tick._index = i;11369count++;11370next = majorIndices[count * spacing];11371} else {11372delete tick.label;11373}11374}11375}1137611377function skip(ticks, spacing, majorStart, majorEnd) {11378var start = valueOrDefault$a(majorStart, 0);11379var end = Math.min(valueOrDefault$a(majorEnd, ticks.length), ticks.length);11380var count = 0;11381var length, i, tick, next;1138211383spacing = Math.ceil(spacing);11384if (majorEnd) {11385length = majorEnd - majorStart;11386spacing = length / Math.floor(length / spacing);11387}1138811389next = start;1139011391while (next < 0) {11392count++;11393next = Math.round(start + count * spacing);11394}1139511396for (i = Math.max(start, 0); i < end; i++) {11397tick = ticks[i];11398if (i === next) {11399tick._index = i;11400count++;11401next = Math.round(start + count * spacing);11402} else {11403delete tick.label;11404}11405}11406}1140711408var Scale = core_element.extend({1140911410zeroLineIndex: 0,1141111412/**11413* Get the padding needed for the scale11414* @method getPadding11415* @private11416* @returns {Padding} the necessary padding11417*/11418getPadding: function() {11419var me = this;11420return {11421left: me.paddingLeft || 0,11422top: me.paddingTop || 0,11423right: me.paddingRight || 0,11424bottom: me.paddingBottom || 011425};11426},1142711428/**11429* Returns the scale tick objects ({label, major})11430* @since 2.711431*/11432getTicks: function() {11433return this._ticks;11434},1143511436/**11437* @private11438*/11439_getLabels: function() {11440var data = this.chart.data;11441return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];11442},1144311444// These methods are ordered by lifecyle. Utilities then follow.11445// Any function defined here is inherited by all scale types.11446// Any function can be extended by the scale type1144711448/**11449* Provided for backward compatibility, not available anymore11450* @function Chart.Scale.mergeTicksOptions11451* @deprecated since version 2.8.011452* @todo remove at version 311453*/11454mergeTicksOptions: function() {11455// noop11456},1145711458beforeUpdate: function() {11459helpers$1.callback(this.options.beforeUpdate, [this]);11460},1146111462/**11463* @param {number} maxWidth - the max width in pixels11464* @param {number} maxHeight - the max height in pixels11465* @param {object} margins - the space between the edge of the other scales and edge of the chart11466* This space comes from two sources:11467* - padding - space that's required to show the labels at the edges of the scale11468* - thickness of scales or legends in another orientation11469*/11470update: function(maxWidth, maxHeight, margins) {11471var me = this;11472var tickOpts = me.options.ticks;11473var sampleSize = tickOpts.sampleSize;11474var i, ilen, labels, ticks, samplingEnabled;1147511476// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)11477me.beforeUpdate();1147811479// Absorb the master measurements11480me.maxWidth = maxWidth;11481me.maxHeight = maxHeight;11482me.margins = helpers$1.extend({11483left: 0,11484right: 0,11485top: 0,11486bottom: 011487}, margins);1148811489me._ticks = null;11490me.ticks = null;11491me._labelSizes = null;11492me._maxLabelLines = 0;11493me.longestLabelWidth = 0;11494me.longestTextCache = me.longestTextCache || {};11495me._gridLineItems = null;11496me._labelItems = null;1149711498// Dimensions11499me.beforeSetDimensions();11500me.setDimensions();11501me.afterSetDimensions();1150211503// Data min/max11504me.beforeDataLimits();11505me.determineDataLimits();11506me.afterDataLimits();1150711508// Ticks - `this.ticks` is now DEPRECATED!11509// Internal ticks are now stored as objects in the PRIVATE `this._ticks` member11510// and must not be accessed directly from outside this class. `this.ticks` being11511// around for long time and not marked as private, we can't change its structure11512// without unexpected breaking changes. If you need to access the scale ticks,11513// use scale.getTicks() instead.1151411515me.beforeBuildTicks();1151611517// New implementations should return an array of objects but for BACKWARD COMPAT,11518// we still support no return (`this.ticks` internally set by calling this method).11519ticks = me.buildTicks() || [];1152011521// Allow modification of ticks in callback.11522ticks = me.afterBuildTicks(ticks) || ticks;1152311524// Ensure ticks contains ticks in new tick format11525if ((!ticks || !ticks.length) && me.ticks) {11526ticks = [];11527for (i = 0, ilen = me.ticks.length; i < ilen; ++i) {11528ticks.push({11529value: me.ticks[i],11530major: false11531});11532}11533}1153411535me._ticks = ticks;1153611537// Compute tick rotation and fit using a sampled subset of labels11538// We generally don't need to compute the size of every single label for determining scale size11539samplingEnabled = sampleSize < ticks.length;11540labels = me._convertTicksToLabels(samplingEnabled ? sample(ticks, sampleSize) : ticks);1154111542// _configure is called twice, once here, once from core.controller.updateLayout.11543// Here we haven't been positioned yet, but dimensions are correct.11544// Variables set in _configure are needed for calculateTickRotation, and11545// it's ok that coordinates are not correct there, only dimensions matter.11546me._configure();1154711548// Tick Rotation11549me.beforeCalculateTickRotation();11550me.calculateTickRotation();11551me.afterCalculateTickRotation();1155211553me.beforeFit();11554me.fit();11555me.afterFit();1155611557// Auto-skip11558me._ticksToDraw = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(ticks) : ticks;1155911560if (samplingEnabled) {11561// Generate labels using all non-skipped ticks11562labels = me._convertTicksToLabels(me._ticksToDraw);11563}1156411565me.ticks = labels; // BACKWARD COMPATIBILITY1156611567// IMPORTANT: after this point, we consider that `this.ticks` will NEVER change!1156811569me.afterUpdate();1157011571// TODO(v3): remove minSize as a public property and return value from all layout boxes. It is unused11572// make maxWidth and maxHeight private11573return me.minSize;11574},1157511576/**11577* @private11578*/11579_configure: function() {11580var me = this;11581var reversePixels = me.options.ticks.reverse;11582var startPixel, endPixel;1158311584if (me.isHorizontal()) {11585startPixel = me.left;11586endPixel = me.right;11587} else {11588startPixel = me.top;11589endPixel = me.bottom;11590// by default vertical scales are from bottom to top, so pixels are reversed11591reversePixels = !reversePixels;11592}11593me._startPixel = startPixel;11594me._endPixel = endPixel;11595me._reversePixels = reversePixels;11596me._length = endPixel - startPixel;11597},1159811599afterUpdate: function() {11600helpers$1.callback(this.options.afterUpdate, [this]);11601},1160211603//1160411605beforeSetDimensions: function() {11606helpers$1.callback(this.options.beforeSetDimensions, [this]);11607},11608setDimensions: function() {11609var me = this;11610// Set the unconstrained dimension before label rotation11611if (me.isHorizontal()) {11612// Reset position before calculating rotation11613me.width = me.maxWidth;11614me.left = 0;11615me.right = me.width;11616} else {11617me.height = me.maxHeight;1161811619// Reset position before calculating rotation11620me.top = 0;11621me.bottom = me.height;11622}1162311624// Reset padding11625me.paddingLeft = 0;11626me.paddingTop = 0;11627me.paddingRight = 0;11628me.paddingBottom = 0;11629},11630afterSetDimensions: function() {11631helpers$1.callback(this.options.afterSetDimensions, [this]);11632},1163311634// Data limits11635beforeDataLimits: function() {11636helpers$1.callback(this.options.beforeDataLimits, [this]);11637},11638determineDataLimits: helpers$1.noop,11639afterDataLimits: function() {11640helpers$1.callback(this.options.afterDataLimits, [this]);11641},1164211643//11644beforeBuildTicks: function() {11645helpers$1.callback(this.options.beforeBuildTicks, [this]);11646},11647buildTicks: helpers$1.noop,11648afterBuildTicks: function(ticks) {11649var me = this;11650// ticks is empty for old axis implementations here11651if (isArray(ticks) && ticks.length) {11652return helpers$1.callback(me.options.afterBuildTicks, [me, ticks]);11653}11654// Support old implementations (that modified `this.ticks` directly in buildTicks)11655me.ticks = helpers$1.callback(me.options.afterBuildTicks, [me, me.ticks]) || me.ticks;11656return ticks;11657},1165811659beforeTickToLabelConversion: function() {11660helpers$1.callback(this.options.beforeTickToLabelConversion, [this]);11661},11662convertTicksToLabels: function() {11663var me = this;11664// Convert ticks to strings11665var tickOpts = me.options.ticks;11666me.ticks = me.ticks.map(tickOpts.userCallback || tickOpts.callback, this);11667},11668afterTickToLabelConversion: function() {11669helpers$1.callback(this.options.afterTickToLabelConversion, [this]);11670},1167111672//1167311674beforeCalculateTickRotation: function() {11675helpers$1.callback(this.options.beforeCalculateTickRotation, [this]);11676},11677calculateTickRotation: function() {11678var me = this;11679var options = me.options;11680var tickOpts = options.ticks;11681var numTicks = me.getTicks().length;11682var minRotation = tickOpts.minRotation || 0;11683var maxRotation = tickOpts.maxRotation;11684var labelRotation = minRotation;11685var labelSizes, maxLabelWidth, maxLabelHeight, maxWidth, tickWidth, maxHeight, maxLabelDiagonal;1168611687if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) {11688me.labelRotation = minRotation;11689return;11690}1169111692labelSizes = me._getLabelSizes();11693maxLabelWidth = labelSizes.widest.width;11694maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset;1169511696// Estimate the width of each grid based on the canvas width, the maximum11697// label width and the number of tick intervals11698maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth);11699tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1);1170011701// Allow 3 pixels x2 padding either side for label readability11702if (maxLabelWidth + 6 > tickWidth) {11703tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));11704maxHeight = me.maxHeight - getTickMarkLength(options.gridLines)11705- tickOpts.padding - getScaleLabelHeight(options.scaleLabel);11706maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);11707labelRotation = helpers$1.toDegrees(Math.min(11708Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)),11709Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal)11710));11711labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));11712}1171311714me.labelRotation = labelRotation;11715},11716afterCalculateTickRotation: function() {11717helpers$1.callback(this.options.afterCalculateTickRotation, [this]);11718},1171911720//1172111722beforeFit: function() {11723helpers$1.callback(this.options.beforeFit, [this]);11724},11725fit: function() {11726var me = this;11727// Reset11728var minSize = me.minSize = {11729width: 0,11730height: 011731};1173211733var chart = me.chart;11734var opts = me.options;11735var tickOpts = opts.ticks;11736var scaleLabelOpts = opts.scaleLabel;11737var gridLineOpts = opts.gridLines;11738var display = me._isVisible();11739var isBottom = opts.position === 'bottom';11740var isHorizontal = me.isHorizontal();1174111742// Width11743if (isHorizontal) {11744minSize.width = me.maxWidth;11745} else if (display) {11746minSize.width = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);11747}1174811749// height11750if (!isHorizontal) {11751minSize.height = me.maxHeight; // fill all the height11752} else if (display) {11753minSize.height = getTickMarkLength(gridLineOpts) + getScaleLabelHeight(scaleLabelOpts);11754}1175511756// Don't bother fitting the ticks if we are not showing the labels11757if (tickOpts.display && display) {11758var tickFonts = parseTickFontOptions(tickOpts);11759var labelSizes = me._getLabelSizes();11760var firstLabelSize = labelSizes.first;11761var lastLabelSize = labelSizes.last;11762var widestLabelSize = labelSizes.widest;11763var highestLabelSize = labelSizes.highest;11764var lineSpace = tickFonts.minor.lineHeight * 0.4;11765var tickPadding = tickOpts.padding;1176611767if (isHorizontal) {11768// A horizontal axis is more constrained by the height.11769var isRotated = me.labelRotation !== 0;11770var angleRadians = helpers$1.toRadians(me.labelRotation);11771var cosRotation = Math.cos(angleRadians);11772var sinRotation = Math.sin(angleRadians);1177311774var labelHeight = sinRotation * widestLabelSize.width11775+ cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0))11776+ (isRotated ? 0 : lineSpace); // padding1177711778minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding);1177911780var offsetLeft = me.getPixelForTick(0) - me.left;11781var offsetRight = me.right - me.getPixelForTick(me.getTicks().length - 1);11782var paddingLeft, paddingRight;1178311784// Ensure that our ticks are always inside the canvas. When rotated, ticks are right aligned11785// which means that the right padding is dominated by the font height11786if (isRotated) {11787paddingLeft = isBottom ?11788cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset :11789sinRotation * (firstLabelSize.height - firstLabelSize.offset);11790paddingRight = isBottom ?11791sinRotation * (lastLabelSize.height - lastLabelSize.offset) :11792cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset;11793} else {11794paddingLeft = firstLabelSize.width / 2;11795paddingRight = lastLabelSize.width / 2;11796}1179711798// Adjust padding taking into account changes in offsets11799// and add 3 px to move away from canvas edges11800me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3;11801me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3;11802} else {11803// A vertical axis is more constrained by the width. Labels are the11804// dominant factor here, so get that length first and account for padding11805var labelWidth = tickOpts.mirror ? 0 :11806// use lineSpace for consistency with horizontal axis11807// tickPadding is not implemented for horizontal11808widestLabelSize.width + tickPadding + lineSpace;1180911810minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth);1181111812me.paddingTop = firstLabelSize.height / 2;11813me.paddingBottom = lastLabelSize.height / 2;11814}11815}1181611817me.handleMargins();1181811819if (isHorizontal) {11820me.width = me._length = chart.width - me.margins.left - me.margins.right;11821me.height = minSize.height;11822} else {11823me.width = minSize.width;11824me.height = me._length = chart.height - me.margins.top - me.margins.bottom;11825}11826},1182711828/**11829* Handle margins and padding interactions11830* @private11831*/11832handleMargins: function() {11833var me = this;11834if (me.margins) {11835me.margins.left = Math.max(me.paddingLeft, me.margins.left);11836me.margins.top = Math.max(me.paddingTop, me.margins.top);11837me.margins.right = Math.max(me.paddingRight, me.margins.right);11838me.margins.bottom = Math.max(me.paddingBottom, me.margins.bottom);11839}11840},1184111842afterFit: function() {11843helpers$1.callback(this.options.afterFit, [this]);11844},1184511846// Shared Methods11847isHorizontal: function() {11848var pos = this.options.position;11849return pos === 'top' || pos === 'bottom';11850},11851isFullWidth: function() {11852return this.options.fullWidth;11853},1185411855// 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 not11856getRightValue: function(rawValue) {11857// Null and undefined values first11858if (isNullOrUndef(rawValue)) {11859return NaN;11860}11861// isNaN(object) returns true, so make sure NaN is checking for a number; Discard Infinite values11862if ((typeof rawValue === 'number' || rawValue instanceof Number) && !isFinite(rawValue)) {11863return NaN;11864}1186511866// If it is in fact an object, dive in one more level11867if (rawValue) {11868if (this.isHorizontal()) {11869if (rawValue.x !== undefined) {11870return this.getRightValue(rawValue.x);11871}11872} else if (rawValue.y !== undefined) {11873return this.getRightValue(rawValue.y);11874}11875}1187611877// Value is good, return it11878return rawValue;11879},1188011881_convertTicksToLabels: function(ticks) {11882var me = this;11883var labels, i, ilen;1188411885me.ticks = ticks.map(function(tick) {11886return tick.value;11887});1188811889me.beforeTickToLabelConversion();1189011891// New implementations should return the formatted tick labels but for BACKWARD11892// COMPAT, we still support no return (`this.ticks` internally changed by calling11893// this method and supposed to contain only string values).11894labels = me.convertTicksToLabels(ticks) || me.ticks;1189511896me.afterTickToLabelConversion();1189711898// BACKWARD COMPAT: synchronize `_ticks` with labels (so potentially `this.ticks`)11899for (i = 0, ilen = ticks.length; i < ilen; ++i) {11900ticks[i].label = labels[i];11901}1190211903return labels;11904},1190511906/**11907* @private11908*/11909_getLabelSizes: function() {11910var me = this;11911var labelSizes = me._labelSizes;1191211913if (!labelSizes) {11914me._labelSizes = labelSizes = computeLabelSizes(me.ctx, parseTickFontOptions(me.options.ticks), me.getTicks(), me.longestTextCache);11915me.longestLabelWidth = labelSizes.widest.width;11916}1191711918return labelSizes;11919},1192011921/**11922* @private11923*/11924_parseValue: function(value) {11925var start, end, min, max;1192611927if (isArray(value)) {11928start = +this.getRightValue(value[0]);11929end = +this.getRightValue(value[1]);11930min = Math.min(start, end);11931max = Math.max(start, end);11932} else {11933value = +this.getRightValue(value);11934start = undefined;11935end = value;11936min = value;11937max = value;11938}1193911940return {11941min: min,11942max: max,11943start: start,11944end: end11945};11946},1194711948/**11949* @private11950*/11951_getScaleLabel: function(rawValue) {11952var v = this._parseValue(rawValue);11953if (v.start !== undefined) {11954return '[' + v.start + ', ' + v.end + ']';11955}1195611957return +this.getRightValue(rawValue);11958},1195911960/**11961* Used to get the value to display in the tooltip for the data at the given index11962* @param index11963* @param datasetIndex11964*/11965getLabelForIndex: helpers$1.noop,1196611967/**11968* Returns the location of the given data point. Value can either be an index or a numerical value11969* The coordinate (0, 0) is at the upper-left corner of the canvas11970* @param value11971* @param index11972* @param datasetIndex11973*/11974getPixelForValue: helpers$1.noop,1197511976/**11977* Used to get the data value from a given pixel. This is the inverse of getPixelForValue11978* The coordinate (0, 0) is at the upper-left corner of the canvas11979* @param pixel11980*/11981getValueForPixel: helpers$1.noop,1198211983/**11984* Returns the location of the tick at the given index11985* The coordinate (0, 0) is at the upper-left corner of the canvas11986*/11987getPixelForTick: function(index) {11988var me = this;11989var offset = me.options.offset;11990var numTicks = me._ticks.length;11991var tickWidth = 1 / Math.max(numTicks - (offset ? 0 : 1), 1);1199211993return index < 0 || index > numTicks - 111994? null11995: me.getPixelForDecimal(index * tickWidth + (offset ? tickWidth / 2 : 0));11996},1199711998/**11999* Utility for getting the pixel location of a percentage of scale12000* The coordinate (0, 0) is at the upper-left corner of the canvas12001*/12002getPixelForDecimal: function(decimal) {12003var me = this;1200412005if (me._reversePixels) {12006decimal = 1 - decimal;12007}1200812009return me._startPixel + decimal * me._length;12010},1201112012getDecimalForPixel: function(pixel) {12013var decimal = (pixel - this._startPixel) / this._length;12014return this._reversePixels ? 1 - decimal : decimal;12015},1201612017/**12018* Returns the pixel for the minimum chart value12019* The coordinate (0, 0) is at the upper-left corner of the canvas12020*/12021getBasePixel: function() {12022return this.getPixelForValue(this.getBaseValue());12023},1202412025getBaseValue: function() {12026var me = this;12027var min = me.min;12028var max = me.max;1202912030return me.beginAtZero ? 0 :12031min < 0 && max < 0 ? max :12032min > 0 && max > 0 ? min :120330;12034},1203512036/**12037* Returns a subset of ticks to be plotted to avoid overlapping labels.12038* @private12039*/12040_autoSkip: function(ticks) {12041var me = this;12042var tickOpts = me.options.ticks;12043var axisLength = me._length;12044var ticksLimit = tickOpts.maxTicksLimit || axisLength / me._tickSize() + 1;12045var majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];12046var numMajorIndices = majorIndices.length;12047var first = majorIndices[0];12048var last = majorIndices[numMajorIndices - 1];12049var i, ilen, spacing, avgMajorSpacing;1205012051// If there are too many major ticks to display them all12052if (numMajorIndices > ticksLimit) {12053skipMajors(ticks, majorIndices, numMajorIndices / ticksLimit);12054return nonSkipped(ticks);12055}1205612057spacing = calculateSpacing(majorIndices, ticks, axisLength, ticksLimit);1205812059if (numMajorIndices > 0) {12060for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {12061skip(ticks, spacing, majorIndices[i], majorIndices[i + 1]);12062}12063avgMajorSpacing = numMajorIndices > 1 ? (last - first) / (numMajorIndices - 1) : null;12064skip(ticks, spacing, helpers$1.isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);12065skip(ticks, spacing, last, helpers$1.isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);12066return nonSkipped(ticks);12067}12068skip(ticks, spacing);12069return nonSkipped(ticks);12070},1207112072/**12073* @private12074*/12075_tickSize: function() {12076var me = this;12077var optionTicks = me.options.ticks;1207812079// Calculate space needed by label in axis direction.12080var rot = helpers$1.toRadians(me.labelRotation);12081var cos = Math.abs(Math.cos(rot));12082var sin = Math.abs(Math.sin(rot));1208312084var labelSizes = me._getLabelSizes();12085var padding = optionTicks.autoSkipPadding || 0;12086var w = labelSizes ? labelSizes.widest.width + padding : 0;12087var h = labelSizes ? labelSizes.highest.height + padding : 0;1208812089// Calculate space needed for 1 tick in axis direction.12090return me.isHorizontal()12091? h * cos > w * sin ? w / cos : h / sin12092: h * sin < w * cos ? h / cos : w / sin;12093},1209412095/**12096* @private12097*/12098_isVisible: function() {12099var me = this;12100var chart = me.chart;12101var display = me.options.display;12102var i, ilen, meta;1210312104if (display !== 'auto') {12105return !!display;12106}1210712108// When 'auto', the scale is visible if at least one associated dataset is visible.12109for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {12110if (chart.isDatasetVisible(i)) {12111meta = chart.getDatasetMeta(i);12112if (meta.xAxisID === me.id || meta.yAxisID === me.id) {12113return true;12114}12115}12116}1211712118return false;12119},1212012121/**12122* @private12123*/12124_computeGridLineItems: function(chartArea) {12125var me = this;12126var chart = me.chart;12127var options = me.options;12128var gridLines = options.gridLines;12129var position = options.position;12130var offsetGridLines = gridLines.offsetGridLines;12131var isHorizontal = me.isHorizontal();12132var ticks = me._ticksToDraw;12133var ticksLength = ticks.length + (offsetGridLines ? 1 : 0);1213412135var tl = getTickMarkLength(gridLines);12136var items = [];12137var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;12138var axisHalfWidth = axisWidth / 2;12139var alignPixel = helpers$1._alignPixel;12140var alignBorderValue = function(pixel) {12141return alignPixel(chart, pixel, axisWidth);12142};12143var borderValue, i, tick, lineValue, alignedLineValue;12144var tx1, ty1, tx2, ty2, x1, y1, x2, y2, lineWidth, lineColor, borderDash, borderDashOffset;1214512146if (position === 'top') {12147borderValue = alignBorderValue(me.bottom);12148ty1 = me.bottom - tl;12149ty2 = borderValue - axisHalfWidth;12150y1 = alignBorderValue(chartArea.top) + axisHalfWidth;12151y2 = chartArea.bottom;12152} else if (position === 'bottom') {12153borderValue = alignBorderValue(me.top);12154y1 = chartArea.top;12155y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;12156ty1 = borderValue + axisHalfWidth;12157ty2 = me.top + tl;12158} else if (position === 'left') {12159borderValue = alignBorderValue(me.right);12160tx1 = me.right - tl;12161tx2 = borderValue - axisHalfWidth;12162x1 = alignBorderValue(chartArea.left) + axisHalfWidth;12163x2 = chartArea.right;12164} else {12165borderValue = alignBorderValue(me.left);12166x1 = chartArea.left;12167x2 = alignBorderValue(chartArea.right) - axisHalfWidth;12168tx1 = borderValue + axisHalfWidth;12169tx2 = me.left + tl;12170}1217112172for (i = 0; i < ticksLength; ++i) {12173tick = ticks[i] || {};1217412175// autoskipper skipped this tick (#4635)12176if (isNullOrUndef(tick.label) && i < ticks.length) {12177continue;12178}1217912180if (i === me.zeroLineIndex && options.offset === offsetGridLines) {12181// Draw the first index specially12182lineWidth = gridLines.zeroLineWidth;12183lineColor = gridLines.zeroLineColor;12184borderDash = gridLines.zeroLineBorderDash || [];12185borderDashOffset = gridLines.zeroLineBorderDashOffset || 0.0;12186} else {12187lineWidth = valueAtIndexOrDefault(gridLines.lineWidth, i, 1);12188lineColor = valueAtIndexOrDefault(gridLines.color, i, 'rgba(0,0,0,0.1)');12189borderDash = gridLines.borderDash || [];12190borderDashOffset = gridLines.borderDashOffset || 0.0;12191}1219212193lineValue = getPixelForGridLine(me, tick._index || i, offsetGridLines);1219412195// Skip if the pixel is out of the range12196if (lineValue === undefined) {12197continue;12198}1219912200alignedLineValue = alignPixel(chart, lineValue, lineWidth);1220112202if (isHorizontal) {12203tx1 = tx2 = x1 = x2 = alignedLineValue;12204} else {12205ty1 = ty2 = y1 = y2 = alignedLineValue;12206}1220712208items.push({12209tx1: tx1,12210ty1: ty1,12211tx2: tx2,12212ty2: ty2,12213x1: x1,12214y1: y1,12215x2: x2,12216y2: y2,12217width: lineWidth,12218color: lineColor,12219borderDash: borderDash,12220borderDashOffset: borderDashOffset,12221});12222}1222312224items.ticksLength = ticksLength;12225items.borderValue = borderValue;1222612227return items;12228},1222912230/**12231* @private12232*/12233_computeLabelItems: function() {12234var me = this;12235var options = me.options;12236var optionTicks = options.ticks;12237var position = options.position;12238var isMirrored = optionTicks.mirror;12239var isHorizontal = me.isHorizontal();12240var ticks = me._ticksToDraw;12241var fonts = parseTickFontOptions(optionTicks);12242var tickPadding = optionTicks.padding;12243var tl = getTickMarkLength(options.gridLines);12244var rotation = -helpers$1.toRadians(me.labelRotation);12245var items = [];12246var i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;1224712248if (position === 'top') {12249y = me.bottom - tl - tickPadding;12250textAlign = !rotation ? 'center' : 'left';12251} else if (position === 'bottom') {12252y = me.top + tl + tickPadding;12253textAlign = !rotation ? 'center' : 'right';12254} else if (position === 'left') {12255x = me.right - (isMirrored ? 0 : tl) - tickPadding;12256textAlign = isMirrored ? 'left' : 'right';12257} else {12258x = me.left + (isMirrored ? 0 : tl) + tickPadding;12259textAlign = isMirrored ? 'right' : 'left';12260}1226112262for (i = 0, ilen = ticks.length; i < ilen; ++i) {12263tick = ticks[i];12264label = tick.label;1226512266// autoskipper skipped this tick (#4635)12267if (isNullOrUndef(label)) {12268continue;12269}1227012271pixel = me.getPixelForTick(tick._index || i) + optionTicks.labelOffset;12272font = tick.major ? fonts.major : fonts.minor;12273lineHeight = font.lineHeight;12274lineCount = isArray(label) ? label.length : 1;1227512276if (isHorizontal) {12277x = pixel;12278textOffset = position === 'top'12279? ((!rotation ? 0.5 : 1) - lineCount) * lineHeight12280: (!rotation ? 0.5 : 0) * lineHeight;12281} else {12282y = pixel;12283textOffset = (1 - lineCount) * lineHeight / 2;12284}1228512286items.push({12287x: x,12288y: y,12289rotation: rotation,12290label: label,12291font: font,12292textOffset: textOffset,12293textAlign: textAlign12294});12295}1229612297return items;12298},1229912300/**12301* @private12302*/12303_drawGrid: function(chartArea) {12304var me = this;12305var gridLines = me.options.gridLines;1230612307if (!gridLines.display) {12308return;12309}1231012311var ctx = me.ctx;12312var chart = me.chart;12313var alignPixel = helpers$1._alignPixel;12314var axisWidth = gridLines.drawBorder ? valueAtIndexOrDefault(gridLines.lineWidth, 0, 0) : 0;12315var items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea));12316var width, color, i, ilen, item;1231712318for (i = 0, ilen = items.length; i < ilen; ++i) {12319item = items[i];12320width = item.width;12321color = item.color;1232212323if (width && color) {12324ctx.save();12325ctx.lineWidth = width;12326ctx.strokeStyle = color;12327if (ctx.setLineDash) {12328ctx.setLineDash(item.borderDash);12329ctx.lineDashOffset = item.borderDashOffset;12330}1233112332ctx.beginPath();1233312334if (gridLines.drawTicks) {12335ctx.moveTo(item.tx1, item.ty1);12336ctx.lineTo(item.tx2, item.ty2);12337}1233812339if (gridLines.drawOnChartArea) {12340ctx.moveTo(item.x1, item.y1);12341ctx.lineTo(item.x2, item.y2);12342}1234312344ctx.stroke();12345ctx.restore();12346}12347}1234812349if (axisWidth) {12350// Draw the line at the edge of the axis12351var firstLineWidth = axisWidth;12352var lastLineWidth = valueAtIndexOrDefault(gridLines.lineWidth, items.ticksLength - 1, 1);12353var borderValue = items.borderValue;12354var x1, x2, y1, y2;1235512356if (me.isHorizontal()) {12357x1 = alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2;12358x2 = alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2;12359y1 = y2 = borderValue;12360} else {12361y1 = alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2;12362y2 = alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2;12363x1 = x2 = borderValue;12364}1236512366ctx.lineWidth = axisWidth;12367ctx.strokeStyle = valueAtIndexOrDefault(gridLines.color, 0);12368ctx.beginPath();12369ctx.moveTo(x1, y1);12370ctx.lineTo(x2, y2);12371ctx.stroke();12372}12373},1237412375/**12376* @private12377*/12378_drawLabels: function() {12379var me = this;12380var optionTicks = me.options.ticks;1238112382if (!optionTicks.display) {12383return;12384}1238512386var ctx = me.ctx;12387var items = me._labelItems || (me._labelItems = me._computeLabelItems());12388var i, j, ilen, jlen, item, tickFont, label, y;1238912390for (i = 0, ilen = items.length; i < ilen; ++i) {12391item = items[i];12392tickFont = item.font;1239312394// Make sure we draw text in the correct color and font12395ctx.save();12396ctx.translate(item.x, item.y);12397ctx.rotate(item.rotation);12398ctx.font = tickFont.string;12399ctx.fillStyle = tickFont.color;12400ctx.textBaseline = 'middle';12401ctx.textAlign = item.textAlign;1240212403label = item.label;12404y = item.textOffset;12405if (isArray(label)) {12406for (j = 0, jlen = label.length; j < jlen; ++j) {12407// We just make sure the multiline element is a string here..12408ctx.fillText('' + label[j], 0, y);12409y += tickFont.lineHeight;12410}12411} else {12412ctx.fillText(label, 0, y);12413}12414ctx.restore();12415}12416},1241712418/**12419* @private12420*/12421_drawTitle: function() {12422var me = this;12423var ctx = me.ctx;12424var options = me.options;12425var scaleLabel = options.scaleLabel;1242612427if (!scaleLabel.display) {12428return;12429}1243012431var scaleLabelFontColor = valueOrDefault$a(scaleLabel.fontColor, core_defaults.global.defaultFontColor);12432var scaleLabelFont = helpers$1.options._parseFont(scaleLabel);12433var scaleLabelPadding = helpers$1.options.toPadding(scaleLabel.padding);12434var halfLineHeight = scaleLabelFont.lineHeight / 2;12435var position = options.position;12436var rotation = 0;12437var scaleLabelX, scaleLabelY;1243812439if (me.isHorizontal()) {12440scaleLabelX = me.left + me.width / 2; // midpoint of the width12441scaleLabelY = position === 'bottom'12442? me.bottom - halfLineHeight - scaleLabelPadding.bottom12443: me.top + halfLineHeight + scaleLabelPadding.top;12444} else {12445var isLeft = position === 'left';12446scaleLabelX = isLeft12447? me.left + halfLineHeight + scaleLabelPadding.top12448: me.right - halfLineHeight - scaleLabelPadding.top;12449scaleLabelY = me.top + me.height / 2;12450rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI;12451}1245212453ctx.save();12454ctx.translate(scaleLabelX, scaleLabelY);12455ctx.rotate(rotation);12456ctx.textAlign = 'center';12457ctx.textBaseline = 'middle';12458ctx.fillStyle = scaleLabelFontColor; // render in correct colour12459ctx.font = scaleLabelFont.string;12460ctx.fillText(scaleLabel.labelString, 0, 0);12461ctx.restore();12462},1246312464draw: function(chartArea) {12465var me = this;1246612467if (!me._isVisible()) {12468return;12469}1247012471me._drawGrid(chartArea);12472me._drawTitle();12473me._drawLabels();12474},1247512476/**12477* @private12478*/12479_layers: function() {12480var me = this;12481var opts = me.options;12482var tz = opts.ticks && opts.ticks.z || 0;12483var gz = opts.gridLines && opts.gridLines.z || 0;1248412485if (!me._isVisible() || tz === gz || me.draw !== me._draw) {12486// backward compatibility: draw has been overridden by custom scale12487return [{12488z: tz,12489draw: function() {12490me.draw.apply(me, arguments);12491}12492}];12493}1249412495return [{12496z: gz,12497draw: function() {12498me._drawGrid.apply(me, arguments);12499me._drawTitle.apply(me, arguments);12500}12501}, {12502z: tz,12503draw: function() {12504me._drawLabels.apply(me, arguments);12505}12506}];12507},1250812509/**12510* @private12511*/12512_getMatchingVisibleMetas: function(type) {12513var me = this;12514var isHorizontal = me.isHorizontal();12515return me.chart._getSortedVisibleDatasetMetas()12516.filter(function(meta) {12517return (!type || meta.type === type)12518&& (isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id);12519});12520}12521});1252212523Scale.prototype._draw = Scale.prototype.draw;1252412525var core_scale = Scale;1252612527var isNullOrUndef$1 = helpers$1.isNullOrUndef;1252812529var defaultConfig = {12530position: 'bottom'12531};1253212533var scale_category = core_scale.extend({12534determineDataLimits: function() {12535var me = this;12536var labels = me._getLabels();12537var ticksOpts = me.options.ticks;12538var min = ticksOpts.min;12539var max = ticksOpts.max;12540var minIndex = 0;12541var maxIndex = labels.length - 1;12542var findIndex;1254312544if (min !== undefined) {12545// user specified min value12546findIndex = labels.indexOf(min);12547if (findIndex >= 0) {12548minIndex = findIndex;12549}12550}1255112552if (max !== undefined) {12553// user specified max value12554findIndex = labels.indexOf(max);12555if (findIndex >= 0) {12556maxIndex = findIndex;12557}12558}1255912560me.minIndex = minIndex;12561me.maxIndex = maxIndex;12562me.min = labels[minIndex];12563me.max = labels[maxIndex];12564},1256512566buildTicks: function() {12567var me = this;12568var labels = me._getLabels();12569var minIndex = me.minIndex;12570var maxIndex = me.maxIndex;1257112572// If we are viewing some subset of labels, slice the original array12573me.ticks = (minIndex === 0 && maxIndex === labels.length - 1) ? labels : labels.slice(minIndex, maxIndex + 1);12574},1257512576getLabelForIndex: function(index, datasetIndex) {12577var me = this;12578var chart = me.chart;1257912580if (chart.getDatasetMeta(datasetIndex).controller._getValueScaleId() === me.id) {12581return me.getRightValue(chart.data.datasets[datasetIndex].data[index]);12582}1258312584return me._getLabels()[index];12585},1258612587_configure: function() {12588var me = this;12589var offset = me.options.offset;12590var ticks = me.ticks;1259112592core_scale.prototype._configure.call(me);1259312594if (!me.isHorizontal()) {12595// For backward compatibility, vertical category scale reverse is inverted.12596me._reversePixels = !me._reversePixels;12597}1259812599if (!ticks) {12600return;12601}1260212603me._startValue = me.minIndex - (offset ? 0.5 : 0);12604me._valueRange = Math.max(ticks.length - (offset ? 0 : 1), 1);12605},1260612607// Used to get data value locations. Value can either be an index or a numerical value12608getPixelForValue: function(value, index, datasetIndex) {12609var me = this;12610var valueCategory, labels, idx;1261112612if (!isNullOrUndef$1(index) && !isNullOrUndef$1(datasetIndex)) {12613value = me.chart.data.datasets[datasetIndex].data[index];12614}1261512616// If value is a data object, then index is the index in the data array,12617// not the index of the scale. We need to change that.12618if (!isNullOrUndef$1(value)) {12619valueCategory = me.isHorizontal() ? value.x : value.y;12620}12621if (valueCategory !== undefined || (value !== undefined && isNaN(index))) {12622labels = me._getLabels();12623value = helpers$1.valueOrDefault(valueCategory, value);12624idx = labels.indexOf(value);12625index = idx !== -1 ? idx : index;12626if (isNaN(index)) {12627index = value;12628}12629}12630return me.getPixelForDecimal((index - me._startValue) / me._valueRange);12631},1263212633getPixelForTick: function(index) {12634var ticks = this.ticks;12635return index < 0 || index > ticks.length - 112636? null12637: this.getPixelForValue(ticks[index], index + this.minIndex);12638},1263912640getValueForPixel: function(pixel) {12641var me = this;12642var value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange);12643return Math.min(Math.max(value, 0), me.ticks.length - 1);12644},1264512646getBasePixel: function() {12647return this.bottom;12648}12649});1265012651// INTERNAL: static default options, registered in src/index.js12652var _defaults = defaultConfig;12653scale_category._defaults = _defaults;1265412655var noop = helpers$1.noop;12656var isNullOrUndef$2 = helpers$1.isNullOrUndef;1265712658/**12659* Generate a set of linear ticks12660* @param generationOptions the options used to generate the ticks12661* @param dataRange the range of the data12662* @returns {number[]} array of tick values12663*/12664function generateTicks(generationOptions, dataRange) {12665var ticks = [];12666// To get a "nice" value for the tick spacing, we will use the appropriately named12667// "nice number" algorithm. See https://stackoverflow.com/questions/8506881/nice-label-algorithm-for-charts-with-minimum-ticks12668// for details.1266912670var MIN_SPACING = 1e-14;12671var stepSize = generationOptions.stepSize;12672var unit = stepSize || 1;12673var maxNumSpaces = generationOptions.maxTicks - 1;12674var min = generationOptions.min;12675var max = generationOptions.max;12676var precision = generationOptions.precision;12677var rmin = dataRange.min;12678var rmax = dataRange.max;12679var spacing = helpers$1.niceNum((rmax - rmin) / maxNumSpaces / unit) * unit;12680var factor, niceMin, niceMax, numSpaces;1268112682// Beyond MIN_SPACING floating point numbers being to lose precision12683// such that we can't do the math necessary to generate ticks12684if (spacing < MIN_SPACING && isNullOrUndef$2(min) && isNullOrUndef$2(max)) {12685return [rmin, rmax];12686}1268712688numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);12689if (numSpaces > maxNumSpaces) {12690// If the calculated num of spaces exceeds maxNumSpaces, recalculate it12691spacing = helpers$1.niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit;12692}1269312694if (stepSize || isNullOrUndef$2(precision)) {12695// If a precision is not specified, calculate factor based on spacing12696factor = Math.pow(10, helpers$1._decimalPlaces(spacing));12697} else {12698// If the user specified a precision, round to that number of decimal places12699factor = Math.pow(10, precision);12700spacing = Math.ceil(spacing * factor) / factor;12701}1270212703niceMin = Math.floor(rmin / spacing) * spacing;12704niceMax = Math.ceil(rmax / spacing) * spacing;1270512706// If min, max and stepSize is set and they make an evenly spaced scale use it.12707if (stepSize) {12708// If very close to our whole number, use it.12709if (!isNullOrUndef$2(min) && helpers$1.almostWhole(min / spacing, spacing / 1000)) {12710niceMin = min;12711}12712if (!isNullOrUndef$2(max) && helpers$1.almostWhole(max / spacing, spacing / 1000)) {12713niceMax = max;12714}12715}1271612717numSpaces = (niceMax - niceMin) / spacing;12718// If very close to our rounded value, use it.12719if (helpers$1.almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {12720numSpaces = Math.round(numSpaces);12721} else {12722numSpaces = Math.ceil(numSpaces);12723}1272412725niceMin = Math.round(niceMin * factor) / factor;12726niceMax = Math.round(niceMax * factor) / factor;12727ticks.push(isNullOrUndef$2(min) ? niceMin : min);12728for (var j = 1; j < numSpaces; ++j) {12729ticks.push(Math.round((niceMin + j * spacing) * factor) / factor);12730}12731ticks.push(isNullOrUndef$2(max) ? niceMax : max);1273212733return ticks;12734}1273512736var scale_linearbase = core_scale.extend({12737getRightValue: function(value) {12738if (typeof value === 'string') {12739return +value;12740}12741return core_scale.prototype.getRightValue.call(this, value);12742},1274312744handleTickRangeOptions: function() {12745var me = this;12746var opts = me.options;12747var tickOpts = opts.ticks;1274812749// If we are forcing it to begin at 0, but 0 will already be rendered on the chart,12750// do nothing since that would make the chart weird. If the user really wants a weird chart12751// axis, they can manually override it12752if (tickOpts.beginAtZero) {12753var minSign = helpers$1.sign(me.min);12754var maxSign = helpers$1.sign(me.max);1275512756if (minSign < 0 && maxSign < 0) {12757// move the top up to 012758me.max = 0;12759} else if (minSign > 0 && maxSign > 0) {12760// move the bottom down to 012761me.min = 0;12762}12763}1276412765var setMin = tickOpts.min !== undefined || tickOpts.suggestedMin !== undefined;12766var setMax = tickOpts.max !== undefined || tickOpts.suggestedMax !== undefined;1276712768if (tickOpts.min !== undefined) {12769me.min = tickOpts.min;12770} else if (tickOpts.suggestedMin !== undefined) {12771if (me.min === null) {12772me.min = tickOpts.suggestedMin;12773} else {12774me.min = Math.min(me.min, tickOpts.suggestedMin);12775}12776}1277712778if (tickOpts.max !== undefined) {12779me.max = tickOpts.max;12780} else if (tickOpts.suggestedMax !== undefined) {12781if (me.max === null) {12782me.max = tickOpts.suggestedMax;12783} else {12784me.max = Math.max(me.max, tickOpts.suggestedMax);12785}12786}1278712788if (setMin !== setMax) {12789// We set the min or the max but not both.12790// So ensure that our range is good12791// Inverted or 0 length range can happen when12792// ticks.min is set, and no datasets are visible12793if (me.min >= me.max) {12794if (setMin) {12795me.max = me.min + 1;12796} else {12797me.min = me.max - 1;12798}12799}12800}1280112802if (me.min === me.max) {12803me.max++;1280412805if (!tickOpts.beginAtZero) {12806me.min--;12807}12808}12809},1281012811getTickLimit: function() {12812var me = this;12813var tickOpts = me.options.ticks;12814var stepSize = tickOpts.stepSize;12815var maxTicksLimit = tickOpts.maxTicksLimit;12816var maxTicks;1281712818if (stepSize) {12819maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1;12820} else {12821maxTicks = me._computeTickLimit();12822maxTicksLimit = maxTicksLimit || 11;12823}1282412825if (maxTicksLimit) {12826maxTicks = Math.min(maxTicksLimit, maxTicks);12827}1282812829return maxTicks;12830},1283112832_computeTickLimit: function() {12833return Number.POSITIVE_INFINITY;12834},1283512836handleDirectionalChanges: noop,1283712838buildTicks: function() {12839var me = this;12840var opts = me.options;12841var tickOpts = opts.ticks;1284212843// Figure out what the max number of ticks we can support it is based on the size of12844// the axis area. For now, we say that the minimum tick spacing in pixels must be 4012845// We also limit the maximum number of ticks to 11 which gives a nice 10 squares on12846// the graph. Make sure we always have at least 2 ticks12847var maxTicks = me.getTickLimit();12848maxTicks = Math.max(2, maxTicks);1284912850var numericGeneratorOptions = {12851maxTicks: maxTicks,12852min: tickOpts.min,12853max: tickOpts.max,12854precision: tickOpts.precision,12855stepSize: helpers$1.valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize)12856};12857var ticks = me.ticks = generateTicks(numericGeneratorOptions, me);1285812859me.handleDirectionalChanges();1286012861// At this point, we need to update our max and min given the tick values since we have expanded the12862// range of the scale12863me.max = helpers$1.max(ticks);12864me.min = helpers$1.min(ticks);1286512866if (tickOpts.reverse) {12867ticks.reverse();1286812869me.start = me.max;12870me.end = me.min;12871} else {12872me.start = me.min;12873me.end = me.max;12874}12875},1287612877convertTicksToLabels: function() {12878var me = this;12879me.ticksAsNumbers = me.ticks.slice();12880me.zeroLineIndex = me.ticks.indexOf(0);1288112882core_scale.prototype.convertTicksToLabels.call(me);12883},1288412885_configure: function() {12886var me = this;12887var ticks = me.getTicks();12888var start = me.min;12889var end = me.max;12890var offset;1289112892core_scale.prototype._configure.call(me);1289312894if (me.options.offset && ticks.length) {12895offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;12896start -= offset;12897end += offset;12898}12899me._startValue = start;12900me._endValue = end;12901me._valueRange = end - start;12902}12903});1290412905var defaultConfig$1 = {12906position: 'left',12907ticks: {12908callback: core_ticks.formatters.linear12909}12910};1291112912var DEFAULT_MIN = 0;12913var DEFAULT_MAX = 1;1291412915function getOrCreateStack(stacks, stacked, meta) {12916var key = [12917meta.type,12918// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined12919stacked === undefined && meta.stack === undefined ? meta.index : '',12920meta.stack12921].join('.');1292212923if (stacks[key] === undefined) {12924stacks[key] = {12925pos: [],12926neg: []12927};12928}1292912930return stacks[key];12931}1293212933function stackData(scale, stacks, meta, data) {12934var opts = scale.options;12935var stacked = opts.stacked;12936var stack = getOrCreateStack(stacks, stacked, meta);12937var pos = stack.pos;12938var neg = stack.neg;12939var ilen = data.length;12940var i, value;1294112942for (i = 0; i < ilen; ++i) {12943value = scale._parseValue(data[i]);12944if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {12945continue;12946}1294712948pos[i] = pos[i] || 0;12949neg[i] = neg[i] || 0;1295012951if (opts.relativePoints) {12952pos[i] = 100;12953} else if (value.min < 0 || value.max < 0) {12954neg[i] += value.min;12955} else {12956pos[i] += value.max;12957}12958}12959}1296012961function updateMinMax(scale, meta, data) {12962var ilen = data.length;12963var i, value;1296412965for (i = 0; i < ilen; ++i) {12966value = scale._parseValue(data[i]);12967if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden) {12968continue;12969}1297012971scale.min = Math.min(scale.min, value.min);12972scale.max = Math.max(scale.max, value.max);12973}12974}1297512976var scale_linear = scale_linearbase.extend({12977determineDataLimits: function() {12978var me = this;12979var opts = me.options;12980var chart = me.chart;12981var datasets = chart.data.datasets;12982var metasets = me._getMatchingVisibleMetas();12983var hasStacks = opts.stacked;12984var stacks = {};12985var ilen = metasets.length;12986var i, meta, data, values;1298712988me.min = Number.POSITIVE_INFINITY;12989me.max = Number.NEGATIVE_INFINITY;1299012991if (hasStacks === undefined) {12992for (i = 0; !hasStacks && i < ilen; ++i) {12993meta = metasets[i];12994hasStacks = meta.stack !== undefined;12995}12996}1299712998for (i = 0; i < ilen; ++i) {12999meta = metasets[i];13000data = datasets[meta.index].data;13001if (hasStacks) {13002stackData(me, stacks, meta, data);13003} else {13004updateMinMax(me, meta, data);13005}13006}1300713008helpers$1.each(stacks, function(stackValues) {13009values = stackValues.pos.concat(stackValues.neg);13010me.min = Math.min(me.min, helpers$1.min(values));13011me.max = Math.max(me.max, helpers$1.max(values));13012});1301313014me.min = helpers$1.isFinite(me.min) && !isNaN(me.min) ? me.min : DEFAULT_MIN;13015me.max = helpers$1.isFinite(me.max) && !isNaN(me.max) ? me.max : DEFAULT_MAX;1301613017// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero13018me.handleTickRangeOptions();13019},1302013021// Returns the maximum number of ticks based on the scale dimension13022_computeTickLimit: function() {13023var me = this;13024var tickFont;1302513026if (me.isHorizontal()) {13027return Math.ceil(me.width / 40);13028}13029tickFont = helpers$1.options._parseFont(me.options.ticks);13030return Math.ceil(me.height / tickFont.lineHeight);13031},1303213033// Called after the ticks are built. We need13034handleDirectionalChanges: function() {13035if (!this.isHorizontal()) {13036// We are in a vertical orientation. The top value is the highest. So reverse the array13037this.ticks.reverse();13038}13039},1304013041getLabelForIndex: function(index, datasetIndex) {13042return this._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);13043},1304413045// Utils13046getPixelForValue: function(value) {13047var me = this;13048return me.getPixelForDecimal((+me.getRightValue(value) - me._startValue) / me._valueRange);13049},1305013051getValueForPixel: function(pixel) {13052return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;13053},1305413055getPixelForTick: function(index) {13056var ticks = this.ticksAsNumbers;13057if (index < 0 || index > ticks.length - 1) {13058return null;13059}13060return this.getPixelForValue(ticks[index]);13061}13062});1306313064// INTERNAL: static default options, registered in src/index.js13065var _defaults$1 = defaultConfig$1;13066scale_linear._defaults = _defaults$1;1306713068var valueOrDefault$b = helpers$1.valueOrDefault;13069var log10 = helpers$1.math.log10;1307013071/**13072* Generate a set of logarithmic ticks13073* @param generationOptions the options used to generate the ticks13074* @param dataRange the range of the data13075* @returns {number[]} array of tick values13076*/13077function generateTicks$1(generationOptions, dataRange) {13078var ticks = [];1307913080var tickVal = valueOrDefault$b(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));1308113082var endExp = Math.floor(log10(dataRange.max));13083var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));13084var exp, significand;1308513086if (tickVal === 0) {13087exp = Math.floor(log10(dataRange.minNotZero));13088significand = Math.floor(dataRange.minNotZero / Math.pow(10, exp));1308913090ticks.push(tickVal);13091tickVal = significand * Math.pow(10, exp);13092} else {13093exp = Math.floor(log10(tickVal));13094significand = Math.floor(tickVal / Math.pow(10, exp));13095}13096var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;1309713098do {13099ticks.push(tickVal);1310013101++significand;13102if (significand === 10) {13103significand = 1;13104++exp;13105precision = exp >= 0 ? 1 : precision;13106}1310713108tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;13109} while (exp < endExp || (exp === endExp && significand < endSignificand));1311013111var lastTick = valueOrDefault$b(generationOptions.max, tickVal);13112ticks.push(lastTick);1311313114return ticks;13115}1311613117var defaultConfig$2 = {13118position: 'left',1311913120// label settings13121ticks: {13122callback: core_ticks.formatters.logarithmic13123}13124};1312513126// TODO(v3): change this to positiveOrDefault13127function nonNegativeOrDefault(value, defaultValue) {13128return helpers$1.isFinite(value) && value >= 0 ? value : defaultValue;13129}1313013131var scale_logarithmic = core_scale.extend({13132determineDataLimits: function() {13133var me = this;13134var opts = me.options;13135var chart = me.chart;13136var datasets = chart.data.datasets;13137var isHorizontal = me.isHorizontal();13138function IDMatches(meta) {13139return isHorizontal ? meta.xAxisID === me.id : meta.yAxisID === me.id;13140}13141var datasetIndex, meta, value, data, i, ilen;1314213143// Calculate Range13144me.min = Number.POSITIVE_INFINITY;13145me.max = Number.NEGATIVE_INFINITY;13146me.minNotZero = Number.POSITIVE_INFINITY;1314713148var hasStacks = opts.stacked;13149if (hasStacks === undefined) {13150for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {13151meta = chart.getDatasetMeta(datasetIndex);13152if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta) &&13153meta.stack !== undefined) {13154hasStacks = true;13155break;13156}13157}13158}1315913160if (opts.stacked || hasStacks) {13161var valuesPerStack = {};1316213163for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {13164meta = chart.getDatasetMeta(datasetIndex);13165var key = [13166meta.type,13167// we have a separate stack for stack=undefined datasets when the opts.stacked is undefined13168((opts.stacked === undefined && meta.stack === undefined) ? datasetIndex : ''),13169meta.stack13170].join('.');1317113172if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {13173if (valuesPerStack[key] === undefined) {13174valuesPerStack[key] = [];13175}1317613177data = datasets[datasetIndex].data;13178for (i = 0, ilen = data.length; i < ilen; i++) {13179var values = valuesPerStack[key];13180value = me._parseValue(data[i]);13181// invalid, hidden and negative values are ignored13182if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {13183continue;13184}13185values[i] = values[i] || 0;13186values[i] += value.max;13187}13188}13189}1319013191helpers$1.each(valuesPerStack, function(valuesForType) {13192if (valuesForType.length > 0) {13193var minVal = helpers$1.min(valuesForType);13194var maxVal = helpers$1.max(valuesForType);13195me.min = Math.min(me.min, minVal);13196me.max = Math.max(me.max, maxVal);13197}13198});1319913200} else {13201for (datasetIndex = 0; datasetIndex < datasets.length; datasetIndex++) {13202meta = chart.getDatasetMeta(datasetIndex);13203if (chart.isDatasetVisible(datasetIndex) && IDMatches(meta)) {13204data = datasets[datasetIndex].data;13205for (i = 0, ilen = data.length; i < ilen; i++) {13206value = me._parseValue(data[i]);13207// invalid, hidden and negative values are ignored13208if (isNaN(value.min) || isNaN(value.max) || meta.data[i].hidden || value.min < 0 || value.max < 0) {13209continue;13210}1321113212me.min = Math.min(value.min, me.min);13213me.max = Math.max(value.max, me.max);1321413215if (value.min !== 0) {13216me.minNotZero = Math.min(value.min, me.minNotZero);13217}13218}13219}13220}13221}1322213223me.min = helpers$1.isFinite(me.min) ? me.min : null;13224me.max = helpers$1.isFinite(me.max) ? me.max : null;13225me.minNotZero = helpers$1.isFinite(me.minNotZero) ? me.minNotZero : null;1322613227// Common base implementation to handle ticks.min, ticks.max13228this.handleTickRangeOptions();13229},1323013231handleTickRangeOptions: function() {13232var me = this;13233var tickOpts = me.options.ticks;13234var DEFAULT_MIN = 1;13235var DEFAULT_MAX = 10;1323613237me.min = nonNegativeOrDefault(tickOpts.min, me.min);13238me.max = nonNegativeOrDefault(tickOpts.max, me.max);1323913240if (me.min === me.max) {13241if (me.min !== 0 && me.min !== null) {13242me.min = Math.pow(10, Math.floor(log10(me.min)) - 1);13243me.max = Math.pow(10, Math.floor(log10(me.max)) + 1);13244} else {13245me.min = DEFAULT_MIN;13246me.max = DEFAULT_MAX;13247}13248}13249if (me.min === null) {13250me.min = Math.pow(10, Math.floor(log10(me.max)) - 1);13251}13252if (me.max === null) {13253me.max = me.min !== 013254? Math.pow(10, Math.floor(log10(me.min)) + 1)13255: DEFAULT_MAX;13256}13257if (me.minNotZero === null) {13258if (me.min > 0) {13259me.minNotZero = me.min;13260} else if (me.max < 1) {13261me.minNotZero = Math.pow(10, Math.floor(log10(me.max)));13262} else {13263me.minNotZero = DEFAULT_MIN;13264}13265}13266},1326713268buildTicks: function() {13269var me = this;13270var tickOpts = me.options.ticks;13271var reverse = !me.isHorizontal();1327213273var generationOptions = {13274min: nonNegativeOrDefault(tickOpts.min),13275max: nonNegativeOrDefault(tickOpts.max)13276};13277var ticks = me.ticks = generateTicks$1(generationOptions, me);1327813279// At this point, we need to update our max and min given the tick values since we have expanded the13280// range of the scale13281me.max = helpers$1.max(ticks);13282me.min = helpers$1.min(ticks);1328313284if (tickOpts.reverse) {13285reverse = !reverse;13286me.start = me.max;13287me.end = me.min;13288} else {13289me.start = me.min;13290me.end = me.max;13291}13292if (reverse) {13293ticks.reverse();13294}13295},1329613297convertTicksToLabels: function() {13298this.tickValues = this.ticks.slice();1329913300core_scale.prototype.convertTicksToLabels.call(this);13301},1330213303// Get the correct tooltip label13304getLabelForIndex: function(index, datasetIndex) {13305return this._getScaleLabel(this.chart.data.datasets[datasetIndex].data[index]);13306},1330713308getPixelForTick: function(index) {13309var ticks = this.tickValues;13310if (index < 0 || index > ticks.length - 1) {13311return null;13312}13313return this.getPixelForValue(ticks[index]);13314},1331513316/**13317* Returns the value of the first tick.13318* @param {number} value - The minimum not zero value.13319* @return {number} The first tick value.13320* @private13321*/13322_getFirstTickValue: function(value) {13323var exp = Math.floor(log10(value));13324var significand = Math.floor(value / Math.pow(10, exp));1332513326return significand * Math.pow(10, exp);13327},1332813329_configure: function() {13330var me = this;13331var start = me.min;13332var offset = 0;1333313334core_scale.prototype._configure.call(me);1333513336if (start === 0) {13337start = me._getFirstTickValue(me.minNotZero);13338offset = valueOrDefault$b(me.options.ticks.fontSize, core_defaults.global.defaultFontSize) / me._length;13339}1334013341me._startValue = log10(start);13342me._valueOffset = offset;13343me._valueRange = (log10(me.max) - log10(start)) / (1 - offset);13344},1334513346getPixelForValue: function(value) {13347var me = this;13348var decimal = 0;1334913350value = +me.getRightValue(value);1335113352if (value > me.min && value > 0) {13353decimal = (log10(value) - me._startValue) / me._valueRange + me._valueOffset;13354}13355return me.getPixelForDecimal(decimal);13356},1335713358getValueForPixel: function(pixel) {13359var me = this;13360var decimal = me.getDecimalForPixel(pixel);13361return decimal === 0 && me.min === 013362? 013363: Math.pow(10, me._startValue + (decimal - me._valueOffset) * me._valueRange);13364}13365});1336613367// INTERNAL: static default options, registered in src/index.js13368var _defaults$2 = defaultConfig$2;13369scale_logarithmic._defaults = _defaults$2;1337013371var valueOrDefault$c = helpers$1.valueOrDefault;13372var valueAtIndexOrDefault$1 = helpers$1.valueAtIndexOrDefault;13373var resolve$4 = helpers$1.options.resolve;1337413375var defaultConfig$3 = {13376display: true,1337713378// Boolean - Whether to animate scaling the chart from the centre13379animate: true,13380position: 'chartArea',1338113382angleLines: {13383display: true,13384color: 'rgba(0,0,0,0.1)',13385lineWidth: 1,13386borderDash: [],13387borderDashOffset: 0.013388},1338913390gridLines: {13391circular: false13392},1339313394// label settings13395ticks: {13396// Boolean - Show a backdrop to the scale label13397showLabelBackdrop: true,1339813399// String - The colour of the label backdrop13400backdropColor: 'rgba(255,255,255,0.75)',1340113402// Number - The backdrop padding above & below the label in pixels13403backdropPaddingY: 2,1340413405// Number - The backdrop padding to the side of the label in pixels13406backdropPaddingX: 2,1340713408callback: core_ticks.formatters.linear13409},1341013411pointLabels: {13412// Boolean - if true, show point labels13413display: true,1341413415// Number - Point label font size in pixels13416fontSize: 10,1341713418// Function - Used to convert point labels13419callback: function(label) {13420return label;13421}13422}13423};1342413425function getTickBackdropHeight(opts) {13426var tickOpts = opts.ticks;1342713428if (tickOpts.display && opts.display) {13429return valueOrDefault$c(tickOpts.fontSize, core_defaults.global.defaultFontSize) + tickOpts.backdropPaddingY * 2;13430}13431return 0;13432}1343313434function measureLabelSize(ctx, lineHeight, label) {13435if (helpers$1.isArray(label)) {13436return {13437w: helpers$1.longestText(ctx, ctx.font, label),13438h: label.length * lineHeight13439};13440}1344113442return {13443w: ctx.measureText(label).width,13444h: lineHeight13445};13446}1344713448function determineLimits(angle, pos, size, min, max) {13449if (angle === min || angle === max) {13450return {13451start: pos - (size / 2),13452end: pos + (size / 2)13453};13454} else if (angle < min || angle > max) {13455return {13456start: pos - size,13457end: pos13458};13459}1346013461return {13462start: pos,13463end: pos + size13464};13465}1346613467/**13468* Helper function to fit a radial linear scale with point labels13469*/13470function fitWithPointLabels(scale) {1347113472// Right, this is really confusing and there is a lot of maths going on here13473// The gist of the problem is here: https://gist.github.com/nnnick/696cc9c55f4b0beb8fe913474//13475// Reaction: https://dl.dropboxusercontent.com/u/34601363/toomuchscience.gif13476//13477// Solution:13478//13479// We assume the radius of the polygon is half the size of the canvas at first13480// at each index we check if the text overlaps.13481//13482// Where it does, we store that angle and that index.13483//13484// After finding the largest index and angle we calculate how much we need to remove13485// from the shape radius to move the point inwards by that x.13486//13487// We average the left and right distances to get the maximum shape radius that can fit in the box13488// along with labels.13489//13490// Once we have that, we can find the centre point for the chart, by taking the x text protrusion13491// on each side, removing that from the size, halving it and adding the left x protrusion width.13492//13493// This will mean we have a shape fitted to the canvas, as large as it can be with the labels13494// and position it in the most space efficient manner13495//13496// https://dl.dropboxusercontent.com/u/34601363/yeahscience.gif1349713498var plFont = helpers$1.options._parseFont(scale.options.pointLabels);1349913500// Get maximum radius of the polygon. Either half the height (minus the text width) or half the width.13501// Use this to calculate the offset + change. - Make sure L/R protrusion is at least 0 to stop issues with centre points13502var furthestLimits = {13503l: 0,13504r: scale.width,13505t: 0,13506b: scale.height - scale.paddingTop13507};13508var furthestAngles = {};13509var i, textSize, pointPosition;1351013511scale.ctx.font = plFont.string;13512scale._pointLabelSizes = [];1351313514var valueCount = scale.chart.data.labels.length;13515for (i = 0; i < valueCount; i++) {13516pointPosition = scale.getPointPosition(i, scale.drawingArea + 5);13517textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]);13518scale._pointLabelSizes[i] = textSize;1351913520// Add quarter circle to make degree 0 mean top of circle13521var angleRadians = scale.getIndexAngle(i);13522var angle = helpers$1.toDegrees(angleRadians) % 360;13523var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);13524var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);1352513526if (hLimits.start < furthestLimits.l) {13527furthestLimits.l = hLimits.start;13528furthestAngles.l = angleRadians;13529}1353013531if (hLimits.end > furthestLimits.r) {13532furthestLimits.r = hLimits.end;13533furthestAngles.r = angleRadians;13534}1353513536if (vLimits.start < furthestLimits.t) {13537furthestLimits.t = vLimits.start;13538furthestAngles.t = angleRadians;13539}1354013541if (vLimits.end > furthestLimits.b) {13542furthestLimits.b = vLimits.end;13543furthestAngles.b = angleRadians;13544}13545}1354613547scale.setReductions(scale.drawingArea, furthestLimits, furthestAngles);13548}1354913550function getTextAlignForAngle(angle) {13551if (angle === 0 || angle === 180) {13552return 'center';13553} else if (angle < 180) {13554return 'left';13555}1355613557return 'right';13558}1355913560function fillText(ctx, text, position, lineHeight) {13561var y = position.y + lineHeight / 2;13562var i, ilen;1356313564if (helpers$1.isArray(text)) {13565for (i = 0, ilen = text.length; i < ilen; ++i) {13566ctx.fillText(text[i], position.x, y);13567y += lineHeight;13568}13569} else {13570ctx.fillText(text, position.x, y);13571}13572}1357313574function adjustPointPositionForLabelHeight(angle, textSize, position) {13575if (angle === 90 || angle === 270) {13576position.y -= (textSize.h / 2);13577} else if (angle > 270 || angle < 90) {13578position.y -= textSize.h;13579}13580}1358113582function drawPointLabels(scale) {13583var ctx = scale.ctx;13584var opts = scale.options;13585var pointLabelOpts = opts.pointLabels;13586var tickBackdropHeight = getTickBackdropHeight(opts);13587var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max);13588var plFont = helpers$1.options._parseFont(pointLabelOpts);1358913590ctx.save();1359113592ctx.font = plFont.string;13593ctx.textBaseline = 'middle';1359413595for (var i = scale.chart.data.labels.length - 1; i >= 0; i--) {13596// Extra pixels out for some label spacing13597var extra = (i === 0 ? tickBackdropHeight / 2 : 0);13598var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5);1359913600// Keep this in loop since we may support array properties here13601var pointLabelFontColor = valueAtIndexOrDefault$1(pointLabelOpts.fontColor, i, core_defaults.global.defaultFontColor);13602ctx.fillStyle = pointLabelFontColor;1360313604var angleRadians = scale.getIndexAngle(i);13605var angle = helpers$1.toDegrees(angleRadians);13606ctx.textAlign = getTextAlignForAngle(angle);13607adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition);13608fillText(ctx, scale.pointLabels[i], pointLabelPosition, plFont.lineHeight);13609}13610ctx.restore();13611}1361213613function drawRadiusLine(scale, gridLineOpts, radius, index) {13614var ctx = scale.ctx;13615var circular = gridLineOpts.circular;13616var valueCount = scale.chart.data.labels.length;13617var lineColor = valueAtIndexOrDefault$1(gridLineOpts.color, index - 1);13618var lineWidth = valueAtIndexOrDefault$1(gridLineOpts.lineWidth, index - 1);13619var pointPosition;1362013621if ((!circular && !valueCount) || !lineColor || !lineWidth) {13622return;13623}1362413625ctx.save();13626ctx.strokeStyle = lineColor;13627ctx.lineWidth = lineWidth;13628if (ctx.setLineDash) {13629ctx.setLineDash(gridLineOpts.borderDash || []);13630ctx.lineDashOffset = gridLineOpts.borderDashOffset || 0.0;13631}1363213633ctx.beginPath();13634if (circular) {13635// Draw circular arcs between the points13636ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2);13637} else {13638// Draw straight lines connecting each index13639pointPosition = scale.getPointPosition(0, radius);13640ctx.moveTo(pointPosition.x, pointPosition.y);1364113642for (var i = 1; i < valueCount; i++) {13643pointPosition = scale.getPointPosition(i, radius);13644ctx.lineTo(pointPosition.x, pointPosition.y);13645}13646}13647ctx.closePath();13648ctx.stroke();13649ctx.restore();13650}1365113652function numberOrZero(param) {13653return helpers$1.isNumber(param) ? param : 0;13654}1365513656var scale_radialLinear = scale_linearbase.extend({13657setDimensions: function() {13658var me = this;1365913660// Set the unconstrained dimension before label rotation13661me.width = me.maxWidth;13662me.height = me.maxHeight;13663me.paddingTop = getTickBackdropHeight(me.options) / 2;13664me.xCenter = Math.floor(me.width / 2);13665me.yCenter = Math.floor((me.height - me.paddingTop) / 2);13666me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2;13667},1366813669determineDataLimits: function() {13670var me = this;13671var chart = me.chart;13672var min = Number.POSITIVE_INFINITY;13673var max = Number.NEGATIVE_INFINITY;1367413675helpers$1.each(chart.data.datasets, function(dataset, datasetIndex) {13676if (chart.isDatasetVisible(datasetIndex)) {13677var meta = chart.getDatasetMeta(datasetIndex);1367813679helpers$1.each(dataset.data, function(rawValue, index) {13680var value = +me.getRightValue(rawValue);13681if (isNaN(value) || meta.data[index].hidden) {13682return;13683}1368413685min = Math.min(value, min);13686max = Math.max(value, max);13687});13688}13689});1369013691me.min = (min === Number.POSITIVE_INFINITY ? 0 : min);13692me.max = (max === Number.NEGATIVE_INFINITY ? 0 : max);1369313694// Common base implementation to handle ticks.min, ticks.max, ticks.beginAtZero13695me.handleTickRangeOptions();13696},1369713698// Returns the maximum number of ticks based on the scale dimension13699_computeTickLimit: function() {13700return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));13701},1370213703convertTicksToLabels: function() {13704var me = this;1370513706scale_linearbase.prototype.convertTicksToLabels.call(me);1370713708// Point labels13709me.pointLabels = me.chart.data.labels.map(function() {13710var label = helpers$1.callback(me.options.pointLabels.callback, arguments, me);13711return label || label === 0 ? label : '';13712});13713},1371413715getLabelForIndex: function(index, datasetIndex) {13716return +this.getRightValue(this.chart.data.datasets[datasetIndex].data[index]);13717},1371813719fit: function() {13720var me = this;13721var opts = me.options;1372213723if (opts.display && opts.pointLabels.display) {13724fitWithPointLabels(me);13725} else {13726me.setCenterPoint(0, 0, 0, 0);13727}13728},1372913730/**13731* Set radius reductions and determine new radius and center point13732* @private13733*/13734setReductions: function(largestPossibleRadius, furthestLimits, furthestAngles) {13735var me = this;13736var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l);13737var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r);13738var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t);13739var radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b);1374013741radiusReductionLeft = numberOrZero(radiusReductionLeft);13742radiusReductionRight = numberOrZero(radiusReductionRight);13743radiusReductionTop = numberOrZero(radiusReductionTop);13744radiusReductionBottom = numberOrZero(radiusReductionBottom);1374513746me.drawingArea = Math.min(13747Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2),13748Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2));13749me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom);13750},1375113752setCenterPoint: function(leftMovement, rightMovement, topMovement, bottomMovement) {13753var me = this;13754var maxRight = me.width - rightMovement - me.drawingArea;13755var maxLeft = leftMovement + me.drawingArea;13756var maxTop = topMovement + me.drawingArea;13757var maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea;1375813759me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left);13760me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop);13761},1376213763getIndexAngle: function(index) {13764var chart = this.chart;13765var angleMultiplier = 360 / chart.data.labels.length;13766var options = chart.options || {};13767var startAngle = options.startAngle || 0;1376813769// Start from the top instead of right, so remove a quarter of the circle13770var angle = (index * angleMultiplier + startAngle) % 360;1377113772return (angle < 0 ? angle + 360 : angle) * Math.PI * 2 / 360;13773},1377413775getDistanceFromCenterForValue: function(value) {13776var me = this;1377713778if (helpers$1.isNullOrUndef(value)) {13779return NaN;13780}1378113782// Take into account half font size + the yPadding of the top value13783var scalingFactor = me.drawingArea / (me.max - me.min);13784if (me.options.ticks.reverse) {13785return (me.max - value) * scalingFactor;13786}13787return (value - me.min) * scalingFactor;13788},1378913790getPointPosition: function(index, distanceFromCenter) {13791var me = this;13792var thisAngle = me.getIndexAngle(index) - (Math.PI / 2);13793return {13794x: Math.cos(thisAngle) * distanceFromCenter + me.xCenter,13795y: Math.sin(thisAngle) * distanceFromCenter + me.yCenter13796};13797},1379813799getPointPositionForValue: function(index, value) {13800return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));13801},1380213803getBasePosition: function(index) {13804var me = this;13805var min = me.min;13806var max = me.max;1380713808return me.getPointPositionForValue(index || 0,13809me.beginAtZero ? 0 :13810min < 0 && max < 0 ? max :13811min > 0 && max > 0 ? min :138120);13813},1381413815/**13816* @private13817*/13818_drawGrid: function() {13819var me = this;13820var ctx = me.ctx;13821var opts = me.options;13822var gridLineOpts = opts.gridLines;13823var angleLineOpts = opts.angleLines;13824var lineWidth = valueOrDefault$c(angleLineOpts.lineWidth, gridLineOpts.lineWidth);13825var lineColor = valueOrDefault$c(angleLineOpts.color, gridLineOpts.color);13826var i, offset, position;1382713828if (opts.pointLabels.display) {13829drawPointLabels(me);13830}1383113832if (gridLineOpts.display) {13833helpers$1.each(me.ticks, function(label, index) {13834if (index !== 0) {13835offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);13836drawRadiusLine(me, gridLineOpts, offset, index);13837}13838});13839}1384013841if (angleLineOpts.display && lineWidth && lineColor) {13842ctx.save();13843ctx.lineWidth = lineWidth;13844ctx.strokeStyle = lineColor;13845if (ctx.setLineDash) {13846ctx.setLineDash(resolve$4([angleLineOpts.borderDash, gridLineOpts.borderDash, []]));13847ctx.lineDashOffset = resolve$4([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0]);13848}1384913850for (i = me.chart.data.labels.length - 1; i >= 0; i--) {13851offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max);13852position = me.getPointPosition(i, offset);13853ctx.beginPath();13854ctx.moveTo(me.xCenter, me.yCenter);13855ctx.lineTo(position.x, position.y);13856ctx.stroke();13857}1385813859ctx.restore();13860}13861},1386213863/**13864* @private13865*/13866_drawLabels: function() {13867var me = this;13868var ctx = me.ctx;13869var opts = me.options;13870var tickOpts = opts.ticks;1387113872if (!tickOpts.display) {13873return;13874}1387513876var startAngle = me.getIndexAngle(0);13877var tickFont = helpers$1.options._parseFont(tickOpts);13878var tickFontColor = valueOrDefault$c(tickOpts.fontColor, core_defaults.global.defaultFontColor);13879var offset, width;1388013881ctx.save();13882ctx.font = tickFont.string;13883ctx.translate(me.xCenter, me.yCenter);13884ctx.rotate(startAngle);13885ctx.textAlign = 'center';13886ctx.textBaseline = 'middle';1388713888helpers$1.each(me.ticks, function(label, index) {13889if (index === 0 && !tickOpts.reverse) {13890return;13891}1389213893offset = me.getDistanceFromCenterForValue(me.ticksAsNumbers[index]);1389413895if (tickOpts.showLabelBackdrop) {13896width = ctx.measureText(label).width;13897ctx.fillStyle = tickOpts.backdropColor;1389813899ctx.fillRect(13900-width / 2 - tickOpts.backdropPaddingX,13901-offset - tickFont.size / 2 - tickOpts.backdropPaddingY,13902width + tickOpts.backdropPaddingX * 2,13903tickFont.size + tickOpts.backdropPaddingY * 213904);13905}1390613907ctx.fillStyle = tickFontColor;13908ctx.fillText(label, 0, -offset);13909});1391013911ctx.restore();13912},1391313914/**13915* @private13916*/13917_drawTitle: helpers$1.noop13918});1391913920// INTERNAL: static default options, registered in src/index.js13921var _defaults$3 = defaultConfig$3;13922scale_radialLinear._defaults = _defaults$3;1392313924var deprecated$1 = helpers$1._deprecated;13925var resolve$5 = helpers$1.options.resolve;13926var valueOrDefault$d = helpers$1.valueOrDefault;1392713928// Integer constants are from the ES6 spec.13929var MIN_INTEGER = Number.MIN_SAFE_INTEGER || -9007199254740991;13930var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991;1393113932var INTERVALS = {13933millisecond: {13934common: true,13935size: 1,13936steps: 100013937},13938second: {13939common: true,13940size: 1000,13941steps: 6013942},13943minute: {13944common: true,13945size: 60000,13946steps: 6013947},13948hour: {13949common: true,13950size: 3600000,13951steps: 2413952},13953day: {13954common: true,13955size: 86400000,13956steps: 3013957},13958week: {13959common: false,13960size: 604800000,13961steps: 413962},13963month: {13964common: true,13965size: 2.628e9,13966steps: 1213967},13968quarter: {13969common: false,13970size: 7.884e9,13971steps: 413972},13973year: {13974common: true,13975size: 3.154e1013976}13977};1397813979var UNITS = Object.keys(INTERVALS);1398013981function sorter(a, b) {13982return a - b;13983}1398413985function arrayUnique(items) {13986var hash = {};13987var out = [];13988var i, ilen, item;1398913990for (i = 0, ilen = items.length; i < ilen; ++i) {13991item = items[i];13992if (!hash[item]) {13993hash[item] = true;13994out.push(item);13995}13996}1399713998return out;13999}1400014001function getMin(options) {14002return helpers$1.valueOrDefault(options.time.min, options.ticks.min);14003}1400414005function getMax(options) {14006return helpers$1.valueOrDefault(options.time.max, options.ticks.max);14007}1400814009/**14010* Returns an array of {time, pos} objects used to interpolate a specific `time` or position14011* (`pos`) on the scale, by searching entries before and after the requested value. `pos` is14012* a decimal between 0 and 1: 0 being the start of the scale (left or top) and 1 the other14013* extremity (left + width or top + height). Note that it would be more optimized to directly14014* store pre-computed pixels, but the scale dimensions are not guaranteed at the time we need14015* to create the lookup table. The table ALWAYS contains at least two items: min and max.14016*14017* @param {number[]} timestamps - timestamps sorted from lowest to highest.14018* @param {string} distribution - If 'linear', timestamps will be spread linearly along the min14019* and max range, so basically, the table will contains only two items: {min, 0} and {max, 1}.14020* If 'series', timestamps will be positioned at the same distance from each other. In this14021* case, only timestamps that break the time linearity are registered, meaning that in the14022* best case, all timestamps are linear, the table contains only min and max.14023*/14024function buildLookupTable(timestamps, min, max, distribution) {14025if (distribution === 'linear' || !timestamps.length) {14026return [14027{time: min, pos: 0},14028{time: max, pos: 1}14029];14030}1403114032var table = [];14033var items = [min];14034var i, ilen, prev, curr, next;1403514036for (i = 0, ilen = timestamps.length; i < ilen; ++i) {14037curr = timestamps[i];14038if (curr > min && curr < max) {14039items.push(curr);14040}14041}1404214043items.push(max);1404414045for (i = 0, ilen = items.length; i < ilen; ++i) {14046next = items[i + 1];14047prev = items[i - 1];14048curr = items[i];1404914050// only add points that breaks the scale linearity14051if (prev === undefined || next === undefined || Math.round((next + prev) / 2) !== curr) {14052table.push({time: curr, pos: i / (ilen - 1)});14053}14054}1405514056return table;14057}1405814059// @see adapted from https://www.anujgakhar.com/2014/03/01/binary-search-in-javascript/14060function lookup(table, key, value) {14061var lo = 0;14062var hi = table.length - 1;14063var mid, i0, i1;1406414065while (lo >= 0 && lo <= hi) {14066mid = (lo + hi) >> 1;14067i0 = table[mid - 1] || null;14068i1 = table[mid];1406914070if (!i0) {14071// given value is outside table (before first item)14072return {lo: null, hi: i1};14073} else if (i1[key] < value) {14074lo = mid + 1;14075} else if (i0[key] > value) {14076hi = mid - 1;14077} else {14078return {lo: i0, hi: i1};14079}14080}1408114082// given value is outside table (after last item)14083return {lo: i1, hi: null};14084}1408514086/**14087* Linearly interpolates the given source `value` using the table items `skey` values and14088* returns the associated `tkey` value. For example, interpolate(table, 'time', 42, 'pos')14089* returns the position for a timestamp equal to 42. If value is out of bounds, values at14090* index [0, 1] or [n - 1, n] are used for the interpolation.14091*/14092function interpolate$1(table, skey, sval, tkey) {14093var range = lookup(table, skey, sval);1409414095// Note: the lookup table ALWAYS contains at least 2 items (min and max)14096var prev = !range.lo ? table[0] : !range.hi ? table[table.length - 2] : range.lo;14097var next = !range.lo ? table[1] : !range.hi ? table[table.length - 1] : range.hi;1409814099var span = next[skey] - prev[skey];14100var ratio = span ? (sval - prev[skey]) / span : 0;14101var offset = (next[tkey] - prev[tkey]) * ratio;1410214103return prev[tkey] + offset;14104}1410514106function toTimestamp(scale, input) {14107var adapter = scale._adapter;14108var options = scale.options.time;14109var parser = options.parser;14110var format = parser || options.format;14111var value = input;1411214113if (typeof parser === 'function') {14114value = parser(value);14115}1411614117// Only parse if its not a timestamp already14118if (!helpers$1.isFinite(value)) {14119value = typeof format === 'string'14120? adapter.parse(value, format)14121: adapter.parse(value);14122}1412314124if (value !== null) {14125return +value;14126}1412714128// Labels are in an incompatible format and no `parser` has been provided.14129// The user might still use the deprecated `format` option for parsing.14130if (!parser && typeof format === 'function') {14131value = format(input);1413214133// `format` could return something else than a timestamp, if so, parse it14134if (!helpers$1.isFinite(value)) {14135value = adapter.parse(value);14136}14137}1413814139return value;14140}1414114142function parse(scale, input) {14143if (helpers$1.isNullOrUndef(input)) {14144return null;14145}1414614147var options = scale.options.time;14148var value = toTimestamp(scale, scale.getRightValue(input));14149if (value === null) {14150return value;14151}1415214153if (options.round) {14154value = +scale._adapter.startOf(value, options.round);14155}1415614157return value;14158}1415914160/**14161* Figures out what unit results in an appropriate number of auto-generated ticks14162*/14163function determineUnitForAutoTicks(minUnit, min, max, capacity) {14164var ilen = UNITS.length;14165var i, interval, factor;1416614167for (i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {14168interval = INTERVALS[UNITS[i]];14169factor = interval.steps ? interval.steps : MAX_INTEGER;1417014171if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {14172return UNITS[i];14173}14174}1417514176return UNITS[ilen - 1];14177}1417814179/**14180* Figures out what unit to format a set of ticks with14181*/14182function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {14183var i, unit;1418414185for (i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {14186unit = UNITS[i];14187if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {14188return unit;14189}14190}1419114192return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];14193}1419414195function determineMajorUnit(unit) {14196for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {14197if (INTERVALS[UNITS[i]].common) {14198return UNITS[i];14199}14200}14201}1420214203/**14204* Generates a maximum of `capacity` timestamps between min and max, rounded to the14205* `minor` unit using the given scale time `options`.14206* Important: this method can return ticks outside the min and max range, it's the14207* responsibility of the calling code to clamp values if needed.14208*/14209function generate(scale, min, max, capacity) {14210var adapter = scale._adapter;14211var options = scale.options;14212var timeOpts = options.time;14213var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, capacity);14214var stepSize = resolve$5([timeOpts.stepSize, timeOpts.unitStepSize, 1]);14215var weekday = minor === 'week' ? timeOpts.isoWeekday : false;14216var first = min;14217var ticks = [];14218var time;1421914220// For 'week' unit, handle the first day of week option14221if (weekday) {14222first = +adapter.startOf(first, 'isoWeek', weekday);14223}1422414225// Align first ticks on unit14226first = +adapter.startOf(first, weekday ? 'day' : minor);1422714228// Prevent browser from freezing in case user options request millions of milliseconds14229if (adapter.diff(max, min, minor) > 100000 * stepSize) {14230throw min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor;14231}1423214233for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) {14234ticks.push(time);14235}1423614237if (time === max || options.bounds === 'ticks') {14238ticks.push(time);14239}1424014241return ticks;14242}1424314244/**14245* Returns the start and end offsets from edges in the form of {start, end}14246* where each value is a relative width to the scale and ranges between 0 and 1.14247* They add extra margins on the both sides by scaling down the original scale.14248* Offsets are added when the `offset` option is true.14249*/14250function computeOffsets(table, ticks, min, max, options) {14251var start = 0;14252var end = 0;14253var first, last;1425414255if (options.offset && ticks.length) {14256first = interpolate$1(table, 'time', ticks[0], 'pos');14257if (ticks.length === 1) {14258start = 1 - first;14259} else {14260start = (interpolate$1(table, 'time', ticks[1], 'pos') - first) / 2;14261}14262last = interpolate$1(table, 'time', ticks[ticks.length - 1], 'pos');14263if (ticks.length === 1) {14264end = last;14265} else {14266end = (last - interpolate$1(table, 'time', ticks[ticks.length - 2], 'pos')) / 2;14267}14268}1426914270return {start: start, end: end, factor: 1 / (start + 1 + end)};14271}1427214273function setMajorTicks(scale, ticks, map, majorUnit) {14274var adapter = scale._adapter;14275var first = +adapter.startOf(ticks[0].value, majorUnit);14276var last = ticks[ticks.length - 1].value;14277var major, index;1427814279for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {14280index = map[major];14281if (index >= 0) {14282ticks[index].major = true;14283}14284}14285return ticks;14286}1428714288function ticksFromTimestamps(scale, values, majorUnit) {14289var ticks = [];14290var map = {};14291var ilen = values.length;14292var i, value;1429314294for (i = 0; i < ilen; ++i) {14295value = values[i];14296map[value] = i;1429714298ticks.push({14299value: value,14300major: false14301});14302}1430314304// We set the major ticks separately from the above loop because calling startOf for every tick14305// is expensive when there is a large number of ticks14306return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);14307}1430814309var defaultConfig$4 = {14310position: 'bottom',1431114312/**14313* Data distribution along the scale:14314* - 'linear': data are spread according to their time (distances can vary),14315* - 'series': data are spread at the same distance from each other.14316* @see https://github.com/chartjs/Chart.js/pull/450714317* @since 2.7.014318*/14319distribution: 'linear',1432014321/**14322* Scale boundary strategy (bypassed by min/max time options)14323* - `data`: make sure data are fully visible, ticks outside are removed14324* - `ticks`: make sure ticks are fully visible, data outside are truncated14325* @see https://github.com/chartjs/Chart.js/pull/455614326* @since 2.7.014327*/14328bounds: 'data',1432914330adapters: {},14331time: {14332parser: false, // false == a pattern string from https://momentjs.com/docs/#/parsing/string-format/ or a custom callback that converts its argument to a moment14333unit: false, // false == automatic or override with week, month, year, etc.14334round: false, // none, or override with week, month, year, etc.14335displayFormat: false, // DEPRECATED14336isoWeekday: false, // override week start day - see https://momentjs.com/docs/#/get-set/iso-weekday/14337minUnit: 'millisecond',14338displayFormats: {}14339},14340ticks: {14341autoSkip: false,1434214343/**14344* Ticks generation input values:14345* - 'auto': generates "optimal" ticks based on scale size and time options.14346* - 'data': generates ticks from data (including labels from data {t|x|y} objects).14347* - 'labels': generates ticks from user given `data.labels` values ONLY.14348* @see https://github.com/chartjs/Chart.js/pull/450714349* @since 2.7.014350*/14351source: 'auto',1435214353major: {14354enabled: false14355}14356}14357};1435814359var scale_time = core_scale.extend({14360initialize: function() {14361this.mergeTicksOptions();14362core_scale.prototype.initialize.call(this);14363},1436414365update: function() {14366var me = this;14367var options = me.options;14368var time = options.time || (options.time = {});14369var adapter = me._adapter = new core_adapters._date(options.adapters.date);1437014371// DEPRECATIONS: output a message only one time per update14372deprecated$1('time scale', time.format, 'time.format', 'time.parser');14373deprecated$1('time scale', time.min, 'time.min', 'ticks.min');14374deprecated$1('time scale', time.max, 'time.max', 'ticks.max');1437514376// Backward compatibility: before introducing adapter, `displayFormats` was14377// supposed to contain *all* unit/string pairs but this can't be resolved14378// when loading the scale (adapters are loaded afterward), so let's populate14379// missing formats on update14380helpers$1.mergeIf(time.displayFormats, adapter.formats());1438114382return core_scale.prototype.update.apply(me, arguments);14383},1438414385/**14386* Allows data to be referenced via 't' attribute14387*/14388getRightValue: function(rawValue) {14389if (rawValue && rawValue.t !== undefined) {14390rawValue = rawValue.t;14391}14392return core_scale.prototype.getRightValue.call(this, rawValue);14393},1439414395determineDataLimits: function() {14396var me = this;14397var chart = me.chart;14398var adapter = me._adapter;14399var options = me.options;14400var unit = options.time.unit || 'day';14401var min = MAX_INTEGER;14402var max = MIN_INTEGER;14403var timestamps = [];14404var datasets = [];14405var labels = [];14406var i, j, ilen, jlen, data, timestamp, labelsAdded;14407var dataLabels = me._getLabels();1440814409for (i = 0, ilen = dataLabels.length; i < ilen; ++i) {14410labels.push(parse(me, dataLabels[i]));14411}1441214413for (i = 0, ilen = (chart.data.datasets || []).length; i < ilen; ++i) {14414if (chart.isDatasetVisible(i)) {14415data = chart.data.datasets[i].data;1441614417// Let's consider that all data have the same format.14418if (helpers$1.isObject(data[0])) {14419datasets[i] = [];1442014421for (j = 0, jlen = data.length; j < jlen; ++j) {14422timestamp = parse(me, data[j]);14423timestamps.push(timestamp);14424datasets[i][j] = timestamp;14425}14426} else {14427datasets[i] = labels.slice(0);14428if (!labelsAdded) {14429timestamps = timestamps.concat(labels);14430labelsAdded = true;14431}14432}14433} else {14434datasets[i] = [];14435}14436}1443714438if (labels.length) {14439min = Math.min(min, labels[0]);14440max = Math.max(max, labels[labels.length - 1]);14441}1444214443if (timestamps.length) {14444timestamps = ilen > 1 ? arrayUnique(timestamps).sort(sorter) : timestamps.sort(sorter);14445min = Math.min(min, timestamps[0]);14446max = Math.max(max, timestamps[timestamps.length - 1]);14447}1444814449min = parse(me, getMin(options)) || min;14450max = parse(me, getMax(options)) || max;1445114452// In case there is no valid min/max, set limits based on unit time option14453min = min === MAX_INTEGER ? +adapter.startOf(Date.now(), unit) : min;14454max = max === MIN_INTEGER ? +adapter.endOf(Date.now(), unit) + 1 : max;1445514456// Make sure that max is strictly higher than min (required by the lookup table)14457me.min = Math.min(min, max);14458me.max = Math.max(min + 1, max);1445914460// PRIVATE14461me._table = [];14462me._timestamps = {14463data: timestamps,14464datasets: datasets,14465labels: labels14466};14467},1446814469buildTicks: function() {14470var me = this;14471var min = me.min;14472var max = me.max;14473var options = me.options;14474var tickOpts = options.ticks;14475var timeOpts = options.time;14476var timestamps = me._timestamps;14477var ticks = [];14478var capacity = me.getLabelCapacity(min);14479var source = tickOpts.source;14480var distribution = options.distribution;14481var i, ilen, timestamp;1448214483if (source === 'data' || (source === 'auto' && distribution === 'series')) {14484timestamps = timestamps.data;14485} else if (source === 'labels') {14486timestamps = timestamps.labels;14487} else {14488timestamps = generate(me, min, max, capacity);14489}1449014491if (options.bounds === 'ticks' && timestamps.length) {14492min = timestamps[0];14493max = timestamps[timestamps.length - 1];14494}1449514496// Enforce limits with user min/max options14497min = parse(me, getMin(options)) || min;14498max = parse(me, getMax(options)) || max;1449914500// Remove ticks outside the min/max range14501for (i = 0, ilen = timestamps.length; i < ilen; ++i) {14502timestamp = timestamps[i];14503if (timestamp >= min && timestamp <= max) {14504ticks.push(timestamp);14505}14506}1450714508me.min = min;14509me.max = max;1451014511// PRIVATE14512// determineUnitForFormatting relies on the number of ticks so we don't use it when14513// autoSkip is enabled because we don't yet know what the final number of ticks will be14514me._unit = timeOpts.unit || (tickOpts.autoSkip14515? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, capacity)14516: determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max));14517me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined14518: determineMajorUnit(me._unit);14519me._table = buildLookupTable(me._timestamps.data, min, max, distribution);14520me._offsets = computeOffsets(me._table, ticks, min, max, options);1452114522if (tickOpts.reverse) {14523ticks.reverse();14524}1452514526return ticksFromTimestamps(me, ticks, me._majorUnit);14527},1452814529getLabelForIndex: function(index, datasetIndex) {14530var me = this;14531var adapter = me._adapter;14532var data = me.chart.data;14533var timeOpts = me.options.time;14534var label = data.labels && index < data.labels.length ? data.labels[index] : '';14535var value = data.datasets[datasetIndex].data[index];1453614537if (helpers$1.isObject(value)) {14538label = me.getRightValue(value);14539}14540if (timeOpts.tooltipFormat) {14541return adapter.format(toTimestamp(me, label), timeOpts.tooltipFormat);14542}14543if (typeof label === 'string') {14544return label;14545}14546return adapter.format(toTimestamp(me, label), timeOpts.displayFormats.datetime);14547},1454814549/**14550* Function to format an individual tick mark14551* @private14552*/14553tickFormatFunction: function(time, index, ticks, format) {14554var me = this;14555var adapter = me._adapter;14556var options = me.options;14557var formats = options.time.displayFormats;14558var minorFormat = formats[me._unit];14559var majorUnit = me._majorUnit;14560var majorFormat = formats[majorUnit];14561var tick = ticks[index];14562var tickOpts = options.ticks;14563var major = majorUnit && majorFormat && tick && tick.major;14564var label = adapter.format(time, format ? format : major ? majorFormat : minorFormat);14565var nestedTickOpts = major ? tickOpts.major : tickOpts.minor;14566var formatter = resolve$5([14567nestedTickOpts.callback,14568nestedTickOpts.userCallback,14569tickOpts.callback,14570tickOpts.userCallback14571]);1457214573return formatter ? formatter(label, index, ticks) : label;14574},1457514576convertTicksToLabels: function(ticks) {14577var labels = [];14578var i, ilen;1457914580for (i = 0, ilen = ticks.length; i < ilen; ++i) {14581labels.push(this.tickFormatFunction(ticks[i].value, i, ticks));14582}1458314584return labels;14585},1458614587/**14588* @private14589*/14590getPixelForOffset: function(time) {14591var me = this;14592var offsets = me._offsets;14593var pos = interpolate$1(me._table, 'time', time, 'pos');14594return me.getPixelForDecimal((offsets.start + pos) * offsets.factor);14595},1459614597getPixelForValue: function(value, index, datasetIndex) {14598var me = this;14599var time = null;1460014601if (index !== undefined && datasetIndex !== undefined) {14602time = me._timestamps.datasets[datasetIndex][index];14603}1460414605if (time === null) {14606time = parse(me, value);14607}1460814609if (time !== null) {14610return me.getPixelForOffset(time);14611}14612},1461314614getPixelForTick: function(index) {14615var ticks = this.getTicks();14616return index >= 0 && index < ticks.length ?14617this.getPixelForOffset(ticks[index].value) :14618null;14619},1462014621getValueForPixel: function(pixel) {14622var me = this;14623var offsets = me._offsets;14624var pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end;14625var time = interpolate$1(me._table, 'pos', pos, 'time');1462614627// DEPRECATION, we should return time directly14628return me._adapter._create(time);14629},1463014631/**14632* @private14633*/14634_getLabelSize: function(label) {14635var me = this;14636var ticksOpts = me.options.ticks;14637var tickLabelWidth = me.ctx.measureText(label).width;14638var angle = helpers$1.toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);14639var cosRotation = Math.cos(angle);14640var sinRotation = Math.sin(angle);14641var tickFontSize = valueOrDefault$d(ticksOpts.fontSize, core_defaults.global.defaultFontSize);1464214643return {14644w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),14645h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)14646};14647},1464814649/**14650* Crude approximation of what the label width might be14651* @private14652*/14653getLabelWidth: function(label) {14654return this._getLabelSize(label).w;14655},1465614657/**14658* @private14659*/14660getLabelCapacity: function(exampleTime) {14661var me = this;14662var timeOpts = me.options.time;14663var displayFormats = timeOpts.displayFormats;1466414665// pick the longest format (milliseconds) for guestimation14666var format = displayFormats[timeOpts.unit] || displayFormats.millisecond;14667var exampleLabel = me.tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format);14668var size = me._getLabelSize(exampleLabel);14669var capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h);1467014671if (me.options.offset) {14672capacity--;14673}1467414675return capacity > 0 ? capacity : 1;14676}14677});1467814679// INTERNAL: static default options, registered in src/index.js14680var _defaults$4 = defaultConfig$4;14681scale_time._defaults = _defaults$4;1468214683var scales = {14684category: scale_category,14685linear: scale_linear,14686logarithmic: scale_logarithmic,14687radialLinear: scale_radialLinear,14688time: scale_time14689};1469014691var moment = createCommonjsModule(function (module, exports) {14692(function (global, factory) {14693module.exports = factory() ;14694}(commonjsGlobal, (function () {14695var hookCallback;1469614697function hooks () {14698return hookCallback.apply(null, arguments);14699}1470014701// This is done to register the method called with moment()14702// without creating circular dependencies.14703function setHookCallback (callback) {14704hookCallback = callback;14705}1470614707function isArray(input) {14708return input instanceof Array || Object.prototype.toString.call(input) === '[object Array]';14709}1471014711function isObject(input) {14712// IE8 will treat undefined and null as object if it wasn't for14713// input != null14714return input != null && Object.prototype.toString.call(input) === '[object Object]';14715}1471614717function isObjectEmpty(obj) {14718if (Object.getOwnPropertyNames) {14719return (Object.getOwnPropertyNames(obj).length === 0);14720} else {14721var k;14722for (k in obj) {14723if (obj.hasOwnProperty(k)) {14724return false;14725}14726}14727return true;14728}14729}1473014731function isUndefined(input) {14732return input === void 0;14733}1473414735function isNumber(input) {14736return typeof input === 'number' || Object.prototype.toString.call(input) === '[object Number]';14737}1473814739function isDate(input) {14740return input instanceof Date || Object.prototype.toString.call(input) === '[object Date]';14741}1474214743function map(arr, fn) {14744var res = [], i;14745for (i = 0; i < arr.length; ++i) {14746res.push(fn(arr[i], i));14747}14748return res;14749}1475014751function hasOwnProp(a, b) {14752return Object.prototype.hasOwnProperty.call(a, b);14753}1475414755function extend(a, b) {14756for (var i in b) {14757if (hasOwnProp(b, i)) {14758a[i] = b[i];14759}14760}1476114762if (hasOwnProp(b, 'toString')) {14763a.toString = b.toString;14764}1476514766if (hasOwnProp(b, 'valueOf')) {14767a.valueOf = b.valueOf;14768}1476914770return a;14771}1477214773function createUTC (input, format, locale, strict) {14774return createLocalOrUTC(input, format, locale, strict, true).utc();14775}1477614777function defaultParsingFlags() {14778// We need to deep clone this object.14779return {14780empty : false,14781unusedTokens : [],14782unusedInput : [],14783overflow : -2,14784charsLeftOver : 0,14785nullInput : false,14786invalidMonth : null,14787invalidFormat : false,14788userInvalidated : false,14789iso : false,14790parsedDateParts : [],14791meridiem : null,14792rfc2822 : false,14793weekdayMismatch : false14794};14795}1479614797function getParsingFlags(m) {14798if (m._pf == null) {14799m._pf = defaultParsingFlags();14800}14801return m._pf;14802}1480314804var some;14805if (Array.prototype.some) {14806some = Array.prototype.some;14807} else {14808some = function (fun) {14809var t = Object(this);14810var len = t.length >>> 0;1481114812for (var i = 0; i < len; i++) {14813if (i in t && fun.call(this, t[i], i, t)) {14814return true;14815}14816}1481714818return false;14819};14820}1482114822function isValid(m) {14823if (m._isValid == null) {14824var flags = getParsingFlags(m);14825var parsedParts = some.call(flags.parsedDateParts, function (i) {14826return i != null;14827});14828var isNowValid = !isNaN(m._d.getTime()) &&14829flags.overflow < 0 &&14830!flags.empty &&14831!flags.invalidMonth &&14832!flags.invalidWeekday &&14833!flags.weekdayMismatch &&14834!flags.nullInput &&14835!flags.invalidFormat &&14836!flags.userInvalidated &&14837(!flags.meridiem || (flags.meridiem && parsedParts));1483814839if (m._strict) {14840isNowValid = isNowValid &&14841flags.charsLeftOver === 0 &&14842flags.unusedTokens.length === 0 &&14843flags.bigHour === undefined;14844}1484514846if (Object.isFrozen == null || !Object.isFrozen(m)) {14847m._isValid = isNowValid;14848}14849else {14850return isNowValid;14851}14852}14853return m._isValid;14854}1485514856function createInvalid (flags) {14857var m = createUTC(NaN);14858if (flags != null) {14859extend(getParsingFlags(m), flags);14860}14861else {14862getParsingFlags(m).userInvalidated = true;14863}1486414865return m;14866}1486714868// Plugins that add properties should also add the key here (null value),14869// so we can properly clone ourselves.14870var momentProperties = hooks.momentProperties = [];1487114872function copyConfig(to, from) {14873var i, prop, val;1487414875if (!isUndefined(from._isAMomentObject)) {14876to._isAMomentObject = from._isAMomentObject;14877}14878if (!isUndefined(from._i)) {14879to._i = from._i;14880}14881if (!isUndefined(from._f)) {14882to._f = from._f;14883}14884if (!isUndefined(from._l)) {14885to._l = from._l;14886}14887if (!isUndefined(from._strict)) {14888to._strict = from._strict;14889}14890if (!isUndefined(from._tzm)) {14891to._tzm = from._tzm;14892}14893if (!isUndefined(from._isUTC)) {14894to._isUTC = from._isUTC;14895}14896if (!isUndefined(from._offset)) {14897to._offset = from._offset;14898}14899if (!isUndefined(from._pf)) {14900to._pf = getParsingFlags(from);14901}14902if (!isUndefined(from._locale)) {14903to._locale = from._locale;14904}1490514906if (momentProperties.length > 0) {14907for (i = 0; i < momentProperties.length; i++) {14908prop = momentProperties[i];14909val = from[prop];14910if (!isUndefined(val)) {14911to[prop] = val;14912}14913}14914}1491514916return to;14917}1491814919var updateInProgress = false;1492014921// Moment prototype object14922function Moment(config) {14923copyConfig(this, config);14924this._d = new Date(config._d != null ? config._d.getTime() : NaN);14925if (!this.isValid()) {14926this._d = new Date(NaN);14927}14928// Prevent infinite loop in case updateOffset creates new moment14929// objects.14930if (updateInProgress === false) {14931updateInProgress = true;14932hooks.updateOffset(this);14933updateInProgress = false;14934}14935}1493614937function isMoment (obj) {14938return obj instanceof Moment || (obj != null && obj._isAMomentObject != null);14939}1494014941function absFloor (number) {14942if (number < 0) {14943// -0 -> 014944return Math.ceil(number) || 0;14945} else {14946return Math.floor(number);14947}14948}1494914950function toInt(argumentForCoercion) {14951var coercedNumber = +argumentForCoercion,14952value = 0;1495314954if (coercedNumber !== 0 && isFinite(coercedNumber)) {14955value = absFloor(coercedNumber);14956}1495714958return value;14959}1496014961// compare two arrays, return the number of differences14962function compareArrays(array1, array2, dontConvert) {14963var len = Math.min(array1.length, array2.length),14964lengthDiff = Math.abs(array1.length - array2.length),14965diffs = 0,14966i;14967for (i = 0; i < len; i++) {14968if ((dontConvert && array1[i] !== array2[i]) ||14969(!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) {14970diffs++;14971}14972}14973return diffs + lengthDiff;14974}1497514976function warn(msg) {14977if (hooks.suppressDeprecationWarnings === false &&14978(typeof console !== 'undefined') && console.warn) {14979console.warn('Deprecation warning: ' + msg);14980}14981}1498214983function deprecate(msg, fn) {14984var firstTime = true;1498514986return extend(function () {14987if (hooks.deprecationHandler != null) {14988hooks.deprecationHandler(null, msg);14989}14990if (firstTime) {14991var args = [];14992var arg;14993for (var i = 0; i < arguments.length; i++) {14994arg = '';14995if (typeof arguments[i] === 'object') {14996arg += '\n[' + i + '] ';14997for (var key in arguments[0]) {14998arg += key + ': ' + arguments[0][key] + ', ';14999}15000arg = arg.slice(0, -2); // Remove trailing comma and space15001} else {15002arg = arguments[i];15003}15004args.push(arg);15005}15006warn(msg + '\nArguments: ' + Array.prototype.slice.call(args).join('') + '\n' + (new Error()).stack);15007firstTime = false;15008}15009return fn.apply(this, arguments);15010}, fn);15011}1501215013var deprecations = {};1501415015function deprecateSimple(name, msg) {15016if (hooks.deprecationHandler != null) {15017hooks.deprecationHandler(name, msg);15018}15019if (!deprecations[name]) {15020warn(msg);15021deprecations[name] = true;15022}15023}1502415025hooks.suppressDeprecationWarnings = false;15026hooks.deprecationHandler = null;1502715028function isFunction(input) {15029return input instanceof Function || Object.prototype.toString.call(input) === '[object Function]';15030}1503115032function set (config) {15033var prop, i;15034for (i in config) {15035prop = config[i];15036if (isFunction(prop)) {15037this[i] = prop;15038} else {15039this['_' + i] = prop;15040}15041}15042this._config = config;15043// Lenient ordinal parsing accepts just a number in addition to15044// number + (possibly) stuff coming from _dayOfMonthOrdinalParse.15045// TODO: Remove "ordinalParse" fallback in next major release.15046this._dayOfMonthOrdinalParseLenient = new RegExp(15047(this._dayOfMonthOrdinalParse.source || this._ordinalParse.source) +15048'|' + (/\d{1,2}/).source);15049}1505015051function mergeConfigs(parentConfig, childConfig) {15052var res = extend({}, parentConfig), prop;15053for (prop in childConfig) {15054if (hasOwnProp(childConfig, prop)) {15055if (isObject(parentConfig[prop]) && isObject(childConfig[prop])) {15056res[prop] = {};15057extend(res[prop], parentConfig[prop]);15058extend(res[prop], childConfig[prop]);15059} else if (childConfig[prop] != null) {15060res[prop] = childConfig[prop];15061} else {15062delete res[prop];15063}15064}15065}15066for (prop in parentConfig) {15067if (hasOwnProp(parentConfig, prop) &&15068!hasOwnProp(childConfig, prop) &&15069isObject(parentConfig[prop])) {15070// make sure changes to properties don't modify parent config15071res[prop] = extend({}, res[prop]);15072}15073}15074return res;15075}1507615077function Locale(config) {15078if (config != null) {15079this.set(config);15080}15081}1508215083var keys;1508415085if (Object.keys) {15086keys = Object.keys;15087} else {15088keys = function (obj) {15089var i, res = [];15090for (i in obj) {15091if (hasOwnProp(obj, i)) {15092res.push(i);15093}15094}15095return res;15096};15097}1509815099var defaultCalendar = {15100sameDay : '[Today at] LT',15101nextDay : '[Tomorrow at] LT',15102nextWeek : 'dddd [at] LT',15103lastDay : '[Yesterday at] LT',15104lastWeek : '[Last] dddd [at] LT',15105sameElse : 'L'15106};1510715108function calendar (key, mom, now) {15109var output = this._calendar[key] || this._calendar['sameElse'];15110return isFunction(output) ? output.call(mom, now) : output;15111}1511215113var defaultLongDateFormat = {15114LTS : 'h:mm:ss A',15115LT : 'h:mm A',15116L : 'MM/DD/YYYY',15117LL : 'MMMM D, YYYY',15118LLL : 'MMMM D, YYYY h:mm A',15119LLLL : 'dddd, MMMM D, YYYY h:mm A'15120};1512115122function longDateFormat (key) {15123var format = this._longDateFormat[key],15124formatUpper = this._longDateFormat[key.toUpperCase()];1512515126if (format || !formatUpper) {15127return format;15128}1512915130this._longDateFormat[key] = formatUpper.replace(/MMMM|MM|DD|dddd/g, function (val) {15131return val.slice(1);15132});1513315134return this._longDateFormat[key];15135}1513615137var defaultInvalidDate = 'Invalid date';1513815139function invalidDate () {15140return this._invalidDate;15141}1514215143var defaultOrdinal = '%d';15144var defaultDayOfMonthOrdinalParse = /\d{1,2}/;1514515146function ordinal (number) {15147return this._ordinal.replace('%d', number);15148}1514915150var defaultRelativeTime = {15151future : 'in %s',15152past : '%s ago',15153s : 'a few seconds',15154ss : '%d seconds',15155m : 'a minute',15156mm : '%d minutes',15157h : 'an hour',15158hh : '%d hours',15159d : 'a day',15160dd : '%d days',15161M : 'a month',15162MM : '%d months',15163y : 'a year',15164yy : '%d years'15165};1516615167function relativeTime (number, withoutSuffix, string, isFuture) {15168var output = this._relativeTime[string];15169return (isFunction(output)) ?15170output(number, withoutSuffix, string, isFuture) :15171output.replace(/%d/i, number);15172}1517315174function pastFuture (diff, output) {15175var format = this._relativeTime[diff > 0 ? 'future' : 'past'];15176return isFunction(format) ? format(output) : format.replace(/%s/i, output);15177}1517815179var aliases = {};1518015181function addUnitAlias (unit, shorthand) {15182var lowerCase = unit.toLowerCase();15183aliases[lowerCase] = aliases[lowerCase + 's'] = aliases[shorthand] = unit;15184}1518515186function normalizeUnits(units) {15187return typeof units === 'string' ? aliases[units] || aliases[units.toLowerCase()] : undefined;15188}1518915190function normalizeObjectUnits(inputObject) {15191var normalizedInput = {},15192normalizedProp,15193prop;1519415195for (prop in inputObject) {15196if (hasOwnProp(inputObject, prop)) {15197normalizedProp = normalizeUnits(prop);15198if (normalizedProp) {15199normalizedInput[normalizedProp] = inputObject[prop];15200}15201}15202}1520315204return normalizedInput;15205}1520615207var priorities = {};1520815209function addUnitPriority(unit, priority) {15210priorities[unit] = priority;15211}1521215213function getPrioritizedUnits(unitsObj) {15214var units = [];15215for (var u in unitsObj) {15216units.push({unit: u, priority: priorities[u]});15217}15218units.sort(function (a, b) {15219return a.priority - b.priority;15220});15221return units;15222}1522315224function zeroFill(number, targetLength, forceSign) {15225var absNumber = '' + Math.abs(number),15226zerosToFill = targetLength - absNumber.length,15227sign = number >= 0;15228return (sign ? (forceSign ? '+' : '') : '-') +15229Math.pow(10, Math.max(0, zerosToFill)).toString().substr(1) + absNumber;15230}1523115232var 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;1523315234var localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g;1523515236var formatFunctions = {};1523715238var formatTokenFunctions = {};1523915240// token: 'M'15241// padded: ['MM', 2]15242// ordinal: 'Mo'15243// callback: function () { this.month() + 1 }15244function addFormatToken (token, padded, ordinal, callback) {15245var func = callback;15246if (typeof callback === 'string') {15247func = function () {15248return this[callback]();15249};15250}15251if (token) {15252formatTokenFunctions[token] = func;15253}15254if (padded) {15255formatTokenFunctions[padded[0]] = function () {15256return zeroFill(func.apply(this, arguments), padded[1], padded[2]);15257};15258}15259if (ordinal) {15260formatTokenFunctions[ordinal] = function () {15261return this.localeData().ordinal(func.apply(this, arguments), token);15262};15263}15264}1526515266function removeFormattingTokens(input) {15267if (input.match(/\[[\s\S]/)) {15268return input.replace(/^\[|\]$/g, '');15269}15270return input.replace(/\\/g, '');15271}1527215273function makeFormatFunction(format) {15274var array = format.match(formattingTokens), i, length;1527515276for (i = 0, length = array.length; i < length; i++) {15277if (formatTokenFunctions[array[i]]) {15278array[i] = formatTokenFunctions[array[i]];15279} else {15280array[i] = removeFormattingTokens(array[i]);15281}15282}1528315284return function (mom) {15285var output = '', i;15286for (i = 0; i < length; i++) {15287output += isFunction(array[i]) ? array[i].call(mom, format) : array[i];15288}15289return output;15290};15291}1529215293// format date using native date object15294function formatMoment(m, format) {15295if (!m.isValid()) {15296return m.localeData().invalidDate();15297}1529815299format = expandFormat(format, m.localeData());15300formatFunctions[format] = formatFunctions[format] || makeFormatFunction(format);1530115302return formatFunctions[format](m);15303}1530415305function expandFormat(format, locale) {15306var i = 5;1530715308function replaceLongDateFormatTokens(input) {15309return locale.longDateFormat(input) || input;15310}1531115312localFormattingTokens.lastIndex = 0;15313while (i >= 0 && localFormattingTokens.test(format)) {15314format = format.replace(localFormattingTokens, replaceLongDateFormatTokens);15315localFormattingTokens.lastIndex = 0;15316i -= 1;15317}1531815319return format;15320}1532115322var match1 = /\d/; // 0 - 915323var match2 = /\d\d/; // 00 - 9915324var match3 = /\d{3}/; // 000 - 99915325var match4 = /\d{4}/; // 0000 - 999915326var match6 = /[+-]?\d{6}/; // -999999 - 99999915327var match1to2 = /\d\d?/; // 0 - 9915328var match3to4 = /\d\d\d\d?/; // 999 - 999915329var match5to6 = /\d\d\d\d\d\d?/; // 99999 - 99999915330var match1to3 = /\d{1,3}/; // 0 - 99915331var match1to4 = /\d{1,4}/; // 0 - 999915332var match1to6 = /[+-]?\d{1,6}/; // -999999 - 9999991533315334var matchUnsigned = /\d+/; // 0 - inf15335var matchSigned = /[+-]?\d+/; // -inf - inf1533615337var matchOffset = /Z|[+-]\d\d:?\d\d/gi; // +00:00 -00:00 +0000 -0000 or Z15338var matchShortOffset = /Z|[+-]\d\d(?::?\d\d)?/gi; // +00 -00 +00:00 -00:00 +0000 -0000 or Z1533915340var matchTimestamp = /[+-]?\d+(\.\d{1,3})?/; // 123456789 123456789.1231534115342// any word (or two) characters or numbers including two/three word month in arabic.15343// includes scottish gaelic two word and hyphenated months15344var matchWord = /[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;1534515346var regexes = {};1534715348function addRegexToken (token, regex, strictRegex) {15349regexes[token] = isFunction(regex) ? regex : function (isStrict, localeData) {15350return (isStrict && strictRegex) ? strictRegex : regex;15351};15352}1535315354function getParseRegexForToken (token, config) {15355if (!hasOwnProp(regexes, token)) {15356return new RegExp(unescapeFormat(token));15357}1535815359return regexes[token](config._strict, config._locale);15360}1536115362// Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript15363function unescapeFormat(s) {15364return regexEscape(s.replace('\\', '').replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) {15365return p1 || p2 || p3 || p4;15366}));15367}1536815369function regexEscape(s) {15370return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');15371}1537215373var tokens = {};1537415375function addParseToken (token, callback) {15376var i, func = callback;15377if (typeof token === 'string') {15378token = [token];15379}15380if (isNumber(callback)) {15381func = function (input, array) {15382array[callback] = toInt(input);15383};15384}15385for (i = 0; i < token.length; i++) {15386tokens[token[i]] = func;15387}15388}1538915390function addWeekParseToken (token, callback) {15391addParseToken(token, function (input, array, config, token) {15392config._w = config._w || {};15393callback(input, config._w, config, token);15394});15395}1539615397function addTimeToArrayFromToken(token, input, config) {15398if (input != null && hasOwnProp(tokens, token)) {15399tokens[token](input, config._a, config, token);15400}15401}1540215403var YEAR = 0;15404var MONTH = 1;15405var DATE = 2;15406var HOUR = 3;15407var MINUTE = 4;15408var SECOND = 5;15409var MILLISECOND = 6;15410var WEEK = 7;15411var WEEKDAY = 8;1541215413// FORMATTING1541415415addFormatToken('Y', 0, 0, function () {15416var y = this.year();15417return y <= 9999 ? '' + y : '+' + y;15418});1541915420addFormatToken(0, ['YY', 2], 0, function () {15421return this.year() % 100;15422});1542315424addFormatToken(0, ['YYYY', 4], 0, 'year');15425addFormatToken(0, ['YYYYY', 5], 0, 'year');15426addFormatToken(0, ['YYYYYY', 6, true], 0, 'year');1542715428// ALIASES1542915430addUnitAlias('year', 'y');1543115432// PRIORITIES1543315434addUnitPriority('year', 1);1543515436// PARSING1543715438addRegexToken('Y', matchSigned);15439addRegexToken('YY', match1to2, match2);15440addRegexToken('YYYY', match1to4, match4);15441addRegexToken('YYYYY', match1to6, match6);15442addRegexToken('YYYYYY', match1to6, match6);1544315444addParseToken(['YYYYY', 'YYYYYY'], YEAR);15445addParseToken('YYYY', function (input, array) {15446array[YEAR] = input.length === 2 ? hooks.parseTwoDigitYear(input) : toInt(input);15447});15448addParseToken('YY', function (input, array) {15449array[YEAR] = hooks.parseTwoDigitYear(input);15450});15451addParseToken('Y', function (input, array) {15452array[YEAR] = parseInt(input, 10);15453});1545415455// HELPERS1545615457function daysInYear(year) {15458return isLeapYear(year) ? 366 : 365;15459}1546015461function isLeapYear(year) {15462return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;15463}1546415465// HOOKS1546615467hooks.parseTwoDigitYear = function (input) {15468return toInt(input) + (toInt(input) > 68 ? 1900 : 2000);15469};1547015471// MOMENTS1547215473var getSetYear = makeGetSet('FullYear', true);1547415475function getIsLeapYear () {15476return isLeapYear(this.year());15477}1547815479function makeGetSet (unit, keepTime) {15480return function (value) {15481if (value != null) {15482set$1(this, unit, value);15483hooks.updateOffset(this, keepTime);15484return this;15485} else {15486return get(this, unit);15487}15488};15489}1549015491function get (mom, unit) {15492return mom.isValid() ?15493mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit]() : NaN;15494}1549515496function set$1 (mom, unit, value) {15497if (mom.isValid() && !isNaN(value)) {15498if (unit === 'FullYear' && isLeapYear(mom.year()) && mom.month() === 1 && mom.date() === 29) {15499mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value, mom.month(), daysInMonth(value, mom.month()));15500}15501else {15502mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value);15503}15504}15505}1550615507// MOMENTS1550815509function stringGet (units) {15510units = normalizeUnits(units);15511if (isFunction(this[units])) {15512return this[units]();15513}15514return this;15515}155161551715518function stringSet (units, value) {15519if (typeof units === 'object') {15520units = normalizeObjectUnits(units);15521var prioritized = getPrioritizedUnits(units);15522for (var i = 0; i < prioritized.length; i++) {15523this[prioritized[i].unit](units[prioritized[i].unit]);15524}15525} else {15526units = normalizeUnits(units);15527if (isFunction(this[units])) {15528return this[units](value);15529}15530}15531return this;15532}1553315534function mod(n, x) {15535return ((n % x) + x) % x;15536}1553715538var indexOf;1553915540if (Array.prototype.indexOf) {15541indexOf = Array.prototype.indexOf;15542} else {15543indexOf = function (o) {15544// I know15545var i;15546for (i = 0; i < this.length; ++i) {15547if (this[i] === o) {15548return i;15549}15550}15551return -1;15552};15553}1555415555function daysInMonth(year, month) {15556if (isNaN(year) || isNaN(month)) {15557return NaN;15558}15559var modMonth = mod(month, 12);15560year += (month - modMonth) / 12;15561return modMonth === 1 ? (isLeapYear(year) ? 29 : 28) : (31 - modMonth % 7 % 2);15562}1556315564// FORMATTING1556515566addFormatToken('M', ['MM', 2], 'Mo', function () {15567return this.month() + 1;15568});1556915570addFormatToken('MMM', 0, 0, function (format) {15571return this.localeData().monthsShort(this, format);15572});1557315574addFormatToken('MMMM', 0, 0, function (format) {15575return this.localeData().months(this, format);15576});1557715578// ALIASES1557915580addUnitAlias('month', 'M');1558115582// PRIORITY1558315584addUnitPriority('month', 8);1558515586// PARSING1558715588addRegexToken('M', match1to2);15589addRegexToken('MM', match1to2, match2);15590addRegexToken('MMM', function (isStrict, locale) {15591return locale.monthsShortRegex(isStrict);15592});15593addRegexToken('MMMM', function (isStrict, locale) {15594return locale.monthsRegex(isStrict);15595});1559615597addParseToken(['M', 'MM'], function (input, array) {15598array[MONTH] = toInt(input) - 1;15599});1560015601addParseToken(['MMM', 'MMMM'], function (input, array, config, token) {15602var month = config._locale.monthsParse(input, token, config._strict);15603// if we didn't find a month name, mark the date as invalid.15604if (month != null) {15605array[MONTH] = month;15606} else {15607getParsingFlags(config).invalidMonth = input;15608}15609});1561015611// LOCALES1561215613var MONTHS_IN_FORMAT = /D[oD]?(\[[^\[\]]*\]|\s)+MMMM?/;15614var defaultLocaleMonths = 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_');15615function localeMonths (m, format) {15616if (!m) {15617return isArray(this._months) ? this._months :15618this._months['standalone'];15619}15620return isArray(this._months) ? this._months[m.month()] :15621this._months[(this._months.isFormat || MONTHS_IN_FORMAT).test(format) ? 'format' : 'standalone'][m.month()];15622}1562315624var defaultLocaleMonthsShort = 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_');15625function localeMonthsShort (m, format) {15626if (!m) {15627return isArray(this._monthsShort) ? this._monthsShort :15628this._monthsShort['standalone'];15629}15630return isArray(this._monthsShort) ? this._monthsShort[m.month()] :15631this._monthsShort[MONTHS_IN_FORMAT.test(format) ? 'format' : 'standalone'][m.month()];15632}1563315634function handleStrictParse(monthName, format, strict) {15635var i, ii, mom, llc = monthName.toLocaleLowerCase();15636if (!this._monthsParse) {15637// this is not used15638this._monthsParse = [];15639this._longMonthsParse = [];15640this._shortMonthsParse = [];15641for (i = 0; i < 12; ++i) {15642mom = createUTC([2000, i]);15643this._shortMonthsParse[i] = this.monthsShort(mom, '').toLocaleLowerCase();15644this._longMonthsParse[i] = this.months(mom, '').toLocaleLowerCase();15645}15646}1564715648if (strict) {15649if (format === 'MMM') {15650ii = indexOf.call(this._shortMonthsParse, llc);15651return ii !== -1 ? ii : null;15652} else {15653ii = indexOf.call(this._longMonthsParse, llc);15654return ii !== -1 ? ii : null;15655}15656} else {15657if (format === 'MMM') {15658ii = indexOf.call(this._shortMonthsParse, llc);15659if (ii !== -1) {15660return ii;15661}15662ii = indexOf.call(this._longMonthsParse, llc);15663return ii !== -1 ? ii : null;15664} else {15665ii = indexOf.call(this._longMonthsParse, llc);15666if (ii !== -1) {15667return ii;15668}15669ii = indexOf.call(this._shortMonthsParse, llc);15670return ii !== -1 ? ii : null;15671}15672}15673}1567415675function localeMonthsParse (monthName, format, strict) {15676var i, mom, regex;1567715678if (this._monthsParseExact) {15679return handleStrictParse.call(this, monthName, format, strict);15680}1568115682if (!this._monthsParse) {15683this._monthsParse = [];15684this._longMonthsParse = [];15685this._shortMonthsParse = [];15686}1568715688// TODO: add sorting15689// Sorting makes sure if one month (or abbr) is a prefix of another15690// see sorting in computeMonthsParse15691for (i = 0; i < 12; i++) {15692// make the regex if we don't have it already15693mom = createUTC([2000, i]);15694if (strict && !this._longMonthsParse[i]) {15695this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');15696this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');15697}15698if (!strict && !this._monthsParse[i]) {15699regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');15700this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');15701}15702// test the regex15703if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {15704return i;15705} else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {15706return i;15707} else if (!strict && this._monthsParse[i].test(monthName)) {15708return i;15709}15710}15711}1571215713// MOMENTS1571415715function setMonth (mom, value) {15716var dayOfMonth;1571715718if (!mom.isValid()) {15719// No op15720return mom;15721}1572215723if (typeof value === 'string') {15724if (/^\d+$/.test(value)) {15725value = toInt(value);15726} else {15727value = mom.localeData().monthsParse(value);15728// TODO: Another silent failure?15729if (!isNumber(value)) {15730return mom;15731}15732}15733}1573415735dayOfMonth = Math.min(mom.date(), daysInMonth(mom.year(), value));15736mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth);15737return mom;15738}1573915740function getSetMonth (value) {15741if (value != null) {15742setMonth(this, value);15743hooks.updateOffset(this, true);15744return this;15745} else {15746return get(this, 'Month');15747}15748}1574915750function getDaysInMonth () {15751return daysInMonth(this.year(), this.month());15752}1575315754var defaultMonthsShortRegex = matchWord;15755function monthsShortRegex (isStrict) {15756if (this._monthsParseExact) {15757if (!hasOwnProp(this, '_monthsRegex')) {15758computeMonthsParse.call(this);15759}15760if (isStrict) {15761return this._monthsShortStrictRegex;15762} else {15763return this._monthsShortRegex;15764}15765} else {15766if (!hasOwnProp(this, '_monthsShortRegex')) {15767this._monthsShortRegex = defaultMonthsShortRegex;15768}15769return this._monthsShortStrictRegex && isStrict ?15770this._monthsShortStrictRegex : this._monthsShortRegex;15771}15772}1577315774var defaultMonthsRegex = matchWord;15775function monthsRegex (isStrict) {15776if (this._monthsParseExact) {15777if (!hasOwnProp(this, '_monthsRegex')) {15778computeMonthsParse.call(this);15779}15780if (isStrict) {15781return this._monthsStrictRegex;15782} else {15783return this._monthsRegex;15784}15785} else {15786if (!hasOwnProp(this, '_monthsRegex')) {15787this._monthsRegex = defaultMonthsRegex;15788}15789return this._monthsStrictRegex && isStrict ?15790this._monthsStrictRegex : this._monthsRegex;15791}15792}1579315794function computeMonthsParse () {15795function cmpLenRev(a, b) {15796return b.length - a.length;15797}1579815799var shortPieces = [], longPieces = [], mixedPieces = [],15800i, mom;15801for (i = 0; i < 12; i++) {15802// make the regex if we don't have it already15803mom = createUTC([2000, i]);15804shortPieces.push(this.monthsShort(mom, ''));15805longPieces.push(this.months(mom, ''));15806mixedPieces.push(this.months(mom, ''));15807mixedPieces.push(this.monthsShort(mom, ''));15808}15809// Sorting makes sure if one month (or abbr) is a prefix of another it15810// will match the longer piece.15811shortPieces.sort(cmpLenRev);15812longPieces.sort(cmpLenRev);15813mixedPieces.sort(cmpLenRev);15814for (i = 0; i < 12; i++) {15815shortPieces[i] = regexEscape(shortPieces[i]);15816longPieces[i] = regexEscape(longPieces[i]);15817}15818for (i = 0; i < 24; i++) {15819mixedPieces[i] = regexEscape(mixedPieces[i]);15820}1582115822this._monthsRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');15823this._monthsShortRegex = this._monthsRegex;15824this._monthsStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');15825this._monthsShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');15826}1582715828function createDate (y, m, d, h, M, s, ms) {15829// can't just apply() to create a date:15830// https://stackoverflow.com/q/18134815831var date;15832// the date constructor remaps years 0-99 to 1900-199915833if (y < 100 && y >= 0) {15834// preserve leap years using a full 400 year cycle, then reset15835date = new Date(y + 400, m, d, h, M, s, ms);15836if (isFinite(date.getFullYear())) {15837date.setFullYear(y);15838}15839} else {15840date = new Date(y, m, d, h, M, s, ms);15841}1584215843return date;15844}1584515846function createUTCDate (y) {15847var date;15848// the Date.UTC function remaps years 0-99 to 1900-199915849if (y < 100 && y >= 0) {15850var args = Array.prototype.slice.call(arguments);15851// preserve leap years using a full 400 year cycle, then reset15852args[0] = y + 400;15853date = new Date(Date.UTC.apply(null, args));15854if (isFinite(date.getUTCFullYear())) {15855date.setUTCFullYear(y);15856}15857} else {15858date = new Date(Date.UTC.apply(null, arguments));15859}1586015861return date;15862}1586315864// start-of-first-week - start-of-year15865function firstWeekOffset(year, dow, doy) {15866var // first-week day -- which january is always in the first week (4 for iso, 1 for other)15867fwd = 7 + dow - doy,15868// first-week day local weekday -- which local weekday is fwd15869fwdlw = (7 + createUTCDate(year, 0, fwd).getUTCDay() - dow) % 7;1587015871return -fwdlw + fwd - 1;15872}1587315874// https://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday15875function dayOfYearFromWeeks(year, week, weekday, dow, doy) {15876var localWeekday = (7 + weekday - dow) % 7,15877weekOffset = firstWeekOffset(year, dow, doy),15878dayOfYear = 1 + 7 * (week - 1) + localWeekday + weekOffset,15879resYear, resDayOfYear;1588015881if (dayOfYear <= 0) {15882resYear = year - 1;15883resDayOfYear = daysInYear(resYear) + dayOfYear;15884} else if (dayOfYear > daysInYear(year)) {15885resYear = year + 1;15886resDayOfYear = dayOfYear - daysInYear(year);15887} else {15888resYear = year;15889resDayOfYear = dayOfYear;15890}1589115892return {15893year: resYear,15894dayOfYear: resDayOfYear15895};15896}1589715898function weekOfYear(mom, dow, doy) {15899var weekOffset = firstWeekOffset(mom.year(), dow, doy),15900week = Math.floor((mom.dayOfYear() - weekOffset - 1) / 7) + 1,15901resWeek, resYear;1590215903if (week < 1) {15904resYear = mom.year() - 1;15905resWeek = week + weeksInYear(resYear, dow, doy);15906} else if (week > weeksInYear(mom.year(), dow, doy)) {15907resWeek = week - weeksInYear(mom.year(), dow, doy);15908resYear = mom.year() + 1;15909} else {15910resYear = mom.year();15911resWeek = week;15912}1591315914return {15915week: resWeek,15916year: resYear15917};15918}1591915920function weeksInYear(year, dow, doy) {15921var weekOffset = firstWeekOffset(year, dow, doy),15922weekOffsetNext = firstWeekOffset(year + 1, dow, doy);15923return (daysInYear(year) - weekOffset + weekOffsetNext) / 7;15924}1592515926// FORMATTING1592715928addFormatToken('w', ['ww', 2], 'wo', 'week');15929addFormatToken('W', ['WW', 2], 'Wo', 'isoWeek');1593015931// ALIASES1593215933addUnitAlias('week', 'w');15934addUnitAlias('isoWeek', 'W');1593515936// PRIORITIES1593715938addUnitPriority('week', 5);15939addUnitPriority('isoWeek', 5);1594015941// PARSING1594215943addRegexToken('w', match1to2);15944addRegexToken('ww', match1to2, match2);15945addRegexToken('W', match1to2);15946addRegexToken('WW', match1to2, match2);1594715948addWeekParseToken(['w', 'ww', 'W', 'WW'], function (input, week, config, token) {15949week[token.substr(0, 1)] = toInt(input);15950});1595115952// HELPERS1595315954// LOCALES1595515956function localeWeek (mom) {15957return weekOfYear(mom, this._week.dow, this._week.doy).week;15958}1595915960var defaultLocaleWeek = {15961dow : 0, // Sunday is the first day of the week.15962doy : 6 // The week that contains Jan 6th is the first week of the year.15963};1596415965function localeFirstDayOfWeek () {15966return this._week.dow;15967}1596815969function localeFirstDayOfYear () {15970return this._week.doy;15971}1597215973// MOMENTS1597415975function getSetWeek (input) {15976var week = this.localeData().week(this);15977return input == null ? week : this.add((input - week) * 7, 'd');15978}1597915980function getSetISOWeek (input) {15981var week = weekOfYear(this, 1, 4).week;15982return input == null ? week : this.add((input - week) * 7, 'd');15983}1598415985// FORMATTING1598615987addFormatToken('d', 0, 'do', 'day');1598815989addFormatToken('dd', 0, 0, function (format) {15990return this.localeData().weekdaysMin(this, format);15991});1599215993addFormatToken('ddd', 0, 0, function (format) {15994return this.localeData().weekdaysShort(this, format);15995});1599615997addFormatToken('dddd', 0, 0, function (format) {15998return this.localeData().weekdays(this, format);15999});1600016001addFormatToken('e', 0, 0, 'weekday');16002addFormatToken('E', 0, 0, 'isoWeekday');1600316004// ALIASES1600516006addUnitAlias('day', 'd');16007addUnitAlias('weekday', 'e');16008addUnitAlias('isoWeekday', 'E');1600916010// PRIORITY16011addUnitPriority('day', 11);16012addUnitPriority('weekday', 11);16013addUnitPriority('isoWeekday', 11);1601416015// PARSING1601616017addRegexToken('d', match1to2);16018addRegexToken('e', match1to2);16019addRegexToken('E', match1to2);16020addRegexToken('dd', function (isStrict, locale) {16021return locale.weekdaysMinRegex(isStrict);16022});16023addRegexToken('ddd', function (isStrict, locale) {16024return locale.weekdaysShortRegex(isStrict);16025});16026addRegexToken('dddd', function (isStrict, locale) {16027return locale.weekdaysRegex(isStrict);16028});1602916030addWeekParseToken(['dd', 'ddd', 'dddd'], function (input, week, config, token) {16031var weekday = config._locale.weekdaysParse(input, token, config._strict);16032// if we didn't get a weekday name, mark the date as invalid16033if (weekday != null) {16034week.d = weekday;16035} else {16036getParsingFlags(config).invalidWeekday = input;16037}16038});1603916040addWeekParseToken(['d', 'e', 'E'], function (input, week, config, token) {16041week[token] = toInt(input);16042});1604316044// HELPERS1604516046function parseWeekday(input, locale) {16047if (typeof input !== 'string') {16048return input;16049}1605016051if (!isNaN(input)) {16052return parseInt(input, 10);16053}1605416055input = locale.weekdaysParse(input);16056if (typeof input === 'number') {16057return input;16058}1605916060return null;16061}1606216063function parseIsoWeekday(input, locale) {16064if (typeof input === 'string') {16065return locale.weekdaysParse(input) % 7 || 7;16066}16067return isNaN(input) ? null : input;16068}1606916070// LOCALES16071function shiftWeekdays (ws, n) {16072return ws.slice(n, 7).concat(ws.slice(0, n));16073}1607416075var defaultLocaleWeekdays = 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_');16076function localeWeekdays (m, format) {16077var weekdays = isArray(this._weekdays) ? this._weekdays :16078this._weekdays[(m && m !== true && this._weekdays.isFormat.test(format)) ? 'format' : 'standalone'];16079return (m === true) ? shiftWeekdays(weekdays, this._week.dow)16080: (m) ? weekdays[m.day()] : weekdays;16081}1608216083var defaultLocaleWeekdaysShort = 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_');16084function localeWeekdaysShort (m) {16085return (m === true) ? shiftWeekdays(this._weekdaysShort, this._week.dow)16086: (m) ? this._weekdaysShort[m.day()] : this._weekdaysShort;16087}1608816089var defaultLocaleWeekdaysMin = 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_');16090function localeWeekdaysMin (m) {16091return (m === true) ? shiftWeekdays(this._weekdaysMin, this._week.dow)16092: (m) ? this._weekdaysMin[m.day()] : this._weekdaysMin;16093}1609416095function handleStrictParse$1(weekdayName, format, strict) {16096var i, ii, mom, llc = weekdayName.toLocaleLowerCase();16097if (!this._weekdaysParse) {16098this._weekdaysParse = [];16099this._shortWeekdaysParse = [];16100this._minWeekdaysParse = [];1610116102for (i = 0; i < 7; ++i) {16103mom = createUTC([2000, 1]).day(i);16104this._minWeekdaysParse[i] = this.weekdaysMin(mom, '').toLocaleLowerCase();16105this._shortWeekdaysParse[i] = this.weekdaysShort(mom, '').toLocaleLowerCase();16106this._weekdaysParse[i] = this.weekdays(mom, '').toLocaleLowerCase();16107}16108}1610916110if (strict) {16111if (format === 'dddd') {16112ii = indexOf.call(this._weekdaysParse, llc);16113return ii !== -1 ? ii : null;16114} else if (format === 'ddd') {16115ii = indexOf.call(this._shortWeekdaysParse, llc);16116return ii !== -1 ? ii : null;16117} else {16118ii = indexOf.call(this._minWeekdaysParse, llc);16119return ii !== -1 ? ii : null;16120}16121} else {16122if (format === 'dddd') {16123ii = indexOf.call(this._weekdaysParse, llc);16124if (ii !== -1) {16125return ii;16126}16127ii = indexOf.call(this._shortWeekdaysParse, llc);16128if (ii !== -1) {16129return ii;16130}16131ii = indexOf.call(this._minWeekdaysParse, llc);16132return ii !== -1 ? ii : null;16133} else if (format === 'ddd') {16134ii = indexOf.call(this._shortWeekdaysParse, llc);16135if (ii !== -1) {16136return ii;16137}16138ii = indexOf.call(this._weekdaysParse, llc);16139if (ii !== -1) {16140return ii;16141}16142ii = indexOf.call(this._minWeekdaysParse, llc);16143return ii !== -1 ? ii : null;16144} else {16145ii = indexOf.call(this._minWeekdaysParse, llc);16146if (ii !== -1) {16147return ii;16148}16149ii = indexOf.call(this._weekdaysParse, llc);16150if (ii !== -1) {16151return ii;16152}16153ii = indexOf.call(this._shortWeekdaysParse, llc);16154return ii !== -1 ? ii : null;16155}16156}16157}1615816159function localeWeekdaysParse (weekdayName, format, strict) {16160var i, mom, regex;1616116162if (this._weekdaysParseExact) {16163return handleStrictParse$1.call(this, weekdayName, format, strict);16164}1616516166if (!this._weekdaysParse) {16167this._weekdaysParse = [];16168this._minWeekdaysParse = [];16169this._shortWeekdaysParse = [];16170this._fullWeekdaysParse = [];16171}1617216173for (i = 0; i < 7; i++) {16174// make the regex if we don't have it already1617516176mom = createUTC([2000, 1]).day(i);16177if (strict && !this._fullWeekdaysParse[i]) {16178this._fullWeekdaysParse[i] = new RegExp('^' + this.weekdays(mom, '').replace('.', '\\.?') + '$', 'i');16179this._shortWeekdaysParse[i] = new RegExp('^' + this.weekdaysShort(mom, '').replace('.', '\\.?') + '$', 'i');16180this._minWeekdaysParse[i] = new RegExp('^' + this.weekdaysMin(mom, '').replace('.', '\\.?') + '$', 'i');16181}16182if (!this._weekdaysParse[i]) {16183regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, '');16184this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i');16185}16186// test the regex16187if (strict && format === 'dddd' && this._fullWeekdaysParse[i].test(weekdayName)) {16188return i;16189} else if (strict && format === 'ddd' && this._shortWeekdaysParse[i].test(weekdayName)) {16190return i;16191} else if (strict && format === 'dd' && this._minWeekdaysParse[i].test(weekdayName)) {16192return i;16193} else if (!strict && this._weekdaysParse[i].test(weekdayName)) {16194return i;16195}16196}16197}1619816199// MOMENTS1620016201function getSetDayOfWeek (input) {16202if (!this.isValid()) {16203return input != null ? this : NaN;16204}16205var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay();16206if (input != null) {16207input = parseWeekday(input, this.localeData());16208return this.add(input - day, 'd');16209} else {16210return day;16211}16212}1621316214function getSetLocaleDayOfWeek (input) {16215if (!this.isValid()) {16216return input != null ? this : NaN;16217}16218var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7;16219return input == null ? weekday : this.add(input - weekday, 'd');16220}1622116222function getSetISODayOfWeek (input) {16223if (!this.isValid()) {16224return input != null ? this : NaN;16225}1622616227// behaves the same as moment#day except16228// as a getter, returns 7 instead of 0 (1-7 range instead of 0-6)16229// as a setter, sunday should belong to the previous week.1623016231if (input != null) {16232var weekday = parseIsoWeekday(input, this.localeData());16233return this.day(this.day() % 7 ? weekday : weekday - 7);16234} else {16235return this.day() || 7;16236}16237}1623816239var defaultWeekdaysRegex = matchWord;16240function weekdaysRegex (isStrict) {16241if (this._weekdaysParseExact) {16242if (!hasOwnProp(this, '_weekdaysRegex')) {16243computeWeekdaysParse.call(this);16244}16245if (isStrict) {16246return this._weekdaysStrictRegex;16247} else {16248return this._weekdaysRegex;16249}16250} else {16251if (!hasOwnProp(this, '_weekdaysRegex')) {16252this._weekdaysRegex = defaultWeekdaysRegex;16253}16254return this._weekdaysStrictRegex && isStrict ?16255this._weekdaysStrictRegex : this._weekdaysRegex;16256}16257}1625816259var defaultWeekdaysShortRegex = matchWord;16260function weekdaysShortRegex (isStrict) {16261if (this._weekdaysParseExact) {16262if (!hasOwnProp(this, '_weekdaysRegex')) {16263computeWeekdaysParse.call(this);16264}16265if (isStrict) {16266return this._weekdaysShortStrictRegex;16267} else {16268return this._weekdaysShortRegex;16269}16270} else {16271if (!hasOwnProp(this, '_weekdaysShortRegex')) {16272this._weekdaysShortRegex = defaultWeekdaysShortRegex;16273}16274return this._weekdaysShortStrictRegex && isStrict ?16275this._weekdaysShortStrictRegex : this._weekdaysShortRegex;16276}16277}1627816279var defaultWeekdaysMinRegex = matchWord;16280function weekdaysMinRegex (isStrict) {16281if (this._weekdaysParseExact) {16282if (!hasOwnProp(this, '_weekdaysRegex')) {16283computeWeekdaysParse.call(this);16284}16285if (isStrict) {16286return this._weekdaysMinStrictRegex;16287} else {16288return this._weekdaysMinRegex;16289}16290} else {16291if (!hasOwnProp(this, '_weekdaysMinRegex')) {16292this._weekdaysMinRegex = defaultWeekdaysMinRegex;16293}16294return this._weekdaysMinStrictRegex && isStrict ?16295this._weekdaysMinStrictRegex : this._weekdaysMinRegex;16296}16297}162981629916300function computeWeekdaysParse () {16301function cmpLenRev(a, b) {16302return b.length - a.length;16303}1630416305var minPieces = [], shortPieces = [], longPieces = [], mixedPieces = [],16306i, mom, minp, shortp, longp;16307for (i = 0; i < 7; i++) {16308// make the regex if we don't have it already16309mom = createUTC([2000, 1]).day(i);16310minp = this.weekdaysMin(mom, '');16311shortp = this.weekdaysShort(mom, '');16312longp = this.weekdays(mom, '');16313minPieces.push(minp);16314shortPieces.push(shortp);16315longPieces.push(longp);16316mixedPieces.push(minp);16317mixedPieces.push(shortp);16318mixedPieces.push(longp);16319}16320// Sorting makes sure if one weekday (or abbr) is a prefix of another it16321// will match the longer piece.16322minPieces.sort(cmpLenRev);16323shortPieces.sort(cmpLenRev);16324longPieces.sort(cmpLenRev);16325mixedPieces.sort(cmpLenRev);16326for (i = 0; i < 7; i++) {16327shortPieces[i] = regexEscape(shortPieces[i]);16328longPieces[i] = regexEscape(longPieces[i]);16329mixedPieces[i] = regexEscape(mixedPieces[i]);16330}1633116332this._weekdaysRegex = new RegExp('^(' + mixedPieces.join('|') + ')', 'i');16333this._weekdaysShortRegex = this._weekdaysRegex;16334this._weekdaysMinRegex = this._weekdaysRegex;1633516336this._weekdaysStrictRegex = new RegExp('^(' + longPieces.join('|') + ')', 'i');16337this._weekdaysShortStrictRegex = new RegExp('^(' + shortPieces.join('|') + ')', 'i');16338this._weekdaysMinStrictRegex = new RegExp('^(' + minPieces.join('|') + ')', 'i');16339}1634016341// FORMATTING1634216343function hFormat() {16344return this.hours() % 12 || 12;16345}1634616347function kFormat() {16348return this.hours() || 24;16349}1635016351addFormatToken('H', ['HH', 2], 0, 'hour');16352addFormatToken('h', ['hh', 2], 0, hFormat);16353addFormatToken('k', ['kk', 2], 0, kFormat);1635416355addFormatToken('hmm', 0, 0, function () {16356return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2);16357});1635816359addFormatToken('hmmss', 0, 0, function () {16360return '' + hFormat.apply(this) + zeroFill(this.minutes(), 2) +16361zeroFill(this.seconds(), 2);16362});1636316364addFormatToken('Hmm', 0, 0, function () {16365return '' + this.hours() + zeroFill(this.minutes(), 2);16366});1636716368addFormatToken('Hmmss', 0, 0, function () {16369return '' + this.hours() + zeroFill(this.minutes(), 2) +16370zeroFill(this.seconds(), 2);16371});1637216373function meridiem (token, lowercase) {16374addFormatToken(token, 0, 0, function () {16375return this.localeData().meridiem(this.hours(), this.minutes(), lowercase);16376});16377}1637816379meridiem('a', true);16380meridiem('A', false);1638116382// ALIASES1638316384addUnitAlias('hour', 'h');1638516386// PRIORITY16387addUnitPriority('hour', 13);1638816389// PARSING1639016391function matchMeridiem (isStrict, locale) {16392return locale._meridiemParse;16393}1639416395addRegexToken('a', matchMeridiem);16396addRegexToken('A', matchMeridiem);16397addRegexToken('H', match1to2);16398addRegexToken('h', match1to2);16399addRegexToken('k', match1to2);16400addRegexToken('HH', match1to2, match2);16401addRegexToken('hh', match1to2, match2);16402addRegexToken('kk', match1to2, match2);1640316404addRegexToken('hmm', match3to4);16405addRegexToken('hmmss', match5to6);16406addRegexToken('Hmm', match3to4);16407addRegexToken('Hmmss', match5to6);1640816409addParseToken(['H', 'HH'], HOUR);16410addParseToken(['k', 'kk'], function (input, array, config) {16411var kInput = toInt(input);16412array[HOUR] = kInput === 24 ? 0 : kInput;16413});16414addParseToken(['a', 'A'], function (input, array, config) {16415config._isPm = config._locale.isPM(input);16416config._meridiem = input;16417});16418addParseToken(['h', 'hh'], function (input, array, config) {16419array[HOUR] = toInt(input);16420getParsingFlags(config).bigHour = true;16421});16422addParseToken('hmm', function (input, array, config) {16423var pos = input.length - 2;16424array[HOUR] = toInt(input.substr(0, pos));16425array[MINUTE] = toInt(input.substr(pos));16426getParsingFlags(config).bigHour = true;16427});16428addParseToken('hmmss', function (input, array, config) {16429var pos1 = input.length - 4;16430var pos2 = input.length - 2;16431array[HOUR] = toInt(input.substr(0, pos1));16432array[MINUTE] = toInt(input.substr(pos1, 2));16433array[SECOND] = toInt(input.substr(pos2));16434getParsingFlags(config).bigHour = true;16435});16436addParseToken('Hmm', function (input, array, config) {16437var pos = input.length - 2;16438array[HOUR] = toInt(input.substr(0, pos));16439array[MINUTE] = toInt(input.substr(pos));16440});16441addParseToken('Hmmss', function (input, array, config) {16442var pos1 = input.length - 4;16443var pos2 = input.length - 2;16444array[HOUR] = toInt(input.substr(0, pos1));16445array[MINUTE] = toInt(input.substr(pos1, 2));16446array[SECOND] = toInt(input.substr(pos2));16447});1644816449// LOCALES1645016451function localeIsPM (input) {16452// IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays16453// Using charAt should be more compatible.16454return ((input + '').toLowerCase().charAt(0) === 'p');16455}1645616457var defaultLocaleMeridiemParse = /[ap]\.?m?\.?/i;16458function localeMeridiem (hours, minutes, isLower) {16459if (hours > 11) {16460return isLower ? 'pm' : 'PM';16461} else {16462return isLower ? 'am' : 'AM';16463}16464}164651646616467// MOMENTS1646816469// Setting the hour should keep the time, because the user explicitly16470// specified which hour they want. So trying to maintain the same hour (in16471// a new timezone) makes sense. Adding/subtracting hours does not follow16472// this rule.16473var getSetHour = makeGetSet('Hours', true);1647416475var baseConfig = {16476calendar: defaultCalendar,16477longDateFormat: defaultLongDateFormat,16478invalidDate: defaultInvalidDate,16479ordinal: defaultOrdinal,16480dayOfMonthOrdinalParse: defaultDayOfMonthOrdinalParse,16481relativeTime: defaultRelativeTime,1648216483months: defaultLocaleMonths,16484monthsShort: defaultLocaleMonthsShort,1648516486week: defaultLocaleWeek,1648716488weekdays: defaultLocaleWeekdays,16489weekdaysMin: defaultLocaleWeekdaysMin,16490weekdaysShort: defaultLocaleWeekdaysShort,1649116492meridiemParse: defaultLocaleMeridiemParse16493};1649416495// internal storage for locale config files16496var locales = {};16497var localeFamilies = {};16498var globalLocale;1649916500function normalizeLocale(key) {16501return key ? key.toLowerCase().replace('_', '-') : key;16502}1650316504// pick the locale from the array16505// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each16506// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root16507function chooseLocale(names) {16508var i = 0, j, next, locale, split;1650916510while (i < names.length) {16511split = normalizeLocale(names[i]).split('-');16512j = split.length;16513next = normalizeLocale(names[i + 1]);16514next = next ? next.split('-') : null;16515while (j > 0) {16516locale = loadLocale(split.slice(0, j).join('-'));16517if (locale) {16518return locale;16519}16520if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) {16521//the next array item is better than a shallower substring of this one16522break;16523}16524j--;16525}16526i++;16527}16528return globalLocale;16529}1653016531function loadLocale(name) {16532var oldLocale = null;16533// TODO: Find a better way to register and load all the locales in Node16534if (!locales[name] && ('object' !== 'undefined') &&16535module && module.exports) {16536try {16537oldLocale = globalLocale._abbr;16538var aliasedRequire = commonjsRequire;16539aliasedRequire('./locale/' + name);16540getSetGlobalLocale(oldLocale);16541} catch (e) {}16542}16543return locales[name];16544}1654516546// This function will load locale and then set the global locale. If16547// no arguments are passed in, it will simply return the current global16548// locale key.16549function getSetGlobalLocale (key, values) {16550var data;16551if (key) {16552if (isUndefined(values)) {16553data = getLocale(key);16554}16555else {16556data = defineLocale(key, values);16557}1655816559if (data) {16560// moment.duration._locale = moment._locale = data;16561globalLocale = data;16562}16563else {16564if ((typeof console !== 'undefined') && console.warn) {16565//warn user if arguments are passed but the locale could not be set16566console.warn('Locale ' + key + ' not found. Did you forget to load it?');16567}16568}16569}1657016571return globalLocale._abbr;16572}1657316574function defineLocale (name, config) {16575if (config !== null) {16576var locale, parentConfig = baseConfig;16577config.abbr = name;16578if (locales[name] != null) {16579deprecateSimple('defineLocaleOverride',16580'use moment.updateLocale(localeName, config) to change ' +16581'an existing locale. moment.defineLocale(localeName, ' +16582'config) should only be used for creating a new locale ' +16583'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');16584parentConfig = locales[name]._config;16585} else if (config.parentLocale != null) {16586if (locales[config.parentLocale] != null) {16587parentConfig = locales[config.parentLocale]._config;16588} else {16589locale = loadLocale(config.parentLocale);16590if (locale != null) {16591parentConfig = locale._config;16592} else {16593if (!localeFamilies[config.parentLocale]) {16594localeFamilies[config.parentLocale] = [];16595}16596localeFamilies[config.parentLocale].push({16597name: name,16598config: config16599});16600return null;16601}16602}16603}16604locales[name] = new Locale(mergeConfigs(parentConfig, config));1660516606if (localeFamilies[name]) {16607localeFamilies[name].forEach(function (x) {16608defineLocale(x.name, x.config);16609});16610}1661116612// backwards compat for now: also set the locale16613// make sure we set the locale AFTER all child locales have been16614// created, so we won't end up with the child locale set.16615getSetGlobalLocale(name);166161661716618return locales[name];16619} else {16620// useful for testing16621delete locales[name];16622return null;16623}16624}1662516626function updateLocale(name, config) {16627if (config != null) {16628var locale, tmpLocale, parentConfig = baseConfig;16629// MERGE16630tmpLocale = loadLocale(name);16631if (tmpLocale != null) {16632parentConfig = tmpLocale._config;16633}16634config = mergeConfigs(parentConfig, config);16635locale = new Locale(config);16636locale.parentLocale = locales[name];16637locales[name] = locale;1663816639// backwards compat for now: also set the locale16640getSetGlobalLocale(name);16641} else {16642// pass null for config to unupdate, useful for tests16643if (locales[name] != null) {16644if (locales[name].parentLocale != null) {16645locales[name] = locales[name].parentLocale;16646} else if (locales[name] != null) {16647delete locales[name];16648}16649}16650}16651return locales[name];16652}1665316654// returns locale data16655function getLocale (key) {16656var locale;1665716658if (key && key._locale && key._locale._abbr) {16659key = key._locale._abbr;16660}1666116662if (!key) {16663return globalLocale;16664}1666516666if (!isArray(key)) {16667//short-circuit everything else16668locale = loadLocale(key);16669if (locale) {16670return locale;16671}16672key = [key];16673}1667416675return chooseLocale(key);16676}1667716678function listLocales() {16679return keys(locales);16680}1668116682function checkOverflow (m) {16683var overflow;16684var a = m._a;1668516686if (a && getParsingFlags(m).overflow === -2) {16687overflow =16688a[MONTH] < 0 || a[MONTH] > 11 ? MONTH :16689a[DATE] < 1 || a[DATE] > daysInMonth(a[YEAR], a[MONTH]) ? DATE :16690a[HOUR] < 0 || a[HOUR] > 24 || (a[HOUR] === 24 && (a[MINUTE] !== 0 || a[SECOND] !== 0 || a[MILLISECOND] !== 0)) ? HOUR :16691a[MINUTE] < 0 || a[MINUTE] > 59 ? MINUTE :16692a[SECOND] < 0 || a[SECOND] > 59 ? SECOND :16693a[MILLISECOND] < 0 || a[MILLISECOND] > 999 ? MILLISECOND :16694-1;1669516696if (getParsingFlags(m)._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) {16697overflow = DATE;16698}16699if (getParsingFlags(m)._overflowWeeks && overflow === -1) {16700overflow = WEEK;16701}16702if (getParsingFlags(m)._overflowWeekday && overflow === -1) {16703overflow = WEEKDAY;16704}1670516706getParsingFlags(m).overflow = overflow;16707}1670816709return m;16710}1671116712// Pick the first defined of two or three arguments.16713function defaults(a, b, c) {16714if (a != null) {16715return a;16716}16717if (b != null) {16718return b;16719}16720return c;16721}1672216723function currentDateArray(config) {16724// hooks is actually the exported moment object16725var nowValue = new Date(hooks.now());16726if (config._useUTC) {16727return [nowValue.getUTCFullYear(), nowValue.getUTCMonth(), nowValue.getUTCDate()];16728}16729return [nowValue.getFullYear(), nowValue.getMonth(), nowValue.getDate()];16730}1673116732// convert an array to a date.16733// the array should mirror the parameters below16734// note: all values past the year are optional and will default to the lowest possible value.16735// [year, month, day , hour, minute, second, millisecond]16736function configFromArray (config) {16737var i, date, input = [], currentDate, expectedWeekday, yearToUse;1673816739if (config._d) {16740return;16741}1674216743currentDate = currentDateArray(config);1674416745//compute day of the year from weeks and weekdays16746if (config._w && config._a[DATE] == null && config._a[MONTH] == null) {16747dayOfYearFromWeekInfo(config);16748}1674916750//if the day of the year is set, figure out what it is16751if (config._dayOfYear != null) {16752yearToUse = defaults(config._a[YEAR], currentDate[YEAR]);1675316754if (config._dayOfYear > daysInYear(yearToUse) || config._dayOfYear === 0) {16755getParsingFlags(config)._overflowDayOfYear = true;16756}1675716758date = createUTCDate(yearToUse, 0, config._dayOfYear);16759config._a[MONTH] = date.getUTCMonth();16760config._a[DATE] = date.getUTCDate();16761}1676216763// Default to current date.16764// * if no year, month, day of month are given, default to today16765// * if day of month is given, default month and year16766// * if month is given, default only year16767// * if year is given, don't default anything16768for (i = 0; i < 3 && config._a[i] == null; ++i) {16769config._a[i] = input[i] = currentDate[i];16770}1677116772// Zero out whatever was not defaulted, including time16773for (; i < 7; i++) {16774config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];16775}1677616777// Check for 24:00:00.00016778if (config._a[HOUR] === 24 &&16779config._a[MINUTE] === 0 &&16780config._a[SECOND] === 0 &&16781config._a[MILLISECOND] === 0) {16782config._nextDay = true;16783config._a[HOUR] = 0;16784}1678516786config._d = (config._useUTC ? createUTCDate : createDate).apply(null, input);16787expectedWeekday = config._useUTC ? config._d.getUTCDay() : config._d.getDay();1678816789// Apply timezone offset from input. The actual utcOffset can be changed16790// with parseZone.16791if (config._tzm != null) {16792config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);16793}1679416795if (config._nextDay) {16796config._a[HOUR] = 24;16797}1679816799// check for mismatching day of week16800if (config._w && typeof config._w.d !== 'undefined' && config._w.d !== expectedWeekday) {16801getParsingFlags(config).weekdayMismatch = true;16802}16803}1680416805function dayOfYearFromWeekInfo(config) {16806var w, weekYear, week, weekday, dow, doy, temp, weekdayOverflow;1680716808w = config._w;16809if (w.GG != null || w.W != null || w.E != null) {16810dow = 1;16811doy = 4;1681216813// TODO: We need to take the current isoWeekYear, but that depends on16814// how we interpret now (local, utc, fixed offset). So create16815// a now version of current config (take local/utc/offset flags, and16816// create now).16817weekYear = defaults(w.GG, config._a[YEAR], weekOfYear(createLocal(), 1, 4).year);16818week = defaults(w.W, 1);16819weekday = defaults(w.E, 1);16820if (weekday < 1 || weekday > 7) {16821weekdayOverflow = true;16822}16823} else {16824dow = config._locale._week.dow;16825doy = config._locale._week.doy;1682616827var curWeek = weekOfYear(createLocal(), dow, doy);1682816829weekYear = defaults(w.gg, config._a[YEAR], curWeek.year);1683016831// Default to current week.16832week = defaults(w.w, curWeek.week);1683316834if (w.d != null) {16835// weekday -- low day numbers are considered next week16836weekday = w.d;16837if (weekday < 0 || weekday > 6) {16838weekdayOverflow = true;16839}16840} else if (w.e != null) {16841// local weekday -- counting starts from beginning of week16842weekday = w.e + dow;16843if (w.e < 0 || w.e > 6) {16844weekdayOverflow = true;16845}16846} else {16847// default to beginning of week16848weekday = dow;16849}16850}16851if (week < 1 || week > weeksInYear(weekYear, dow, doy)) {16852getParsingFlags(config)._overflowWeeks = true;16853} else if (weekdayOverflow != null) {16854getParsingFlags(config)._overflowWeekday = true;16855} else {16856temp = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy);16857config._a[YEAR] = temp.year;16858config._dayOfYear = temp.dayOfYear;16859}16860}1686116862// iso 8601 regex16863// 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)16864var 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)?)?$/;16865var 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)?)?$/;1686616867var tzRegex = /Z|[+-]\d\d(?::?\d\d)?/;1686816869var isoDates = [16870['YYYYYY-MM-DD', /[+-]\d{6}-\d\d-\d\d/],16871['YYYY-MM-DD', /\d{4}-\d\d-\d\d/],16872['GGGG-[W]WW-E', /\d{4}-W\d\d-\d/],16873['GGGG-[W]WW', /\d{4}-W\d\d/, false],16874['YYYY-DDD', /\d{4}-\d{3}/],16875['YYYY-MM', /\d{4}-\d\d/, false],16876['YYYYYYMMDD', /[+-]\d{10}/],16877['YYYYMMDD', /\d{8}/],16878// YYYYMM is NOT allowed by the standard16879['GGGG[W]WWE', /\d{4}W\d{3}/],16880['GGGG[W]WW', /\d{4}W\d{2}/, false],16881['YYYYDDD', /\d{7}/]16882];1688316884// iso time formats and regexes16885var isoTimes = [16886['HH:mm:ss.SSSS', /\d\d:\d\d:\d\d\.\d+/],16887['HH:mm:ss,SSSS', /\d\d:\d\d:\d\d,\d+/],16888['HH:mm:ss', /\d\d:\d\d:\d\d/],16889['HH:mm', /\d\d:\d\d/],16890['HHmmss.SSSS', /\d\d\d\d\d\d\.\d+/],16891['HHmmss,SSSS', /\d\d\d\d\d\d,\d+/],16892['HHmmss', /\d\d\d\d\d\d/],16893['HHmm', /\d\d\d\d/],16894['HH', /\d\d/]16895];1689616897var aspNetJsonRegex = /^\/?Date\((\-?\d+)/i;1689816899// date from iso format16900function configFromISO(config) {16901var i, l,16902string = config._i,16903match = extendedIsoRegex.exec(string) || basicIsoRegex.exec(string),16904allowTime, dateFormat, timeFormat, tzFormat;1690516906if (match) {16907getParsingFlags(config).iso = true;1690816909for (i = 0, l = isoDates.length; i < l; i++) {16910if (isoDates[i][1].exec(match[1])) {16911dateFormat = isoDates[i][0];16912allowTime = isoDates[i][2] !== false;16913break;16914}16915}16916if (dateFormat == null) {16917config._isValid = false;16918return;16919}16920if (match[3]) {16921for (i = 0, l = isoTimes.length; i < l; i++) {16922if (isoTimes[i][1].exec(match[3])) {16923// match[2] should be 'T' or space16924timeFormat = (match[2] || ' ') + isoTimes[i][0];16925break;16926}16927}16928if (timeFormat == null) {16929config._isValid = false;16930return;16931}16932}16933if (!allowTime && timeFormat != null) {16934config._isValid = false;16935return;16936}16937if (match[4]) {16938if (tzRegex.exec(match[4])) {16939tzFormat = 'Z';16940} else {16941config._isValid = false;16942return;16943}16944}16945config._f = dateFormat + (timeFormat || '') + (tzFormat || '');16946configFromStringAndFormat(config);16947} else {16948config._isValid = false;16949}16950}1695116952// RFC 2822 regex: For details see https://tools.ietf.org/html/rfc2822#section-3.316953var rfc2822 = /^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/;1695416955function extractFromRFC2822Strings(yearStr, monthStr, dayStr, hourStr, minuteStr, secondStr) {16956var result = [16957untruncateYear(yearStr),16958defaultLocaleMonthsShort.indexOf(monthStr),16959parseInt(dayStr, 10),16960parseInt(hourStr, 10),16961parseInt(minuteStr, 10)16962];1696316964if (secondStr) {16965result.push(parseInt(secondStr, 10));16966}1696716968return result;16969}1697016971function untruncateYear(yearStr) {16972var year = parseInt(yearStr, 10);16973if (year <= 49) {16974return 2000 + year;16975} else if (year <= 999) {16976return 1900 + year;16977}16978return year;16979}1698016981function preprocessRFC2822(s) {16982// Remove comments and folding whitespace and replace multiple-spaces with a single space16983return s.replace(/\([^)]*\)|[\n\t]/g, ' ').replace(/(\s\s+)/g, ' ').replace(/^\s\s*/, '').replace(/\s\s*$/, '');16984}1698516986function checkWeekday(weekdayStr, parsedInput, config) {16987if (weekdayStr) {16988// TODO: Replace the vanilla JS Date object with an indepentent day-of-week check.16989var weekdayProvided = defaultLocaleWeekdaysShort.indexOf(weekdayStr),16990weekdayActual = new Date(parsedInput[0], parsedInput[1], parsedInput[2]).getDay();16991if (weekdayProvided !== weekdayActual) {16992getParsingFlags(config).weekdayMismatch = true;16993config._isValid = false;16994return false;16995}16996}16997return true;16998}1699917000var obsOffsets = {17001UT: 0,17002GMT: 0,17003EDT: -4 * 60,17004EST: -5 * 60,17005CDT: -5 * 60,17006CST: -6 * 60,17007MDT: -6 * 60,17008MST: -7 * 60,17009PDT: -7 * 60,17010PST: -8 * 6017011};1701217013function calculateOffset(obsOffset, militaryOffset, numOffset) {17014if (obsOffset) {17015return obsOffsets[obsOffset];17016} else if (militaryOffset) {17017// the only allowed military tz is Z17018return 0;17019} else {17020var hm = parseInt(numOffset, 10);17021var m = hm % 100, h = (hm - m) / 100;17022return h * 60 + m;17023}17024}1702517026// date and time from ref 2822 format17027function configFromRFC2822(config) {17028var match = rfc2822.exec(preprocessRFC2822(config._i));17029if (match) {17030var parsedArray = extractFromRFC2822Strings(match[4], match[3], match[2], match[5], match[6], match[7]);17031if (!checkWeekday(match[1], parsedArray, config)) {17032return;17033}1703417035config._a = parsedArray;17036config._tzm = calculateOffset(match[8], match[9], match[10]);1703717038config._d = createUTCDate.apply(null, config._a);17039config._d.setUTCMinutes(config._d.getUTCMinutes() - config._tzm);1704017041getParsingFlags(config).rfc2822 = true;17042} else {17043config._isValid = false;17044}17045}1704617047// date from iso format or fallback17048function configFromString(config) {17049var matched = aspNetJsonRegex.exec(config._i);1705017051if (matched !== null) {17052config._d = new Date(+matched[1]);17053return;17054}1705517056configFromISO(config);17057if (config._isValid === false) {17058delete config._isValid;17059} else {17060return;17061}1706217063configFromRFC2822(config);17064if (config._isValid === false) {17065delete config._isValid;17066} else {17067return;17068}1706917070// Final attempt, use Input Fallback17071hooks.createFromInputFallback(config);17072}1707317074hooks.createFromInputFallback = deprecate(17075'value provided is not in a recognized RFC2822 or ISO format. moment construction falls back to js Date(), ' +17076'which is not reliable across all browsers and versions. Non RFC2822/ISO date formats are ' +17077'discouraged and will be removed in an upcoming major release. Please refer to ' +17078'http://momentjs.com/guides/#/warnings/js-date/ for more info.',17079function (config) {17080config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));17081}17082);1708317084// constant that refers to the ISO standard17085hooks.ISO_8601 = function () {};1708617087// constant that refers to the RFC 2822 form17088hooks.RFC_2822 = function () {};1708917090// date from string and format string17091function configFromStringAndFormat(config) {17092// TODO: Move this to another part of the creation flow to prevent circular deps17093if (config._f === hooks.ISO_8601) {17094configFromISO(config);17095return;17096}17097if (config._f === hooks.RFC_2822) {17098configFromRFC2822(config);17099return;17100}17101config._a = [];17102getParsingFlags(config).empty = true;1710317104// This array is used to make a Date, either with `new Date` or `Date.UTC`17105var string = '' + config._i,17106i, parsedInput, tokens, token, skipped,17107stringLength = string.length,17108totalParsedInputLength = 0;1710917110tokens = expandFormat(config._f, config._locale).match(formattingTokens) || [];1711117112for (i = 0; i < tokens.length; i++) {17113token = tokens[i];17114parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0];17115// console.log('token', token, 'parsedInput', parsedInput,17116// 'regex', getParseRegexForToken(token, config));17117if (parsedInput) {17118skipped = string.substr(0, string.indexOf(parsedInput));17119if (skipped.length > 0) {17120getParsingFlags(config).unusedInput.push(skipped);17121}17122string = string.slice(string.indexOf(parsedInput) + parsedInput.length);17123totalParsedInputLength += parsedInput.length;17124}17125// don't parse if it's not a known token17126if (formatTokenFunctions[token]) {17127if (parsedInput) {17128getParsingFlags(config).empty = false;17129}17130else {17131getParsingFlags(config).unusedTokens.push(token);17132}17133addTimeToArrayFromToken(token, parsedInput, config);17134}17135else if (config._strict && !parsedInput) {17136getParsingFlags(config).unusedTokens.push(token);17137}17138}1713917140// add remaining unparsed input length to the string17141getParsingFlags(config).charsLeftOver = stringLength - totalParsedInputLength;17142if (string.length > 0) {17143getParsingFlags(config).unusedInput.push(string);17144}1714517146// clear _12h flag if hour is <= 1217147if (config._a[HOUR] <= 12 &&17148getParsingFlags(config).bigHour === true &&17149config._a[HOUR] > 0) {17150getParsingFlags(config).bigHour = undefined;17151}1715217153getParsingFlags(config).parsedDateParts = config._a.slice(0);17154getParsingFlags(config).meridiem = config._meridiem;17155// handle meridiem17156config._a[HOUR] = meridiemFixWrap(config._locale, config._a[HOUR], config._meridiem);1715717158configFromArray(config);17159checkOverflow(config);17160}171611716217163function meridiemFixWrap (locale, hour, meridiem) {17164var isPm;1716517166if (meridiem == null) {17167// nothing to do17168return hour;17169}17170if (locale.meridiemHour != null) {17171return locale.meridiemHour(hour, meridiem);17172} else if (locale.isPM != null) {17173// Fallback17174isPm = locale.isPM(meridiem);17175if (isPm && hour < 12) {17176hour += 12;17177}17178if (!isPm && hour === 12) {17179hour = 0;17180}17181return hour;17182} else {17183// this is not supposed to happen17184return hour;17185}17186}1718717188// date from string and array of format strings17189function configFromStringAndArray(config) {17190var tempConfig,17191bestMoment,1719217193scoreToBeat,17194i,17195currentScore;1719617197if (config._f.length === 0) {17198getParsingFlags(config).invalidFormat = true;17199config._d = new Date(NaN);17200return;17201}1720217203for (i = 0; i < config._f.length; i++) {17204currentScore = 0;17205tempConfig = copyConfig({}, config);17206if (config._useUTC != null) {17207tempConfig._useUTC = config._useUTC;17208}17209tempConfig._f = config._f[i];17210configFromStringAndFormat(tempConfig);1721117212if (!isValid(tempConfig)) {17213continue;17214}1721517216// if there is any input that was not parsed add a penalty for that format17217currentScore += getParsingFlags(tempConfig).charsLeftOver;1721817219//or tokens17220currentScore += getParsingFlags(tempConfig).unusedTokens.length * 10;1722117222getParsingFlags(tempConfig).score = currentScore;1722317224if (scoreToBeat == null || currentScore < scoreToBeat) {17225scoreToBeat = currentScore;17226bestMoment = tempConfig;17227}17228}1722917230extend(config, bestMoment || tempConfig);17231}1723217233function configFromObject(config) {17234if (config._d) {17235return;17236}1723717238var i = normalizeObjectUnits(config._i);17239config._a = map([i.year, i.month, i.day || i.date, i.hour, i.minute, i.second, i.millisecond], function (obj) {17240return obj && parseInt(obj, 10);17241});1724217243configFromArray(config);17244}1724517246function createFromConfig (config) {17247var res = new Moment(checkOverflow(prepareConfig(config)));17248if (res._nextDay) {17249// Adding is smart enough around DST17250res.add(1, 'd');17251res._nextDay = undefined;17252}1725317254return res;17255}1725617257function prepareConfig (config) {17258var input = config._i,17259format = config._f;1726017261config._locale = config._locale || getLocale(config._l);1726217263if (input === null || (format === undefined && input === '')) {17264return createInvalid({nullInput: true});17265}1726617267if (typeof input === 'string') {17268config._i = input = config._locale.preparse(input);17269}1727017271if (isMoment(input)) {17272return new Moment(checkOverflow(input));17273} else if (isDate(input)) {17274config._d = input;17275} else if (isArray(format)) {17276configFromStringAndArray(config);17277} else if (format) {17278configFromStringAndFormat(config);17279} else {17280configFromInput(config);17281}1728217283if (!isValid(config)) {17284config._d = null;17285}1728617287return config;17288}1728917290function configFromInput(config) {17291var input = config._i;17292if (isUndefined(input)) {17293config._d = new Date(hooks.now());17294} else if (isDate(input)) {17295config._d = new Date(input.valueOf());17296} else if (typeof input === 'string') {17297configFromString(config);17298} else if (isArray(input)) {17299config._a = map(input.slice(0), function (obj) {17300return parseInt(obj, 10);17301});17302configFromArray(config);17303} else if (isObject(input)) {17304configFromObject(config);17305} else if (isNumber(input)) {17306// from milliseconds17307config._d = new Date(input);17308} else {17309hooks.createFromInputFallback(config);17310}17311}1731217313function createLocalOrUTC (input, format, locale, strict, isUTC) {17314var c = {};1731517316if (locale === true || locale === false) {17317strict = locale;17318locale = undefined;17319}1732017321if ((isObject(input) && isObjectEmpty(input)) ||17322(isArray(input) && input.length === 0)) {17323input = undefined;17324}17325// object construction must be done this way.17326// https://github.com/moment/moment/issues/142317327c._isAMomentObject = true;17328c._useUTC = c._isUTC = isUTC;17329c._l = locale;17330c._i = input;17331c._f = format;17332c._strict = strict;1733317334return createFromConfig(c);17335}1733617337function createLocal (input, format, locale, strict) {17338return createLocalOrUTC(input, format, locale, strict, false);17339}1734017341var prototypeMin = deprecate(17342'moment().min is deprecated, use moment.max instead. http://momentjs.com/guides/#/warnings/min-max/',17343function () {17344var other = createLocal.apply(null, arguments);17345if (this.isValid() && other.isValid()) {17346return other < this ? this : other;17347} else {17348return createInvalid();17349}17350}17351);1735217353var prototypeMax = deprecate(17354'moment().max is deprecated, use moment.min instead. http://momentjs.com/guides/#/warnings/min-max/',17355function () {17356var other = createLocal.apply(null, arguments);17357if (this.isValid() && other.isValid()) {17358return other > this ? this : other;17359} else {17360return createInvalid();17361}17362}17363);1736417365// Pick a moment m from moments so that m[fn](other) is true for all17366// other. This relies on the function fn to be transitive.17367//17368// moments should either be an array of moment objects or an array, whose17369// first element is an array of moment objects.17370function pickBy(fn, moments) {17371var res, i;17372if (moments.length === 1 && isArray(moments[0])) {17373moments = moments[0];17374}17375if (!moments.length) {17376return createLocal();17377}17378res = moments[0];17379for (i = 1; i < moments.length; ++i) {17380if (!moments[i].isValid() || moments[i][fn](res)) {17381res = moments[i];17382}17383}17384return res;17385}1738617387// TODO: Use [].sort instead?17388function min () {17389var args = [].slice.call(arguments, 0);1739017391return pickBy('isBefore', args);17392}1739317394function max () {17395var args = [].slice.call(arguments, 0);1739617397return pickBy('isAfter', args);17398}1739917400var now = function () {17401return Date.now ? Date.now() : +(new Date());17402};1740317404var ordering = ['year', 'quarter', 'month', 'week', 'day', 'hour', 'minute', 'second', 'millisecond'];1740517406function isDurationValid(m) {17407for (var key in m) {17408if (!(indexOf.call(ordering, key) !== -1 && (m[key] == null || !isNaN(m[key])))) {17409return false;17410}17411}1741217413var unitHasDecimal = false;17414for (var i = 0; i < ordering.length; ++i) {17415if (m[ordering[i]]) {17416if (unitHasDecimal) {17417return false; // only allow non-integers for smallest unit17418}17419if (parseFloat(m[ordering[i]]) !== toInt(m[ordering[i]])) {17420unitHasDecimal = true;17421}17422}17423}1742417425return true;17426}1742717428function isValid$1() {17429return this._isValid;17430}1743117432function createInvalid$1() {17433return createDuration(NaN);17434}1743517436function Duration (duration) {17437var normalizedInput = normalizeObjectUnits(duration),17438years = normalizedInput.year || 0,17439quarters = normalizedInput.quarter || 0,17440months = normalizedInput.month || 0,17441weeks = normalizedInput.week || normalizedInput.isoWeek || 0,17442days = normalizedInput.day || 0,17443hours = normalizedInput.hour || 0,17444minutes = normalizedInput.minute || 0,17445seconds = normalizedInput.second || 0,17446milliseconds = normalizedInput.millisecond || 0;1744717448this._isValid = isDurationValid(normalizedInput);1744917450// representation for dateAddRemove17451this._milliseconds = +milliseconds +17452seconds * 1e3 + // 100017453minutes * 6e4 + // 1000 * 6017454hours * 1000 * 60 * 60; //using 1000 * 60 * 60 instead of 36e5 to avoid floating point rounding errors https://github.com/moment/moment/issues/297817455// Because of dateAddRemove treats 24 hours as different from a17456// day when working around DST, we need to store them separately17457this._days = +days +17458weeks * 7;17459// It is impossible to translate months into days without knowing17460// which months you are are talking about, so we have to store17461// it separately.17462this._months = +months +17463quarters * 3 +17464years * 12;1746517466this._data = {};1746717468this._locale = getLocale();1746917470this._bubble();17471}1747217473function isDuration (obj) {17474return obj instanceof Duration;17475}1747617477function absRound (number) {17478if (number < 0) {17479return Math.round(-1 * number) * -1;17480} else {17481return Math.round(number);17482}17483}1748417485// FORMATTING1748617487function offset (token, separator) {17488addFormatToken(token, 0, 0, function () {17489var offset = this.utcOffset();17490var sign = '+';17491if (offset < 0) {17492offset = -offset;17493sign = '-';17494}17495return sign + zeroFill(~~(offset / 60), 2) + separator + zeroFill(~~(offset) % 60, 2);17496});17497}1749817499offset('Z', ':');17500offset('ZZ', '');1750117502// PARSING1750317504addRegexToken('Z', matchShortOffset);17505addRegexToken('ZZ', matchShortOffset);17506addParseToken(['Z', 'ZZ'], function (input, array, config) {17507config._useUTC = true;17508config._tzm = offsetFromString(matchShortOffset, input);17509});1751017511// HELPERS1751217513// timezone chunker17514// '+10:00' > ['10', '00']17515// '-1530' > ['-15', '30']17516var chunkOffset = /([\+\-]|\d\d)/gi;1751717518function offsetFromString(matcher, string) {17519var matches = (string || '').match(matcher);1752017521if (matches === null) {17522return null;17523}1752417525var chunk = matches[matches.length - 1] || [];17526var parts = (chunk + '').match(chunkOffset) || ['-', 0, 0];17527var minutes = +(parts[1] * 60) + toInt(parts[2]);1752817529return minutes === 0 ?175300 :17531parts[0] === '+' ? minutes : -minutes;17532}1753317534// Return a moment from input, that is local/utc/zone equivalent to model.17535function cloneWithOffset(input, model) {17536var res, diff;17537if (model._isUTC) {17538res = model.clone();17539diff = (isMoment(input) || isDate(input) ? input.valueOf() : createLocal(input).valueOf()) - res.valueOf();17540// Use low-level api, because this fn is low-level api.17541res._d.setTime(res._d.valueOf() + diff);17542hooks.updateOffset(res, false);17543return res;17544} else {17545return createLocal(input).local();17546}17547}1754817549function getDateOffset (m) {17550// On Firefox.24 Date#getTimezoneOffset returns a floating point.17551// https://github.com/moment/moment/pull/187117552return -Math.round(m._d.getTimezoneOffset() / 15) * 15;17553}1755417555// HOOKS1755617557// This function will be called whenever a moment is mutated.17558// It is intended to keep the offset in sync with the timezone.17559hooks.updateOffset = function () {};1756017561// MOMENTS1756217563// keepLocalTime = true means only change the timezone, without17564// affecting the local hour. So 5:31:26 +0300 --[utcOffset(2, true)]-->17565// 5:31:26 +0200 It is possible that 5:31:26 doesn't exist with offset17566// +0200, so we adjust the time as needed, to be valid.17567//17568// Keeping the time actually adds/subtracts (one hour)17569// from the actual represented time. That is why we call updateOffset17570// a second time. In case it wants us to change the offset again17571// _changeInProgress == true case, then we have to adjust, because17572// there is no such time in the given timezone.17573function getSetOffset (input, keepLocalTime, keepMinutes) {17574var offset = this._offset || 0,17575localAdjust;17576if (!this.isValid()) {17577return input != null ? this : NaN;17578}17579if (input != null) {17580if (typeof input === 'string') {17581input = offsetFromString(matchShortOffset, input);17582if (input === null) {17583return this;17584}17585} else if (Math.abs(input) < 16 && !keepMinutes) {17586input = input * 60;17587}17588if (!this._isUTC && keepLocalTime) {17589localAdjust = getDateOffset(this);17590}17591this._offset = input;17592this._isUTC = true;17593if (localAdjust != null) {17594this.add(localAdjust, 'm');17595}17596if (offset !== input) {17597if (!keepLocalTime || this._changeInProgress) {17598addSubtract(this, createDuration(input - offset, 'm'), 1, false);17599} else if (!this._changeInProgress) {17600this._changeInProgress = true;17601hooks.updateOffset(this, true);17602this._changeInProgress = null;17603}17604}17605return this;17606} else {17607return this._isUTC ? offset : getDateOffset(this);17608}17609}1761017611function getSetZone (input, keepLocalTime) {17612if (input != null) {17613if (typeof input !== 'string') {17614input = -input;17615}1761617617this.utcOffset(input, keepLocalTime);1761817619return this;17620} else {17621return -this.utcOffset();17622}17623}1762417625function setOffsetToUTC (keepLocalTime) {17626return this.utcOffset(0, keepLocalTime);17627}1762817629function setOffsetToLocal (keepLocalTime) {17630if (this._isUTC) {17631this.utcOffset(0, keepLocalTime);17632this._isUTC = false;1763317634if (keepLocalTime) {17635this.subtract(getDateOffset(this), 'm');17636}17637}17638return this;17639}1764017641function setOffsetToParsedOffset () {17642if (this._tzm != null) {17643this.utcOffset(this._tzm, false, true);17644} else if (typeof this._i === 'string') {17645var tZone = offsetFromString(matchOffset, this._i);17646if (tZone != null) {17647this.utcOffset(tZone);17648}17649else {17650this.utcOffset(0, true);17651}17652}17653return this;17654}1765517656function hasAlignedHourOffset (input) {17657if (!this.isValid()) {17658return false;17659}17660input = input ? createLocal(input).utcOffset() : 0;1766117662return (this.utcOffset() - input) % 60 === 0;17663}1766417665function isDaylightSavingTime () {17666return (17667this.utcOffset() > this.clone().month(0).utcOffset() ||17668this.utcOffset() > this.clone().month(5).utcOffset()17669);17670}1767117672function isDaylightSavingTimeShifted () {17673if (!isUndefined(this._isDSTShifted)) {17674return this._isDSTShifted;17675}1767617677var c = {};1767817679copyConfig(c, this);17680c = prepareConfig(c);1768117682if (c._a) {17683var other = c._isUTC ? createUTC(c._a) : createLocal(c._a);17684this._isDSTShifted = this.isValid() &&17685compareArrays(c._a, other.toArray()) > 0;17686} else {17687this._isDSTShifted = false;17688}1768917690return this._isDSTShifted;17691}1769217693function isLocal () {17694return this.isValid() ? !this._isUTC : false;17695}1769617697function isUtcOffset () {17698return this.isValid() ? this._isUTC : false;17699}1770017701function isUtc () {17702return this.isValid() ? this._isUTC && this._offset === 0 : false;17703}1770417705// ASP.NET json date format regex17706var aspNetRegex = /^(\-|\+)?(?:(\d*)[. ])?(\d+)\:(\d+)(?:\:(\d+)(\.\d*)?)?$/;1770717708// from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html17709// somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere17710// and further modified to allow for strings containing both week and day17711var isoRegex = /^(-|\+)?P(?:([-+]?[0-9,.]*)Y)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)W)?(?:([-+]?[0-9,.]*)D)?(?:T(?:([-+]?[0-9,.]*)H)?(?:([-+]?[0-9,.]*)M)?(?:([-+]?[0-9,.]*)S)?)?$/;1771217713function createDuration (input, key) {17714var duration = input,17715// matching against regexp is expensive, do it on demand17716match = null,17717sign,17718ret,17719diffRes;1772017721if (isDuration(input)) {17722duration = {17723ms : input._milliseconds,17724d : input._days,17725M : input._months17726};17727} else if (isNumber(input)) {17728duration = {};17729if (key) {17730duration[key] = input;17731} else {17732duration.milliseconds = input;17733}17734} else if (!!(match = aspNetRegex.exec(input))) {17735sign = (match[1] === '-') ? -1 : 1;17736duration = {17737y : 0,17738d : toInt(match[DATE]) * sign,17739h : toInt(match[HOUR]) * sign,17740m : toInt(match[MINUTE]) * sign,17741s : toInt(match[SECOND]) * sign,17742ms : toInt(absRound(match[MILLISECOND] * 1000)) * sign // the millisecond decimal point is included in the match17743};17744} else if (!!(match = isoRegex.exec(input))) {17745sign = (match[1] === '-') ? -1 : 1;17746duration = {17747y : parseIso(match[2], sign),17748M : parseIso(match[3], sign),17749w : parseIso(match[4], sign),17750d : parseIso(match[5], sign),17751h : parseIso(match[6], sign),17752m : parseIso(match[7], sign),17753s : parseIso(match[8], sign)17754};17755} else if (duration == null) {// checks for null or undefined17756duration = {};17757} else if (typeof duration === 'object' && ('from' in duration || 'to' in duration)) {17758diffRes = momentsDifference(createLocal(duration.from), createLocal(duration.to));1775917760duration = {};17761duration.ms = diffRes.milliseconds;17762duration.M = diffRes.months;17763}1776417765ret = new Duration(duration);1776617767if (isDuration(input) && hasOwnProp(input, '_locale')) {17768ret._locale = input._locale;17769}1777017771return ret;17772}1777317774createDuration.fn = Duration.prototype;17775createDuration.invalid = createInvalid$1;1777617777function parseIso (inp, sign) {17778// We'd normally use ~~inp for this, but unfortunately it also17779// converts floats to ints.17780// inp may be undefined, so careful calling replace on it.17781var res = inp && parseFloat(inp.replace(',', '.'));17782// apply sign while we're at it17783return (isNaN(res) ? 0 : res) * sign;17784}1778517786function positiveMomentsDifference(base, other) {17787var res = {};1778817789res.months = other.month() - base.month() +17790(other.year() - base.year()) * 12;17791if (base.clone().add(res.months, 'M').isAfter(other)) {17792--res.months;17793}1779417795res.milliseconds = +other - +(base.clone().add(res.months, 'M'));1779617797return res;17798}1779917800function momentsDifference(base, other) {17801var res;17802if (!(base.isValid() && other.isValid())) {17803return {milliseconds: 0, months: 0};17804}1780517806other = cloneWithOffset(other, base);17807if (base.isBefore(other)) {17808res = positiveMomentsDifference(base, other);17809} else {17810res = positiveMomentsDifference(other, base);17811res.milliseconds = -res.milliseconds;17812res.months = -res.months;17813}1781417815return res;17816}1781717818// TODO: remove 'name' arg after deprecation is removed17819function createAdder(direction, name) {17820return function (val, period) {17821var dur, tmp;17822//invert the arguments, but complain about it17823if (period !== null && !isNaN(+period)) {17824deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period). ' +17825'See http://momentjs.com/guides/#/warnings/add-inverted-param/ for more info.');17826tmp = val; val = period; period = tmp;17827}1782817829val = typeof val === 'string' ? +val : val;17830dur = createDuration(val, period);17831addSubtract(this, dur, direction);17832return this;17833};17834}1783517836function addSubtract (mom, duration, isAdding, updateOffset) {17837var milliseconds = duration._milliseconds,17838days = absRound(duration._days),17839months = absRound(duration._months);1784017841if (!mom.isValid()) {17842// No op17843return;17844}1784517846updateOffset = updateOffset == null ? true : updateOffset;1784717848if (months) {17849setMonth(mom, get(mom, 'Month') + months * isAdding);17850}17851if (days) {17852set$1(mom, 'Date', get(mom, 'Date') + days * isAdding);17853}17854if (milliseconds) {17855mom._d.setTime(mom._d.valueOf() + milliseconds * isAdding);17856}17857if (updateOffset) {17858hooks.updateOffset(mom, days || months);17859}17860}1786117862var add = createAdder(1, 'add');17863var subtract = createAdder(-1, 'subtract');1786417865function getCalendarFormat(myMoment, now) {17866var diff = myMoment.diff(now, 'days', true);17867return diff < -6 ? 'sameElse' :17868diff < -1 ? 'lastWeek' :17869diff < 0 ? 'lastDay' :17870diff < 1 ? 'sameDay' :17871diff < 2 ? 'nextDay' :17872diff < 7 ? 'nextWeek' : 'sameElse';17873}1787417875function calendar$1 (time, formats) {17876// We want to compare the start of today, vs this.17877// Getting start-of-today depends on whether we're local/utc/offset or not.17878var now = time || createLocal(),17879sod = cloneWithOffset(now, this).startOf('day'),17880format = hooks.calendarFormat(this, sod) || 'sameElse';1788117882var output = formats && (isFunction(formats[format]) ? formats[format].call(this, now) : formats[format]);1788317884return this.format(output || this.localeData().calendar(format, this, createLocal(now)));17885}1788617887function clone () {17888return new Moment(this);17889}1789017891function isAfter (input, units) {17892var localInput = isMoment(input) ? input : createLocal(input);17893if (!(this.isValid() && localInput.isValid())) {17894return false;17895}17896units = normalizeUnits(units) || 'millisecond';17897if (units === 'millisecond') {17898return this.valueOf() > localInput.valueOf();17899} else {17900return localInput.valueOf() < this.clone().startOf(units).valueOf();17901}17902}1790317904function isBefore (input, units) {17905var localInput = isMoment(input) ? input : createLocal(input);17906if (!(this.isValid() && localInput.isValid())) {17907return false;17908}17909units = normalizeUnits(units) || 'millisecond';17910if (units === 'millisecond') {17911return this.valueOf() < localInput.valueOf();17912} else {17913return this.clone().endOf(units).valueOf() < localInput.valueOf();17914}17915}1791617917function isBetween (from, to, units, inclusivity) {17918var localFrom = isMoment(from) ? from : createLocal(from),17919localTo = isMoment(to) ? to : createLocal(to);17920if (!(this.isValid() && localFrom.isValid() && localTo.isValid())) {17921return false;17922}17923inclusivity = inclusivity || '()';17924return (inclusivity[0] === '(' ? this.isAfter(localFrom, units) : !this.isBefore(localFrom, units)) &&17925(inclusivity[1] === ')' ? this.isBefore(localTo, units) : !this.isAfter(localTo, units));17926}1792717928function isSame (input, units) {17929var localInput = isMoment(input) ? input : createLocal(input),17930inputMs;17931if (!(this.isValid() && localInput.isValid())) {17932return false;17933}17934units = normalizeUnits(units) || 'millisecond';17935if (units === 'millisecond') {17936return this.valueOf() === localInput.valueOf();17937} else {17938inputMs = localInput.valueOf();17939return this.clone().startOf(units).valueOf() <= inputMs && inputMs <= this.clone().endOf(units).valueOf();17940}17941}1794217943function isSameOrAfter (input, units) {17944return this.isSame(input, units) || this.isAfter(input, units);17945}1794617947function isSameOrBefore (input, units) {17948return this.isSame(input, units) || this.isBefore(input, units);17949}1795017951function diff (input, units, asFloat) {17952var that,17953zoneDelta,17954output;1795517956if (!this.isValid()) {17957return NaN;17958}1795917960that = cloneWithOffset(input, this);1796117962if (!that.isValid()) {17963return NaN;17964}1796517966zoneDelta = (that.utcOffset() - this.utcOffset()) * 6e4;1796717968units = normalizeUnits(units);1796917970switch (units) {17971case 'year': output = monthDiff(this, that) / 12; break;17972case 'month': output = monthDiff(this, that); break;17973case 'quarter': output = monthDiff(this, that) / 3; break;17974case 'second': output = (this - that) / 1e3; break; // 100017975case 'minute': output = (this - that) / 6e4; break; // 1000 * 6017976case 'hour': output = (this - that) / 36e5; break; // 1000 * 60 * 6017977case 'day': output = (this - that - zoneDelta) / 864e5; break; // 1000 * 60 * 60 * 24, negate dst17978case 'week': output = (this - that - zoneDelta) / 6048e5; break; // 1000 * 60 * 60 * 24 * 7, negate dst17979default: output = this - that;17980}1798117982return asFloat ? output : absFloor(output);17983}1798417985function monthDiff (a, b) {17986// difference in months17987var wholeMonthDiff = ((b.year() - a.year()) * 12) + (b.month() - a.month()),17988// b is in (anchor - 1 month, anchor + 1 month)17989anchor = a.clone().add(wholeMonthDiff, 'months'),17990anchor2, adjust;1799117992if (b - anchor < 0) {17993anchor2 = a.clone().add(wholeMonthDiff - 1, 'months');17994// linear across the month17995adjust = (b - anchor) / (anchor - anchor2);17996} else {17997anchor2 = a.clone().add(wholeMonthDiff + 1, 'months');17998// linear across the month17999adjust = (b - anchor) / (anchor2 - anchor);18000}1800118002//check for negative zero, return zero if negative zero18003return -(wholeMonthDiff + adjust) || 0;18004}1800518006hooks.defaultFormat = 'YYYY-MM-DDTHH:mm:ssZ';18007hooks.defaultFormatUtc = 'YYYY-MM-DDTHH:mm:ss[Z]';1800818009function toString () {18010return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ');18011}1801218013function toISOString(keepOffset) {18014if (!this.isValid()) {18015return null;18016}18017var utc = keepOffset !== true;18018var m = utc ? this.clone().utc() : this;18019if (m.year() < 0 || m.year() > 9999) {18020return formatMoment(m, utc ? 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYYYY-MM-DD[T]HH:mm:ss.SSSZ');18021}18022if (isFunction(Date.prototype.toISOString)) {18023// native implementation is ~50x faster, use it when we can18024if (utc) {18025return this.toDate().toISOString();18026} else {18027return new Date(this.valueOf() + this.utcOffset() * 60 * 1000).toISOString().replace('Z', formatMoment(m, 'Z'));18028}18029}18030return formatMoment(m, utc ? 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]' : 'YYYY-MM-DD[T]HH:mm:ss.SSSZ');18031}1803218033/**18034* Return a human readable representation of a moment that can18035* also be evaluated to get a new moment which is the same18036*18037* @link https://nodejs.org/dist/latest/docs/api/util.html#util_custom_inspect_function_on_objects18038*/18039function inspect () {18040if (!this.isValid()) {18041return 'moment.invalid(/* ' + this._i + ' */)';18042}18043var func = 'moment';18044var zone = '';18045if (!this.isLocal()) {18046func = this.utcOffset() === 0 ? 'moment.utc' : 'moment.parseZone';18047zone = 'Z';18048}18049var prefix = '[' + func + '("]';18050var year = (0 <= this.year() && this.year() <= 9999) ? 'YYYY' : 'YYYYYY';18051var datetime = '-MM-DD[T]HH:mm:ss.SSS';18052var suffix = zone + '[")]';1805318054return this.format(prefix + year + datetime + suffix);18055}1805618057function format (inputString) {18058if (!inputString) {18059inputString = this.isUtc() ? hooks.defaultFormatUtc : hooks.defaultFormat;18060}18061var output = formatMoment(this, inputString);18062return this.localeData().postformat(output);18063}1806418065function from (time, withoutSuffix) {18066if (this.isValid() &&18067((isMoment(time) && time.isValid()) ||18068createLocal(time).isValid())) {18069return createDuration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix);18070} else {18071return this.localeData().invalidDate();18072}18073}1807418075function fromNow (withoutSuffix) {18076return this.from(createLocal(), withoutSuffix);18077}1807818079function to (time, withoutSuffix) {18080if (this.isValid() &&18081((isMoment(time) && time.isValid()) ||18082createLocal(time).isValid())) {18083return createDuration({from: this, to: time}).locale(this.locale()).humanize(!withoutSuffix);18084} else {18085return this.localeData().invalidDate();18086}18087}1808818089function toNow (withoutSuffix) {18090return this.to(createLocal(), withoutSuffix);18091}1809218093// If passed a locale key, it will set the locale for this18094// instance. Otherwise, it will return the locale configuration18095// variables for this instance.18096function locale (key) {18097var newLocaleData;1809818099if (key === undefined) {18100return this._locale._abbr;18101} else {18102newLocaleData = getLocale(key);18103if (newLocaleData != null) {18104this._locale = newLocaleData;18105}18106return this;18107}18108}1810918110var lang = deprecate(18111'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',18112function (key) {18113if (key === undefined) {18114return this.localeData();18115} else {18116return this.locale(key);18117}18118}18119);1812018121function localeData () {18122return this._locale;18123}1812418125var MS_PER_SECOND = 1000;18126var MS_PER_MINUTE = 60 * MS_PER_SECOND;18127var MS_PER_HOUR = 60 * MS_PER_MINUTE;18128var MS_PER_400_YEARS = (365 * 400 + 97) * 24 * MS_PER_HOUR;1812918130// actual modulo - handles negative numbers (for dates before 1970):18131function mod$1(dividend, divisor) {18132return (dividend % divisor + divisor) % divisor;18133}1813418135function localStartOfDate(y, m, d) {18136// the date constructor remaps years 0-99 to 1900-199918137if (y < 100 && y >= 0) {18138// preserve leap years using a full 400 year cycle, then reset18139return new Date(y + 400, m, d) - MS_PER_400_YEARS;18140} else {18141return new Date(y, m, d).valueOf();18142}18143}1814418145function utcStartOfDate(y, m, d) {18146// Date.UTC remaps years 0-99 to 1900-199918147if (y < 100 && y >= 0) {18148// preserve leap years using a full 400 year cycle, then reset18149return Date.UTC(y + 400, m, d) - MS_PER_400_YEARS;18150} else {18151return Date.UTC(y, m, d);18152}18153}1815418155function startOf (units) {18156var time;18157units = normalizeUnits(units);18158if (units === undefined || units === 'millisecond' || !this.isValid()) {18159return this;18160}1816118162var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;1816318164switch (units) {18165case 'year':18166time = startOfDate(this.year(), 0, 1);18167break;18168case 'quarter':18169time = startOfDate(this.year(), this.month() - this.month() % 3, 1);18170break;18171case 'month':18172time = startOfDate(this.year(), this.month(), 1);18173break;18174case 'week':18175time = startOfDate(this.year(), this.month(), this.date() - this.weekday());18176break;18177case 'isoWeek':18178time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1));18179break;18180case 'day':18181case 'date':18182time = startOfDate(this.year(), this.month(), this.date());18183break;18184case 'hour':18185time = this._d.valueOf();18186time -= mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR);18187break;18188case 'minute':18189time = this._d.valueOf();18190time -= mod$1(time, MS_PER_MINUTE);18191break;18192case 'second':18193time = this._d.valueOf();18194time -= mod$1(time, MS_PER_SECOND);18195break;18196}1819718198this._d.setTime(time);18199hooks.updateOffset(this, true);18200return this;18201}1820218203function endOf (units) {18204var time;18205units = normalizeUnits(units);18206if (units === undefined || units === 'millisecond' || !this.isValid()) {18207return this;18208}1820918210var startOfDate = this._isUTC ? utcStartOfDate : localStartOfDate;1821118212switch (units) {18213case 'year':18214time = startOfDate(this.year() + 1, 0, 1) - 1;18215break;18216case 'quarter':18217time = startOfDate(this.year(), this.month() - this.month() % 3 + 3, 1) - 1;18218break;18219case 'month':18220time = startOfDate(this.year(), this.month() + 1, 1) - 1;18221break;18222case 'week':18223time = startOfDate(this.year(), this.month(), this.date() - this.weekday() + 7) - 1;18224break;18225case 'isoWeek':18226time = startOfDate(this.year(), this.month(), this.date() - (this.isoWeekday() - 1) + 7) - 1;18227break;18228case 'day':18229case 'date':18230time = startOfDate(this.year(), this.month(), this.date() + 1) - 1;18231break;18232case 'hour':18233time = this._d.valueOf();18234time += MS_PER_HOUR - mod$1(time + (this._isUTC ? 0 : this.utcOffset() * MS_PER_MINUTE), MS_PER_HOUR) - 1;18235break;18236case 'minute':18237time = this._d.valueOf();18238time += MS_PER_MINUTE - mod$1(time, MS_PER_MINUTE) - 1;18239break;18240case 'second':18241time = this._d.valueOf();18242time += MS_PER_SECOND - mod$1(time, MS_PER_SECOND) - 1;18243break;18244}1824518246this._d.setTime(time);18247hooks.updateOffset(this, true);18248return this;18249}1825018251function valueOf () {18252return this._d.valueOf() - ((this._offset || 0) * 60000);18253}1825418255function unix () {18256return Math.floor(this.valueOf() / 1000);18257}1825818259function toDate () {18260return new Date(this.valueOf());18261}1826218263function toArray () {18264var m = this;18265return [m.year(), m.month(), m.date(), m.hour(), m.minute(), m.second(), m.millisecond()];18266}1826718268function toObject () {18269var m = this;18270return {18271years: m.year(),18272months: m.month(),18273date: m.date(),18274hours: m.hours(),18275minutes: m.minutes(),18276seconds: m.seconds(),18277milliseconds: m.milliseconds()18278};18279}1828018281function toJSON () {18282// new Date(NaN).toJSON() === null18283return this.isValid() ? this.toISOString() : null;18284}1828518286function isValid$2 () {18287return isValid(this);18288}1828918290function parsingFlags () {18291return extend({}, getParsingFlags(this));18292}1829318294function invalidAt () {18295return getParsingFlags(this).overflow;18296}1829718298function creationData() {18299return {18300input: this._i,18301format: this._f,18302locale: this._locale,18303isUTC: this._isUTC,18304strict: this._strict18305};18306}1830718308// FORMATTING1830918310addFormatToken(0, ['gg', 2], 0, function () {18311return this.weekYear() % 100;18312});1831318314addFormatToken(0, ['GG', 2], 0, function () {18315return this.isoWeekYear() % 100;18316});1831718318function addWeekYearFormatToken (token, getter) {18319addFormatToken(0, [token, token.length], 0, getter);18320}1832118322addWeekYearFormatToken('gggg', 'weekYear');18323addWeekYearFormatToken('ggggg', 'weekYear');18324addWeekYearFormatToken('GGGG', 'isoWeekYear');18325addWeekYearFormatToken('GGGGG', 'isoWeekYear');1832618327// ALIASES1832818329addUnitAlias('weekYear', 'gg');18330addUnitAlias('isoWeekYear', 'GG');1833118332// PRIORITY1833318334addUnitPriority('weekYear', 1);18335addUnitPriority('isoWeekYear', 1);183361833718338// PARSING1833918340addRegexToken('G', matchSigned);18341addRegexToken('g', matchSigned);18342addRegexToken('GG', match1to2, match2);18343addRegexToken('gg', match1to2, match2);18344addRegexToken('GGGG', match1to4, match4);18345addRegexToken('gggg', match1to4, match4);18346addRegexToken('GGGGG', match1to6, match6);18347addRegexToken('ggggg', match1to6, match6);1834818349addWeekParseToken(['gggg', 'ggggg', 'GGGG', 'GGGGG'], function (input, week, config, token) {18350week[token.substr(0, 2)] = toInt(input);18351});1835218353addWeekParseToken(['gg', 'GG'], function (input, week, config, token) {18354week[token] = hooks.parseTwoDigitYear(input);18355});1835618357// MOMENTS1835818359function getSetWeekYear (input) {18360return getSetWeekYearHelper.call(this,18361input,18362this.week(),18363this.weekday(),18364this.localeData()._week.dow,18365this.localeData()._week.doy);18366}1836718368function getSetISOWeekYear (input) {18369return getSetWeekYearHelper.call(this,18370input, this.isoWeek(), this.isoWeekday(), 1, 4);18371}1837218373function getISOWeeksInYear () {18374return weeksInYear(this.year(), 1, 4);18375}1837618377function getWeeksInYear () {18378var weekInfo = this.localeData()._week;18379return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy);18380}1838118382function getSetWeekYearHelper(input, week, weekday, dow, doy) {18383var weeksTarget;18384if (input == null) {18385return weekOfYear(this, dow, doy).year;18386} else {18387weeksTarget = weeksInYear(input, dow, doy);18388if (week > weeksTarget) {18389week = weeksTarget;18390}18391return setWeekAll.call(this, input, week, weekday, dow, doy);18392}18393}1839418395function setWeekAll(weekYear, week, weekday, dow, doy) {18396var dayOfYearData = dayOfYearFromWeeks(weekYear, week, weekday, dow, doy),18397date = createUTCDate(dayOfYearData.year, 0, dayOfYearData.dayOfYear);1839818399this.year(date.getUTCFullYear());18400this.month(date.getUTCMonth());18401this.date(date.getUTCDate());18402return this;18403}1840418405// FORMATTING1840618407addFormatToken('Q', 0, 'Qo', 'quarter');1840818409// ALIASES1841018411addUnitAlias('quarter', 'Q');1841218413// PRIORITY1841418415addUnitPriority('quarter', 7);1841618417// PARSING1841818419addRegexToken('Q', match1);18420addParseToken('Q', function (input, array) {18421array[MONTH] = (toInt(input) - 1) * 3;18422});1842318424// MOMENTS1842518426function getSetQuarter (input) {18427return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3);18428}1842918430// FORMATTING1843118432addFormatToken('D', ['DD', 2], 'Do', 'date');1843318434// ALIASES1843518436addUnitAlias('date', 'D');1843718438// PRIORITY18439addUnitPriority('date', 9);1844018441// PARSING1844218443addRegexToken('D', match1to2);18444addRegexToken('DD', match1to2, match2);18445addRegexToken('Do', function (isStrict, locale) {18446// TODO: Remove "ordinalParse" fallback in next major release.18447return isStrict ?18448(locale._dayOfMonthOrdinalParse || locale._ordinalParse) :18449locale._dayOfMonthOrdinalParseLenient;18450});1845118452addParseToken(['D', 'DD'], DATE);18453addParseToken('Do', function (input, array) {18454array[DATE] = toInt(input.match(match1to2)[0]);18455});1845618457// MOMENTS1845818459var getSetDayOfMonth = makeGetSet('Date', true);1846018461// FORMATTING1846218463addFormatToken('DDD', ['DDDD', 3], 'DDDo', 'dayOfYear');1846418465// ALIASES1846618467addUnitAlias('dayOfYear', 'DDD');1846818469// PRIORITY18470addUnitPriority('dayOfYear', 4);1847118472// PARSING1847318474addRegexToken('DDD', match1to3);18475addRegexToken('DDDD', match3);18476addParseToken(['DDD', 'DDDD'], function (input, array, config) {18477config._dayOfYear = toInt(input);18478});1847918480// HELPERS1848118482// MOMENTS1848318484function getSetDayOfYear (input) {18485var dayOfYear = Math.round((this.clone().startOf('day') - this.clone().startOf('year')) / 864e5) + 1;18486return input == null ? dayOfYear : this.add((input - dayOfYear), 'd');18487}1848818489// FORMATTING1849018491addFormatToken('m', ['mm', 2], 0, 'minute');1849218493// ALIASES1849418495addUnitAlias('minute', 'm');1849618497// PRIORITY1849818499addUnitPriority('minute', 14);1850018501// PARSING1850218503addRegexToken('m', match1to2);18504addRegexToken('mm', match1to2, match2);18505addParseToken(['m', 'mm'], MINUTE);1850618507// MOMENTS1850818509var getSetMinute = makeGetSet('Minutes', false);1851018511// FORMATTING1851218513addFormatToken('s', ['ss', 2], 0, 'second');1851418515// ALIASES1851618517addUnitAlias('second', 's');1851818519// PRIORITY1852018521addUnitPriority('second', 15);1852218523// PARSING1852418525addRegexToken('s', match1to2);18526addRegexToken('ss', match1to2, match2);18527addParseToken(['s', 'ss'], SECOND);1852818529// MOMENTS1853018531var getSetSecond = makeGetSet('Seconds', false);1853218533// FORMATTING1853418535addFormatToken('S', 0, 0, function () {18536return ~~(this.millisecond() / 100);18537});1853818539addFormatToken(0, ['SS', 2], 0, function () {18540return ~~(this.millisecond() / 10);18541});1854218543addFormatToken(0, ['SSS', 3], 0, 'millisecond');18544addFormatToken(0, ['SSSS', 4], 0, function () {18545return this.millisecond() * 10;18546});18547addFormatToken(0, ['SSSSS', 5], 0, function () {18548return this.millisecond() * 100;18549});18550addFormatToken(0, ['SSSSSS', 6], 0, function () {18551return this.millisecond() * 1000;18552});18553addFormatToken(0, ['SSSSSSS', 7], 0, function () {18554return this.millisecond() * 10000;18555});18556addFormatToken(0, ['SSSSSSSS', 8], 0, function () {18557return this.millisecond() * 100000;18558});18559addFormatToken(0, ['SSSSSSSSS', 9], 0, function () {18560return this.millisecond() * 1000000;18561});185621856318564// ALIASES1856518566addUnitAlias('millisecond', 'ms');1856718568// PRIORITY1856918570addUnitPriority('millisecond', 16);1857118572// PARSING1857318574addRegexToken('S', match1to3, match1);18575addRegexToken('SS', match1to3, match2);18576addRegexToken('SSS', match1to3, match3);1857718578var token;18579for (token = 'SSSS'; token.length <= 9; token += 'S') {18580addRegexToken(token, matchUnsigned);18581}1858218583function parseMs(input, array) {18584array[MILLISECOND] = toInt(('0.' + input) * 1000);18585}1858618587for (token = 'S'; token.length <= 9; token += 'S') {18588addParseToken(token, parseMs);18589}18590// MOMENTS1859118592var getSetMillisecond = makeGetSet('Milliseconds', false);1859318594// FORMATTING1859518596addFormatToken('z', 0, 0, 'zoneAbbr');18597addFormatToken('zz', 0, 0, 'zoneName');1859818599// MOMENTS1860018601function getZoneAbbr () {18602return this._isUTC ? 'UTC' : '';18603}1860418605function getZoneName () {18606return this._isUTC ? 'Coordinated Universal Time' : '';18607}1860818609var proto = Moment.prototype;1861018611proto.add = add;18612proto.calendar = calendar$1;18613proto.clone = clone;18614proto.diff = diff;18615proto.endOf = endOf;18616proto.format = format;18617proto.from = from;18618proto.fromNow = fromNow;18619proto.to = to;18620proto.toNow = toNow;18621proto.get = stringGet;18622proto.invalidAt = invalidAt;18623proto.isAfter = isAfter;18624proto.isBefore = isBefore;18625proto.isBetween = isBetween;18626proto.isSame = isSame;18627proto.isSameOrAfter = isSameOrAfter;18628proto.isSameOrBefore = isSameOrBefore;18629proto.isValid = isValid$2;18630proto.lang = lang;18631proto.locale = locale;18632proto.localeData = localeData;18633proto.max = prototypeMax;18634proto.min = prototypeMin;18635proto.parsingFlags = parsingFlags;18636proto.set = stringSet;18637proto.startOf = startOf;18638proto.subtract = subtract;18639proto.toArray = toArray;18640proto.toObject = toObject;18641proto.toDate = toDate;18642proto.toISOString = toISOString;18643proto.inspect = inspect;18644proto.toJSON = toJSON;18645proto.toString = toString;18646proto.unix = unix;18647proto.valueOf = valueOf;18648proto.creationData = creationData;18649proto.year = getSetYear;18650proto.isLeapYear = getIsLeapYear;18651proto.weekYear = getSetWeekYear;18652proto.isoWeekYear = getSetISOWeekYear;18653proto.quarter = proto.quarters = getSetQuarter;18654proto.month = getSetMonth;18655proto.daysInMonth = getDaysInMonth;18656proto.week = proto.weeks = getSetWeek;18657proto.isoWeek = proto.isoWeeks = getSetISOWeek;18658proto.weeksInYear = getWeeksInYear;18659proto.isoWeeksInYear = getISOWeeksInYear;18660proto.date = getSetDayOfMonth;18661proto.day = proto.days = getSetDayOfWeek;18662proto.weekday = getSetLocaleDayOfWeek;18663proto.isoWeekday = getSetISODayOfWeek;18664proto.dayOfYear = getSetDayOfYear;18665proto.hour = proto.hours = getSetHour;18666proto.minute = proto.minutes = getSetMinute;18667proto.second = proto.seconds = getSetSecond;18668proto.millisecond = proto.milliseconds = getSetMillisecond;18669proto.utcOffset = getSetOffset;18670proto.utc = setOffsetToUTC;18671proto.local = setOffsetToLocal;18672proto.parseZone = setOffsetToParsedOffset;18673proto.hasAlignedHourOffset = hasAlignedHourOffset;18674proto.isDST = isDaylightSavingTime;18675proto.isLocal = isLocal;18676proto.isUtcOffset = isUtcOffset;18677proto.isUtc = isUtc;18678proto.isUTC = isUtc;18679proto.zoneAbbr = getZoneAbbr;18680proto.zoneName = getZoneName;18681proto.dates = deprecate('dates accessor is deprecated. Use date instead.', getSetDayOfMonth);18682proto.months = deprecate('months accessor is deprecated. Use month instead', getSetMonth);18683proto.years = deprecate('years accessor is deprecated. Use year instead', getSetYear);18684proto.zone = deprecate('moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/', getSetZone);18685proto.isDSTShifted = deprecate('isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information', isDaylightSavingTimeShifted);1868618687function createUnix (input) {18688return createLocal(input * 1000);18689}1869018691function createInZone () {18692return createLocal.apply(null, arguments).parseZone();18693}1869418695function preParsePostFormat (string) {18696return string;18697}1869818699var proto$1 = Locale.prototype;1870018701proto$1.calendar = calendar;18702proto$1.longDateFormat = longDateFormat;18703proto$1.invalidDate = invalidDate;18704proto$1.ordinal = ordinal;18705proto$1.preparse = preParsePostFormat;18706proto$1.postformat = preParsePostFormat;18707proto$1.relativeTime = relativeTime;18708proto$1.pastFuture = pastFuture;18709proto$1.set = set;1871018711proto$1.months = localeMonths;18712proto$1.monthsShort = localeMonthsShort;18713proto$1.monthsParse = localeMonthsParse;18714proto$1.monthsRegex = monthsRegex;18715proto$1.monthsShortRegex = monthsShortRegex;18716proto$1.week = localeWeek;18717proto$1.firstDayOfYear = localeFirstDayOfYear;18718proto$1.firstDayOfWeek = localeFirstDayOfWeek;1871918720proto$1.weekdays = localeWeekdays;18721proto$1.weekdaysMin = localeWeekdaysMin;18722proto$1.weekdaysShort = localeWeekdaysShort;18723proto$1.weekdaysParse = localeWeekdaysParse;1872418725proto$1.weekdaysRegex = weekdaysRegex;18726proto$1.weekdaysShortRegex = weekdaysShortRegex;18727proto$1.weekdaysMinRegex = weekdaysMinRegex;1872818729proto$1.isPM = localeIsPM;18730proto$1.meridiem = localeMeridiem;1873118732function get$1 (format, index, field, setter) {18733var locale = getLocale();18734var utc = createUTC().set(setter, index);18735return locale[field](utc, format);18736}1873718738function listMonthsImpl (format, index, field) {18739if (isNumber(format)) {18740index = format;18741format = undefined;18742}1874318744format = format || '';1874518746if (index != null) {18747return get$1(format, index, field, 'month');18748}1874918750var i;18751var out = [];18752for (i = 0; i < 12; i++) {18753out[i] = get$1(format, i, field, 'month');18754}18755return out;18756}1875718758// ()18759// (5)18760// (fmt, 5)18761// (fmt)18762// (true)18763// (true, 5)18764// (true, fmt, 5)18765// (true, fmt)18766function listWeekdaysImpl (localeSorted, format, index, field) {18767if (typeof localeSorted === 'boolean') {18768if (isNumber(format)) {18769index = format;18770format = undefined;18771}1877218773format = format || '';18774} else {18775format = localeSorted;18776index = format;18777localeSorted = false;1877818779if (isNumber(format)) {18780index = format;18781format = undefined;18782}1878318784format = format || '';18785}1878618787var locale = getLocale(),18788shift = localeSorted ? locale._week.dow : 0;1878918790if (index != null) {18791return get$1(format, (index + shift) % 7, field, 'day');18792}1879318794var i;18795var out = [];18796for (i = 0; i < 7; i++) {18797out[i] = get$1(format, (i + shift) % 7, field, 'day');18798}18799return out;18800}1880118802function listMonths (format, index) {18803return listMonthsImpl(format, index, 'months');18804}1880518806function listMonthsShort (format, index) {18807return listMonthsImpl(format, index, 'monthsShort');18808}1880918810function listWeekdays (localeSorted, format, index) {18811return listWeekdaysImpl(localeSorted, format, index, 'weekdays');18812}1881318814function listWeekdaysShort (localeSorted, format, index) {18815return listWeekdaysImpl(localeSorted, format, index, 'weekdaysShort');18816}1881718818function listWeekdaysMin (localeSorted, format, index) {18819return listWeekdaysImpl(localeSorted, format, index, 'weekdaysMin');18820}1882118822getSetGlobalLocale('en', {18823dayOfMonthOrdinalParse: /\d{1,2}(th|st|nd|rd)/,18824ordinal : function (number) {18825var b = number % 10,18826output = (toInt(number % 100 / 10) === 1) ? 'th' :18827(b === 1) ? 'st' :18828(b === 2) ? 'nd' :18829(b === 3) ? 'rd' : 'th';18830return number + output;18831}18832});1883318834// Side effect imports1883518836hooks.lang = deprecate('moment.lang is deprecated. Use moment.locale instead.', getSetGlobalLocale);18837hooks.langData = deprecate('moment.langData is deprecated. Use moment.localeData instead.', getLocale);1883818839var mathAbs = Math.abs;1884018841function abs () {18842var data = this._data;1884318844this._milliseconds = mathAbs(this._milliseconds);18845this._days = mathAbs(this._days);18846this._months = mathAbs(this._months);1884718848data.milliseconds = mathAbs(data.milliseconds);18849data.seconds = mathAbs(data.seconds);18850data.minutes = mathAbs(data.minutes);18851data.hours = mathAbs(data.hours);18852data.months = mathAbs(data.months);18853data.years = mathAbs(data.years);1885418855return this;18856}1885718858function addSubtract$1 (duration, input, value, direction) {18859var other = createDuration(input, value);1886018861duration._milliseconds += direction * other._milliseconds;18862duration._days += direction * other._days;18863duration._months += direction * other._months;1886418865return duration._bubble();18866}1886718868// supports only 2.0-style add(1, 's') or add(duration)18869function add$1 (input, value) {18870return addSubtract$1(this, input, value, 1);18871}1887218873// supports only 2.0-style subtract(1, 's') or subtract(duration)18874function subtract$1 (input, value) {18875return addSubtract$1(this, input, value, -1);18876}1887718878function absCeil (number) {18879if (number < 0) {18880return Math.floor(number);18881} else {18882return Math.ceil(number);18883}18884}1888518886function bubble () {18887var milliseconds = this._milliseconds;18888var days = this._days;18889var months = this._months;18890var data = this._data;18891var seconds, minutes, hours, years, monthsFromDays;1889218893// if we have a mix of positive and negative values, bubble down first18894// check: https://github.com/moment/moment/issues/216618895if (!((milliseconds >= 0 && days >= 0 && months >= 0) ||18896(milliseconds <= 0 && days <= 0 && months <= 0))) {18897milliseconds += absCeil(monthsToDays(months) + days) * 864e5;18898days = 0;18899months = 0;18900}1890118902// The following code bubbles up values, see the tests for18903// examples of what that means.18904data.milliseconds = milliseconds % 1000;1890518906seconds = absFloor(milliseconds / 1000);18907data.seconds = seconds % 60;1890818909minutes = absFloor(seconds / 60);18910data.minutes = minutes % 60;1891118912hours = absFloor(minutes / 60);18913data.hours = hours % 24;1891418915days += absFloor(hours / 24);1891618917// convert days to months18918monthsFromDays = absFloor(daysToMonths(days));18919months += monthsFromDays;18920days -= absCeil(monthsToDays(monthsFromDays));1892118922// 12 months -> 1 year18923years = absFloor(months / 12);18924months %= 12;1892518926data.days = days;18927data.months = months;18928data.years = years;1892918930return this;18931}1893218933function daysToMonths (days) {18934// 400 years have 146097 days (taking into account leap year rules)18935// 400 years have 12 months === 480018936return days * 4800 / 146097;18937}1893818939function monthsToDays (months) {18940// the reverse of daysToMonths18941return months * 146097 / 4800;18942}1894318944function as (units) {18945if (!this.isValid()) {18946return NaN;18947}18948var days;18949var months;18950var milliseconds = this._milliseconds;1895118952units = normalizeUnits(units);1895318954if (units === 'month' || units === 'quarter' || units === 'year') {18955days = this._days + milliseconds / 864e5;18956months = this._months + daysToMonths(days);18957switch (units) {18958case 'month': return months;18959case 'quarter': return months / 3;18960case 'year': return months / 12;18961}18962} else {18963// handle milliseconds separately because of floating point math errors (issue #1867)18964days = this._days + Math.round(monthsToDays(this._months));18965switch (units) {18966case 'week' : return days / 7 + milliseconds / 6048e5;18967case 'day' : return days + milliseconds / 864e5;18968case 'hour' : return days * 24 + milliseconds / 36e5;18969case 'minute' : return days * 1440 + milliseconds / 6e4;18970case 'second' : return days * 86400 + milliseconds / 1000;18971// Math.floor prevents floating point math errors here18972case 'millisecond': return Math.floor(days * 864e5) + milliseconds;18973default: throw new Error('Unknown unit ' + units);18974}18975}18976}1897718978// TODO: Use this.as('ms')?18979function valueOf$1 () {18980if (!this.isValid()) {18981return NaN;18982}18983return (18984this._milliseconds +18985this._days * 864e5 +18986(this._months % 12) * 2592e6 +18987toInt(this._months / 12) * 31536e618988);18989}1899018991function makeAs (alias) {18992return function () {18993return this.as(alias);18994};18995}1899618997var asMilliseconds = makeAs('ms');18998var asSeconds = makeAs('s');18999var asMinutes = makeAs('m');19000var asHours = makeAs('h');19001var asDays = makeAs('d');19002var asWeeks = makeAs('w');19003var asMonths = makeAs('M');19004var asQuarters = makeAs('Q');19005var asYears = makeAs('y');1900619007function clone$1 () {19008return createDuration(this);19009}1901019011function get$2 (units) {19012units = normalizeUnits(units);19013return this.isValid() ? this[units + 's']() : NaN;19014}1901519016function makeGetter(name) {19017return function () {19018return this.isValid() ? this._data[name] : NaN;19019};19020}1902119022var milliseconds = makeGetter('milliseconds');19023var seconds = makeGetter('seconds');19024var minutes = makeGetter('minutes');19025var hours = makeGetter('hours');19026var days = makeGetter('days');19027var months = makeGetter('months');19028var years = makeGetter('years');1902919030function weeks () {19031return absFloor(this.days() / 7);19032}1903319034var round = Math.round;19035var thresholds = {19036ss: 44, // a few seconds to seconds19037s : 45, // seconds to minute19038m : 45, // minutes to hour19039h : 22, // hours to day19040d : 26, // days to month19041M : 11 // months to year19042};1904319044// helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize19045function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) {19046return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture);19047}1904819049function relativeTime$1 (posNegDuration, withoutSuffix, locale) {19050var duration = createDuration(posNegDuration).abs();19051var seconds = round(duration.as('s'));19052var minutes = round(duration.as('m'));19053var hours = round(duration.as('h'));19054var days = round(duration.as('d'));19055var months = round(duration.as('M'));19056var years = round(duration.as('y'));1905719058var a = seconds <= thresholds.ss && ['s', seconds] ||19059seconds < thresholds.s && ['ss', seconds] ||19060minutes <= 1 && ['m'] ||19061minutes < thresholds.m && ['mm', minutes] ||19062hours <= 1 && ['h'] ||19063hours < thresholds.h && ['hh', hours] ||19064days <= 1 && ['d'] ||19065days < thresholds.d && ['dd', days] ||19066months <= 1 && ['M'] ||19067months < thresholds.M && ['MM', months] ||19068years <= 1 && ['y'] || ['yy', years];1906919070a[2] = withoutSuffix;19071a[3] = +posNegDuration > 0;19072a[4] = locale;19073return substituteTimeAgo.apply(null, a);19074}1907519076// This function allows you to set the rounding function for relative time strings19077function getSetRelativeTimeRounding (roundingFunction) {19078if (roundingFunction === undefined) {19079return round;19080}19081if (typeof(roundingFunction) === 'function') {19082round = roundingFunction;19083return true;19084}19085return false;19086}1908719088// This function allows you to set a threshold for relative time strings19089function getSetRelativeTimeThreshold (threshold, limit) {19090if (thresholds[threshold] === undefined) {19091return false;19092}19093if (limit === undefined) {19094return thresholds[threshold];19095}19096thresholds[threshold] = limit;19097if (threshold === 's') {19098thresholds.ss = limit - 1;19099}19100return true;19101}1910219103function humanize (withSuffix) {19104if (!this.isValid()) {19105return this.localeData().invalidDate();19106}1910719108var locale = this.localeData();19109var output = relativeTime$1(this, !withSuffix, locale);1911019111if (withSuffix) {19112output = locale.pastFuture(+this, output);19113}1911419115return locale.postformat(output);19116}1911719118var abs$1 = Math.abs;1911919120function sign(x) {19121return ((x > 0) - (x < 0)) || +x;19122}1912319124function toISOString$1() {19125// for ISO strings we do not use the normal bubbling rules:19126// * milliseconds bubble up until they become hours19127// * days do not bubble at all19128// * months bubble up until they become years19129// This is because there is no context-free conversion between hours and days19130// (think of clock changes)19131// and also not between days and months (28-31 days per month)19132if (!this.isValid()) {19133return this.localeData().invalidDate();19134}1913519136var seconds = abs$1(this._milliseconds) / 1000;19137var days = abs$1(this._days);19138var months = abs$1(this._months);19139var minutes, hours, years;1914019141// 3600 seconds -> 60 minutes -> 1 hour19142minutes = absFloor(seconds / 60);19143hours = absFloor(minutes / 60);19144seconds %= 60;19145minutes %= 60;1914619147// 12 months -> 1 year19148years = absFloor(months / 12);19149months %= 12;191501915119152// inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js19153var Y = years;19154var M = months;19155var D = days;19156var h = hours;19157var m = minutes;19158var s = seconds ? seconds.toFixed(3).replace(/\.?0+$/, '') : '';19159var total = this.asSeconds();1916019161if (!total) {19162// this is the same as C#'s (Noda) and python (isodate)...19163// but not other JS (goog.date)19164return 'P0D';19165}1916619167var totalSign = total < 0 ? '-' : '';19168var ymSign = sign(this._months) !== sign(total) ? '-' : '';19169var daysSign = sign(this._days) !== sign(total) ? '-' : '';19170var hmsSign = sign(this._milliseconds) !== sign(total) ? '-' : '';1917119172return totalSign + 'P' +19173(Y ? ymSign + Y + 'Y' : '') +19174(M ? ymSign + M + 'M' : '') +19175(D ? daysSign + D + 'D' : '') +19176((h || m || s) ? 'T' : '') +19177(h ? hmsSign + h + 'H' : '') +19178(m ? hmsSign + m + 'M' : '') +19179(s ? hmsSign + s + 'S' : '');19180}1918119182var proto$2 = Duration.prototype;1918319184proto$2.isValid = isValid$1;19185proto$2.abs = abs;19186proto$2.add = add$1;19187proto$2.subtract = subtract$1;19188proto$2.as = as;19189proto$2.asMilliseconds = asMilliseconds;19190proto$2.asSeconds = asSeconds;19191proto$2.asMinutes = asMinutes;19192proto$2.asHours = asHours;19193proto$2.asDays = asDays;19194proto$2.asWeeks = asWeeks;19195proto$2.asMonths = asMonths;19196proto$2.asQuarters = asQuarters;19197proto$2.asYears = asYears;19198proto$2.valueOf = valueOf$1;19199proto$2._bubble = bubble;19200proto$2.clone = clone$1;19201proto$2.get = get$2;19202proto$2.milliseconds = milliseconds;19203proto$2.seconds = seconds;19204proto$2.minutes = minutes;19205proto$2.hours = hours;19206proto$2.days = days;19207proto$2.weeks = weeks;19208proto$2.months = months;19209proto$2.years = years;19210proto$2.humanize = humanize;19211proto$2.toISOString = toISOString$1;19212proto$2.toString = toISOString$1;19213proto$2.toJSON = toISOString$1;19214proto$2.locale = locale;19215proto$2.localeData = localeData;1921619217proto$2.toIsoString = deprecate('toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)', toISOString$1);19218proto$2.lang = lang;1921919220// Side effect imports1922119222// FORMATTING1922319224addFormatToken('X', 0, 0, 'unix');19225addFormatToken('x', 0, 0, 'valueOf');1922619227// PARSING1922819229addRegexToken('x', matchSigned);19230addRegexToken('X', matchTimestamp);19231addParseToken('X', function (input, array, config) {19232config._d = new Date(parseFloat(input, 10) * 1000);19233});19234addParseToken('x', function (input, array, config) {19235config._d = new Date(toInt(input));19236});1923719238// Side effect imports192391924019241hooks.version = '2.24.0';1924219243setHookCallback(createLocal);1924419245hooks.fn = proto;19246hooks.min = min;19247hooks.max = max;19248hooks.now = now;19249hooks.utc = createUTC;19250hooks.unix = createUnix;19251hooks.months = listMonths;19252hooks.isDate = isDate;19253hooks.locale = getSetGlobalLocale;19254hooks.invalid = createInvalid;19255hooks.duration = createDuration;19256hooks.isMoment = isMoment;19257hooks.weekdays = listWeekdays;19258hooks.parseZone = createInZone;19259hooks.localeData = getLocale;19260hooks.isDuration = isDuration;19261hooks.monthsShort = listMonthsShort;19262hooks.weekdaysMin = listWeekdaysMin;19263hooks.defineLocale = defineLocale;19264hooks.updateLocale = updateLocale;19265hooks.locales = listLocales;19266hooks.weekdaysShort = listWeekdaysShort;19267hooks.normalizeUnits = normalizeUnits;19268hooks.relativeTimeRounding = getSetRelativeTimeRounding;19269hooks.relativeTimeThreshold = getSetRelativeTimeThreshold;19270hooks.calendarFormat = getCalendarFormat;19271hooks.prototype = proto;1927219273// currently HTML5 input type only supports 24-hour formats19274hooks.HTML5_FMT = {19275DATETIME_LOCAL: 'YYYY-MM-DDTHH:mm', // <input type="datetime-local" />19276DATETIME_LOCAL_SECONDS: 'YYYY-MM-DDTHH:mm:ss', // <input type="datetime-local" step="1" />19277DATETIME_LOCAL_MS: 'YYYY-MM-DDTHH:mm:ss.SSS', // <input type="datetime-local" step="0.001" />19278DATE: 'YYYY-MM-DD', // <input type="date" />19279TIME: 'HH:mm', // <input type="time" />19280TIME_SECONDS: 'HH:mm:ss', // <input type="time" step="1" />19281TIME_MS: 'HH:mm:ss.SSS', // <input type="time" step="0.001" />19282WEEK: 'GGGG-[W]WW', // <input type="week" />19283MONTH: 'YYYY-MM' // <input type="month" />19284};1928519286return hooks;1928719288})));19289});1929019291var FORMATS = {19292datetime: 'MMM D, YYYY, h:mm:ss a',19293millisecond: 'h:mm:ss.SSS a',19294second: 'h:mm:ss a',19295minute: 'h:mm a',19296hour: 'hA',19297day: 'MMM D',19298week: 'll',19299month: 'MMM YYYY',19300quarter: '[Q]Q - YYYY',19301year: 'YYYY'19302};1930319304core_adapters._date.override(typeof moment === 'function' ? {19305_id: 'moment', // DEBUG ONLY1930619307formats: function() {19308return FORMATS;19309},1931019311parse: function(value, format) {19312if (typeof value === 'string' && typeof format === 'string') {19313value = moment(value, format);19314} else if (!(value instanceof moment)) {19315value = moment(value);19316}19317return value.isValid() ? value.valueOf() : null;19318},1931919320format: function(time, format) {19321return moment(time).format(format);19322},1932319324add: function(time, amount, unit) {19325return moment(time).add(amount, unit).valueOf();19326},1932719328diff: function(max, min, unit) {19329return moment(max).diff(moment(min), unit);19330},1933119332startOf: function(time, unit, weekday) {19333time = moment(time);19334if (unit === 'isoWeek') {19335return time.isoWeekday(weekday).valueOf();19336}19337return time.startOf(unit).valueOf();19338},1933919340endOf: function(time, unit) {19341return moment(time).endOf(unit).valueOf();19342},1934319344// DEPRECATIONS1934519346/**19347* Provided for backward compatibility with scale.getValueForPixel().19348* @deprecated since version 2.8.019349* @todo remove at version 319350* @private19351*/19352_create: function(time) {19353return moment(time);19354},19355} : {});1935619357core_defaults._set('global', {19358plugins: {19359filler: {19360propagate: true19361}19362}19363});1936419365var mappers = {19366dataset: function(source) {19367var index = source.fill;19368var chart = source.chart;19369var meta = chart.getDatasetMeta(index);19370var visible = meta && chart.isDatasetVisible(index);19371var points = (visible && meta.dataset._children) || [];19372var length = points.length || 0;1937319374return !length ? null : function(point, i) {19375return (i < length && points[i]._view) || null;19376};19377},1937819379boundary: function(source) {19380var boundary = source.boundary;19381var x = boundary ? boundary.x : null;19382var y = boundary ? boundary.y : null;1938319384if (helpers$1.isArray(boundary)) {19385return function(point, i) {19386return boundary[i];19387};19388}1938919390return function(point) {19391return {19392x: x === null ? point.x : x,19393y: y === null ? point.y : y,19394};19395};19396}19397};1939819399// @todo if (fill[0] === '#')19400function decodeFill(el, index, count) {19401var model = el._model || {};19402var fill = model.fill;19403var target;1940419405if (fill === undefined) {19406fill = !!model.backgroundColor;19407}1940819409if (fill === false || fill === null) {19410return false;19411}1941219413if (fill === true) {19414return 'origin';19415}1941619417target = parseFloat(fill, 10);19418if (isFinite(target) && Math.floor(target) === target) {19419if (fill[0] === '-' || fill[0] === '+') {19420target = index + target;19421}1942219423if (target === index || target < 0 || target >= count) {19424return false;19425}1942619427return target;19428}1942919430switch (fill) {19431// compatibility19432case 'bottom':19433return 'start';19434case 'top':19435return 'end';19436case 'zero':19437return 'origin';19438// supported boundaries19439case 'origin':19440case 'start':19441case 'end':19442return fill;19443// invalid fill values19444default:19445return false;19446}19447}1944819449function computeLinearBoundary(source) {19450var model = source.el._model || {};19451var scale = source.el._scale || {};19452var fill = source.fill;19453var target = null;19454var horizontal;1945519456if (isFinite(fill)) {19457return null;19458}1945919460// Backward compatibility: until v3, we still need to support boundary values set on19461// the model (scaleTop, scaleBottom and scaleZero) because some external plugins and19462// controllers might still use it (e.g. the Smith chart).1946319464if (fill === 'start') {19465target = model.scaleBottom === undefined ? scale.bottom : model.scaleBottom;19466} else if (fill === 'end') {19467target = model.scaleTop === undefined ? scale.top : model.scaleTop;19468} else if (model.scaleZero !== undefined) {19469target = model.scaleZero;19470} else if (scale.getBasePixel) {19471target = scale.getBasePixel();19472}1947319474if (target !== undefined && target !== null) {19475if (target.x !== undefined && target.y !== undefined) {19476return target;19477}1947819479if (helpers$1.isFinite(target)) {19480horizontal = scale.isHorizontal();19481return {19482x: horizontal ? target : null,19483y: horizontal ? null : target19484};19485}19486}1948719488return null;19489}1949019491function computeCircularBoundary(source) {19492var scale = source.el._scale;19493var options = scale.options;19494var length = scale.chart.data.labels.length;19495var fill = source.fill;19496var target = [];19497var start, end, center, i, point;1949819499if (!length) {19500return null;19501}1950219503start = options.ticks.reverse ? scale.max : scale.min;19504end = options.ticks.reverse ? scale.min : scale.max;19505center = scale.getPointPositionForValue(0, start);19506for (i = 0; i < length; ++i) {19507point = fill === 'start' || fill === 'end'19508? scale.getPointPositionForValue(i, fill === 'start' ? start : end)19509: scale.getBasePosition(i);19510if (options.gridLines.circular) {19511point.cx = center.x;19512point.cy = center.y;19513point.angle = scale.getIndexAngle(i) - Math.PI / 2;19514}19515target.push(point);19516}19517return target;19518}1951919520function computeBoundary(source) {19521var scale = source.el._scale || {};1952219523if (scale.getPointPositionForValue) {19524return computeCircularBoundary(source);19525}19526return computeLinearBoundary(source);19527}1952819529function resolveTarget(sources, index, propagate) {19530var source = sources[index];19531var fill = source.fill;19532var visited = [index];19533var target;1953419535if (!propagate) {19536return fill;19537}1953819539while (fill !== false && visited.indexOf(fill) === -1) {19540if (!isFinite(fill)) {19541return fill;19542}1954319544target = sources[fill];19545if (!target) {19546return false;19547}1954819549if (target.visible) {19550return fill;19551}1955219553visited.push(fill);19554fill = target.fill;19555}1955619557return false;19558}1955919560function createMapper(source) {19561var fill = source.fill;19562var type = 'dataset';1956319564if (fill === false) {19565return null;19566}1956719568if (!isFinite(fill)) {19569type = 'boundary';19570}1957119572return mappers[type](source);19573}1957419575function isDrawable(point) {19576return point && !point.skip;19577}1957819579function drawArea(ctx, curve0, curve1, len0, len1) {19580var i, cx, cy, r;1958119582if (!len0 || !len1) {19583return;19584}1958519586// building first area curve (normal)19587ctx.moveTo(curve0[0].x, curve0[0].y);19588for (i = 1; i < len0; ++i) {19589helpers$1.canvas.lineTo(ctx, curve0[i - 1], curve0[i]);19590}1959119592if (curve1[0].angle !== undefined) {19593cx = curve1[0].cx;19594cy = curve1[0].cy;19595r = Math.sqrt(Math.pow(curve1[0].x - cx, 2) + Math.pow(curve1[0].y - cy, 2));19596for (i = len1 - 1; i > 0; --i) {19597ctx.arc(cx, cy, r, curve1[i].angle, curve1[i - 1].angle, true);19598}19599return;19600}1960119602// joining the two area curves19603ctx.lineTo(curve1[len1 - 1].x, curve1[len1 - 1].y);1960419605// building opposite area curve (reverse)19606for (i = len1 - 1; i > 0; --i) {19607helpers$1.canvas.lineTo(ctx, curve1[i], curve1[i - 1], true);19608}19609}1961019611function doFill(ctx, points, mapper, view, color, loop) {19612var count = points.length;19613var span = view.spanGaps;19614var curve0 = [];19615var curve1 = [];19616var len0 = 0;19617var len1 = 0;19618var i, ilen, index, p0, p1, d0, d1, loopOffset;1961919620ctx.beginPath();1962119622for (i = 0, ilen = count; i < ilen; ++i) {19623index = i % count;19624p0 = points[index]._view;19625p1 = mapper(p0, index, view);19626d0 = isDrawable(p0);19627d1 = isDrawable(p1);1962819629if (loop && loopOffset === undefined && d0) {19630loopOffset = i + 1;19631ilen = count + loopOffset;19632}1963319634if (d0 && d1) {19635len0 = curve0.push(p0);19636len1 = curve1.push(p1);19637} else if (len0 && len1) {19638if (!span) {19639drawArea(ctx, curve0, curve1, len0, len1);19640len0 = len1 = 0;19641curve0 = [];19642curve1 = [];19643} else {19644if (d0) {19645curve0.push(p0);19646}19647if (d1) {19648curve1.push(p1);19649}19650}19651}19652}1965319654drawArea(ctx, curve0, curve1, len0, len1);1965519656ctx.closePath();19657ctx.fillStyle = color;19658ctx.fill();19659}1966019661var plugin_filler = {19662id: 'filler',1966319664afterDatasetsUpdate: function(chart, options) {19665var count = (chart.data.datasets || []).length;19666var propagate = options.propagate;19667var sources = [];19668var meta, i, el, source;1966919670for (i = 0; i < count; ++i) {19671meta = chart.getDatasetMeta(i);19672el = meta.dataset;19673source = null;1967419675if (el && el._model && el instanceof elements.Line) {19676source = {19677visible: chart.isDatasetVisible(i),19678fill: decodeFill(el, i, count),19679chart: chart,19680el: el19681};19682}1968319684meta.$filler = source;19685sources.push(source);19686}1968719688for (i = 0; i < count; ++i) {19689source = sources[i];19690if (!source) {19691continue;19692}1969319694source.fill = resolveTarget(sources, i, propagate);19695source.boundary = computeBoundary(source);19696source.mapper = createMapper(source);19697}19698},1969919700beforeDatasetsDraw: function(chart) {19701var metasets = chart._getSortedVisibleDatasetMetas();19702var ctx = chart.ctx;19703var meta, i, el, view, points, mapper, color;1970419705for (i = metasets.length - 1; i >= 0; --i) {19706meta = metasets[i].$filler;1970719708if (!meta || !meta.visible) {19709continue;19710}1971119712el = meta.el;19713view = el._view;19714points = el._children || [];19715mapper = meta.mapper;19716color = view.backgroundColor || core_defaults.global.defaultColor;1971719718if (mapper && color && points.length) {19719helpers$1.canvas.clipArea(ctx, chart.chartArea);19720doFill(ctx, points, mapper, view, color, el._loop);19721helpers$1.canvas.unclipArea(ctx);19722}19723}19724}19725};1972619727var getRtlHelper$1 = helpers$1.rtl.getRtlAdapter;19728var noop$1 = helpers$1.noop;19729var valueOrDefault$e = helpers$1.valueOrDefault;1973019731core_defaults._set('global', {19732legend: {19733display: true,19734position: 'top',19735align: 'center',19736fullWidth: true,19737reverse: false,19738weight: 1000,1973919740// a callback that will handle19741onClick: function(e, legendItem) {19742var index = legendItem.datasetIndex;19743var ci = this.chart;19744var meta = ci.getDatasetMeta(index);1974519746// See controller.isDatasetVisible comment19747meta.hidden = meta.hidden === null ? !ci.data.datasets[index].hidden : null;1974819749// We hid a dataset ... rerender the chart19750ci.update();19751},1975219753onHover: null,19754onLeave: null,1975519756labels: {19757boxWidth: 40,19758padding: 10,19759// Generates labels shown in the legend19760// Valid properties to return:19761// text : text to display19762// fillStyle : fill of coloured box19763// strokeStyle: stroke of coloured box19764// hidden : if this legend item refers to a hidden item19765// lineCap : cap style for line19766// lineDash19767// lineDashOffset :19768// lineJoin :19769// lineWidth :19770generateLabels: function(chart) {19771var datasets = chart.data.datasets;19772var options = chart.options.legend || {};19773var usePointStyle = options.labels && options.labels.usePointStyle;1977419775return chart._getSortedDatasetMetas().map(function(meta) {19776var style = meta.controller.getStyle(usePointStyle ? 0 : undefined);1977719778return {19779text: datasets[meta.index].label,19780fillStyle: style.backgroundColor,19781hidden: !chart.isDatasetVisible(meta.index),19782lineCap: style.borderCapStyle,19783lineDash: style.borderDash,19784lineDashOffset: style.borderDashOffset,19785lineJoin: style.borderJoinStyle,19786lineWidth: style.borderWidth,19787strokeStyle: style.borderColor,19788pointStyle: style.pointStyle,19789rotation: style.rotation,1979019791// Below is extra data used for toggling the datasets19792datasetIndex: meta.index19793};19794}, this);19795}19796}19797},1979819799legendCallback: function(chart) {19800var list = document.createElement('ul');19801var datasets = chart.data.datasets;19802var i, ilen, listItem, listItemSpan;1980319804list.setAttribute('class', chart.id + '-legend');1980519806for (i = 0, ilen = datasets.length; i < ilen; i++) {19807listItem = list.appendChild(document.createElement('li'));19808listItemSpan = listItem.appendChild(document.createElement('span'));19809listItemSpan.style.backgroundColor = datasets[i].backgroundColor;19810if (datasets[i].label) {19811listItem.appendChild(document.createTextNode(datasets[i].label));19812}19813}1981419815return list.outerHTML;19816}19817});1981819819/**19820* Helper function to get the box width based on the usePointStyle option19821* @param {object} labelopts - the label options on the legend19822* @param {number} fontSize - the label font size19823* @return {number} width of the color box area19824*/19825function getBoxWidth(labelOpts, fontSize) {19826return labelOpts.usePointStyle && labelOpts.boxWidth > fontSize ?19827fontSize :19828labelOpts.boxWidth;19829}1983019831/**19832* IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!19833*/19834var Legend = core_element.extend({1983519836initialize: function(config) {19837var me = this;19838helpers$1.extend(me, config);1983919840// Contains hit boxes for each dataset (in dataset order)19841me.legendHitBoxes = [];1984219843/**19844* @private19845*/19846me._hoveredItem = null;1984719848// Are we in doughnut mode which has a different data type19849me.doughnutMode = false;19850},1985119852// These methods are ordered by lifecycle. Utilities then follow.19853// Any function defined here is inherited by all legend types.19854// Any function can be extended by the legend type1985519856beforeUpdate: noop$1,19857update: function(maxWidth, maxHeight, margins) {19858var me = this;1985919860// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)19861me.beforeUpdate();1986219863// Absorb the master measurements19864me.maxWidth = maxWidth;19865me.maxHeight = maxHeight;19866me.margins = margins;1986719868// Dimensions19869me.beforeSetDimensions();19870me.setDimensions();19871me.afterSetDimensions();19872// Labels19873me.beforeBuildLabels();19874me.buildLabels();19875me.afterBuildLabels();1987619877// Fit19878me.beforeFit();19879me.fit();19880me.afterFit();19881//19882me.afterUpdate();1988319884return me.minSize;19885},19886afterUpdate: noop$1,1988719888//1988919890beforeSetDimensions: noop$1,19891setDimensions: function() {19892var me = this;19893// Set the unconstrained dimension before label rotation19894if (me.isHorizontal()) {19895// Reset position before calculating rotation19896me.width = me.maxWidth;19897me.left = 0;19898me.right = me.width;19899} else {19900me.height = me.maxHeight;1990119902// Reset position before calculating rotation19903me.top = 0;19904me.bottom = me.height;19905}1990619907// Reset padding19908me.paddingLeft = 0;19909me.paddingTop = 0;19910me.paddingRight = 0;19911me.paddingBottom = 0;1991219913// Reset minSize19914me.minSize = {19915width: 0,19916height: 019917};19918},19919afterSetDimensions: noop$1,1992019921//1992219923beforeBuildLabels: noop$1,19924buildLabels: function() {19925var me = this;19926var labelOpts = me.options.labels || {};19927var legendItems = helpers$1.callback(labelOpts.generateLabels, [me.chart], me) || [];1992819929if (labelOpts.filter) {19930legendItems = legendItems.filter(function(item) {19931return labelOpts.filter(item, me.chart.data);19932});19933}1993419935if (me.options.reverse) {19936legendItems.reverse();19937}1993819939me.legendItems = legendItems;19940},19941afterBuildLabels: noop$1,1994219943//1994419945beforeFit: noop$1,19946fit: function() {19947var me = this;19948var opts = me.options;19949var labelOpts = opts.labels;19950var display = opts.display;1995119952var ctx = me.ctx;1995319954var labelFont = helpers$1.options._parseFont(labelOpts);19955var fontSize = labelFont.size;1995619957// Reset hit boxes19958var hitboxes = me.legendHitBoxes = [];1995919960var minSize = me.minSize;19961var isHorizontal = me.isHorizontal();1996219963if (isHorizontal) {19964minSize.width = me.maxWidth; // fill all the width19965minSize.height = display ? 10 : 0;19966} else {19967minSize.width = display ? 10 : 0;19968minSize.height = me.maxHeight; // fill all the height19969}1997019971// Increase sizes here19972if (!display) {19973me.width = minSize.width = me.height = minSize.height = 0;19974return;19975}19976ctx.font = labelFont.string;1997719978if (isHorizontal) {19979// Labels1998019981// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one19982var lineWidths = me.lineWidths = [0];19983var totalHeight = 0;1998419985ctx.textAlign = 'left';19986ctx.textBaseline = 'middle';1998719988helpers$1.each(me.legendItems, function(legendItem, i) {19989var boxWidth = getBoxWidth(labelOpts, fontSize);19990var width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;1999119992if (i === 0 || lineWidths[lineWidths.length - 1] + width + 2 * labelOpts.padding > minSize.width) {19993totalHeight += fontSize + labelOpts.padding;19994lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;19995}1999619997// Store the hitbox width and height here. Final position will be updated in `draw`19998hitboxes[i] = {19999left: 0,20000top: 0,20001width: width,20002height: fontSize20003};2000420005lineWidths[lineWidths.length - 1] += width + labelOpts.padding;20006});2000720008minSize.height += totalHeight;2000920010} else {20011var vPadding = labelOpts.padding;20012var columnWidths = me.columnWidths = [];20013var columnHeights = me.columnHeights = [];20014var totalWidth = labelOpts.padding;20015var currentColWidth = 0;20016var currentColHeight = 0;2001720018helpers$1.each(me.legendItems, function(legendItem, i) {20019var boxWidth = getBoxWidth(labelOpts, fontSize);20020var itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;2002120022// If too tall, go to new column20023if (i > 0 && currentColHeight + fontSize + 2 * vPadding > minSize.height) {20024totalWidth += currentColWidth + labelOpts.padding;20025columnWidths.push(currentColWidth); // previous column width20026columnHeights.push(currentColHeight);20027currentColWidth = 0;20028currentColHeight = 0;20029}2003020031// Get max width20032currentColWidth = Math.max(currentColWidth, itemWidth);20033currentColHeight += fontSize + vPadding;2003420035// Store the hitbox width and height here. Final position will be updated in `draw`20036hitboxes[i] = {20037left: 0,20038top: 0,20039width: itemWidth,20040height: fontSize20041};20042});2004320044totalWidth += currentColWidth;20045columnWidths.push(currentColWidth);20046columnHeights.push(currentColHeight);20047minSize.width += totalWidth;20048}2004920050me.width = minSize.width;20051me.height = minSize.height;20052},20053afterFit: noop$1,2005420055// Shared Methods20056isHorizontal: function() {20057return this.options.position === 'top' || this.options.position === 'bottom';20058},2005920060// Actually draw the legend on the canvas20061draw: function() {20062var me = this;20063var opts = me.options;20064var labelOpts = opts.labels;20065var globalDefaults = core_defaults.global;20066var defaultColor = globalDefaults.defaultColor;20067var lineDefault = globalDefaults.elements.line;20068var legendHeight = me.height;20069var columnHeights = me.columnHeights;20070var legendWidth = me.width;20071var lineWidths = me.lineWidths;2007220073if (!opts.display) {20074return;20075}2007620077var rtlHelper = getRtlHelper$1(opts.rtl, me.left, me.minSize.width);20078var ctx = me.ctx;20079var fontColor = valueOrDefault$e(labelOpts.fontColor, globalDefaults.defaultFontColor);20080var labelFont = helpers$1.options._parseFont(labelOpts);20081var fontSize = labelFont.size;20082var cursor;2008320084// Canvas setup20085ctx.textAlign = rtlHelper.textAlign('left');20086ctx.textBaseline = 'middle';20087ctx.lineWidth = 0.5;20088ctx.strokeStyle = fontColor; // for strikethrough effect20089ctx.fillStyle = fontColor; // render in correct colour20090ctx.font = labelFont.string;2009120092var boxWidth = getBoxWidth(labelOpts, fontSize);20093var hitboxes = me.legendHitBoxes;2009420095// current position20096var drawLegendBox = function(x, y, legendItem) {20097if (isNaN(boxWidth) || boxWidth <= 0) {20098return;20099}2010020101// Set the ctx for the box20102ctx.save();2010320104var lineWidth = valueOrDefault$e(legendItem.lineWidth, lineDefault.borderWidth);20105ctx.fillStyle = valueOrDefault$e(legendItem.fillStyle, defaultColor);20106ctx.lineCap = valueOrDefault$e(legendItem.lineCap, lineDefault.borderCapStyle);20107ctx.lineDashOffset = valueOrDefault$e(legendItem.lineDashOffset, lineDefault.borderDashOffset);20108ctx.lineJoin = valueOrDefault$e(legendItem.lineJoin, lineDefault.borderJoinStyle);20109ctx.lineWidth = lineWidth;20110ctx.strokeStyle = valueOrDefault$e(legendItem.strokeStyle, defaultColor);2011120112if (ctx.setLineDash) {20113// IE 9 and 10 do not support line dash20114ctx.setLineDash(valueOrDefault$e(legendItem.lineDash, lineDefault.borderDash));20115}2011620117if (labelOpts && labelOpts.usePointStyle) {20118// Recalculate x and y for drawPoint() because its expecting20119// x and y to be center of figure (instead of top left)20120var radius = boxWidth * Math.SQRT2 / 2;20121var centerX = rtlHelper.xPlus(x, boxWidth / 2);20122var centerY = y + fontSize / 2;2012320124// Draw pointStyle as legend symbol20125helpers$1.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY, legendItem.rotation);20126} else {20127// Draw box as legend symbol20128ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);20129if (lineWidth !== 0) {20130ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), y, boxWidth, fontSize);20131}20132}2013320134ctx.restore();20135};2013620137var fillText = function(x, y, legendItem, textWidth) {20138var halfFontSize = fontSize / 2;20139var xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize);20140var yMiddle = y + halfFontSize;2014120142ctx.fillText(legendItem.text, xLeft, yMiddle);2014320144if (legendItem.hidden) {20145// Strikethrough the text if hidden20146ctx.beginPath();20147ctx.lineWidth = 2;20148ctx.moveTo(xLeft, yMiddle);20149ctx.lineTo(rtlHelper.xPlus(xLeft, textWidth), yMiddle);20150ctx.stroke();20151}20152};2015320154var alignmentOffset = function(dimension, blockSize) {20155switch (opts.align) {20156case 'start':20157return labelOpts.padding;20158case 'end':20159return dimension - blockSize;20160default: // center20161return (dimension - blockSize + labelOpts.padding) / 2;20162}20163};2016420165// Horizontal20166var isHorizontal = me.isHorizontal();20167if (isHorizontal) {20168cursor = {20169x: me.left + alignmentOffset(legendWidth, lineWidths[0]),20170y: me.top + labelOpts.padding,20171line: 020172};20173} else {20174cursor = {20175x: me.left + labelOpts.padding,20176y: me.top + alignmentOffset(legendHeight, columnHeights[0]),20177line: 020178};20179}2018020181helpers$1.rtl.overrideTextDirection(me.ctx, opts.textDirection);2018220183var itemHeight = fontSize + labelOpts.padding;20184helpers$1.each(me.legendItems, function(legendItem, i) {20185var textWidth = ctx.measureText(legendItem.text).width;20186var width = boxWidth + (fontSize / 2) + textWidth;20187var x = cursor.x;20188var y = cursor.y;2018920190rtlHelper.setWidth(me.minSize.width);2019120192// Use (me.left + me.minSize.width) and (me.top + me.minSize.height)20193// instead of me.right and me.bottom because me.width and me.height20194// may have been changed since me.minSize was calculated20195if (isHorizontal) {20196if (i > 0 && x + width + labelOpts.padding > me.left + me.minSize.width) {20197y = cursor.y += itemHeight;20198cursor.line++;20199x = cursor.x = me.left + alignmentOffset(legendWidth, lineWidths[cursor.line]);20200}20201} else if (i > 0 && y + itemHeight > me.top + me.minSize.height) {20202x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding;20203cursor.line++;20204y = cursor.y = me.top + alignmentOffset(legendHeight, columnHeights[cursor.line]);20205}2020620207var realX = rtlHelper.x(x);2020820209drawLegendBox(realX, y, legendItem);2021020211hitboxes[i].left = rtlHelper.leftForLtr(realX, hitboxes[i].width);20212hitboxes[i].top = y;2021320214// Fill the actual label20215fillText(realX, y, legendItem, textWidth);2021620217if (isHorizontal) {20218cursor.x += width + labelOpts.padding;20219} else {20220cursor.y += itemHeight;20221}20222});2022320224helpers$1.rtl.restoreTextDirection(me.ctx, opts.textDirection);20225},2022620227/**20228* @private20229*/20230_getLegendItemAt: function(x, y) {20231var me = this;20232var i, hitBox, lh;2023320234if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) {20235// See if we are touching one of the dataset boxes20236lh = me.legendHitBoxes;20237for (i = 0; i < lh.length; ++i) {20238hitBox = lh[i];2023920240if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) {20241// Touching an element20242return me.legendItems[i];20243}20244}20245}2024620247return null;20248},2024920250/**20251* Handle an event20252* @private20253* @param {IEvent} event - The event to handle20254*/20255handleEvent: function(e) {20256var me = this;20257var opts = me.options;20258var type = e.type === 'mouseup' ? 'click' : e.type;20259var hoveredItem;2026020261if (type === 'mousemove') {20262if (!opts.onHover && !opts.onLeave) {20263return;20264}20265} else if (type === 'click') {20266if (!opts.onClick) {20267return;20268}20269} else {20270return;20271}2027220273// Chart event already has relative position in it20274hoveredItem = me._getLegendItemAt(e.x, e.y);2027520276if (type === 'click') {20277if (hoveredItem && opts.onClick) {20278// use e.native for backwards compatibility20279opts.onClick.call(me, e.native, hoveredItem);20280}20281} else {20282if (opts.onLeave && hoveredItem !== me._hoveredItem) {20283if (me._hoveredItem) {20284opts.onLeave.call(me, e.native, me._hoveredItem);20285}20286me._hoveredItem = hoveredItem;20287}2028820289if (opts.onHover && hoveredItem) {20290// use e.native for backwards compatibility20291opts.onHover.call(me, e.native, hoveredItem);20292}20293}20294}20295});2029620297function createNewLegendAndAttach(chart, legendOpts) {20298var legend = new Legend({20299ctx: chart.ctx,20300options: legendOpts,20301chart: chart20302});2030320304core_layouts.configure(chart, legend, legendOpts);20305core_layouts.addBox(chart, legend);20306chart.legend = legend;20307}2030820309var plugin_legend = {20310id: 'legend',2031120312/**20313* Backward compatibility: since 2.1.5, the legend is registered as a plugin, making20314* Chart.Legend obsolete. To avoid a breaking change, we export the Legend as part of20315* the plugin, which one will be re-exposed in the chart.js file.20316* https://github.com/chartjs/Chart.js/pull/264020317* @private20318*/20319_element: Legend,2032020321beforeInit: function(chart) {20322var legendOpts = chart.options.legend;2032320324if (legendOpts) {20325createNewLegendAndAttach(chart, legendOpts);20326}20327},2032820329beforeUpdate: function(chart) {20330var legendOpts = chart.options.legend;20331var legend = chart.legend;2033220333if (legendOpts) {20334helpers$1.mergeIf(legendOpts, core_defaults.global.legend);2033520336if (legend) {20337core_layouts.configure(chart, legend, legendOpts);20338legend.options = legendOpts;20339} else {20340createNewLegendAndAttach(chart, legendOpts);20341}20342} else if (legend) {20343core_layouts.removeBox(chart, legend);20344delete chart.legend;20345}20346},2034720348afterEvent: function(chart, e) {20349var legend = chart.legend;20350if (legend) {20351legend.handleEvent(e);20352}20353}20354};2035520356var noop$2 = helpers$1.noop;2035720358core_defaults._set('global', {20359title: {20360display: false,20361fontStyle: 'bold',20362fullWidth: true,20363padding: 10,20364position: 'top',20365text: '',20366weight: 2000 // by default greater than legend (1000) to be above20367}20368});2036920370/**20371* IMPORTANT: this class is exposed publicly as Chart.Legend, backward compatibility required!20372*/20373var Title = core_element.extend({20374initialize: function(config) {20375var me = this;20376helpers$1.extend(me, config);2037720378// Contains hit boxes for each dataset (in dataset order)20379me.legendHitBoxes = [];20380},2038120382// These methods are ordered by lifecycle. Utilities then follow.2038320384beforeUpdate: noop$2,20385update: function(maxWidth, maxHeight, margins) {20386var me = this;2038720388// Update Lifecycle - Probably don't want to ever extend or overwrite this function ;)20389me.beforeUpdate();2039020391// Absorb the master measurements20392me.maxWidth = maxWidth;20393me.maxHeight = maxHeight;20394me.margins = margins;2039520396// Dimensions20397me.beforeSetDimensions();20398me.setDimensions();20399me.afterSetDimensions();20400// Labels20401me.beforeBuildLabels();20402me.buildLabels();20403me.afterBuildLabels();2040420405// Fit20406me.beforeFit();20407me.fit();20408me.afterFit();20409//20410me.afterUpdate();2041120412return me.minSize;2041320414},20415afterUpdate: noop$2,2041620417//2041820419beforeSetDimensions: noop$2,20420setDimensions: function() {20421var me = this;20422// Set the unconstrained dimension before label rotation20423if (me.isHorizontal()) {20424// Reset position before calculating rotation20425me.width = me.maxWidth;20426me.left = 0;20427me.right = me.width;20428} else {20429me.height = me.maxHeight;2043020431// Reset position before calculating rotation20432me.top = 0;20433me.bottom = me.height;20434}2043520436// Reset padding20437me.paddingLeft = 0;20438me.paddingTop = 0;20439me.paddingRight = 0;20440me.paddingBottom = 0;2044120442// Reset minSize20443me.minSize = {20444width: 0,20445height: 020446};20447},20448afterSetDimensions: noop$2,2044920450//2045120452beforeBuildLabels: noop$2,20453buildLabels: noop$2,20454afterBuildLabels: noop$2,2045520456//2045720458beforeFit: noop$2,20459fit: function() {20460var me = this;20461var opts = me.options;20462var minSize = me.minSize = {};20463var isHorizontal = me.isHorizontal();20464var lineCount, textSize;2046520466if (!opts.display) {20467me.width = minSize.width = me.height = minSize.height = 0;20468return;20469}2047020471lineCount = helpers$1.isArray(opts.text) ? opts.text.length : 1;20472textSize = lineCount * helpers$1.options._parseFont(opts).lineHeight + opts.padding * 2;2047320474me.width = minSize.width = isHorizontal ? me.maxWidth : textSize;20475me.height = minSize.height = isHorizontal ? textSize : me.maxHeight;20476},20477afterFit: noop$2,2047820479// Shared Methods20480isHorizontal: function() {20481var pos = this.options.position;20482return pos === 'top' || pos === 'bottom';20483},2048420485// Actually draw the title block on the canvas20486draw: function() {20487var me = this;20488var ctx = me.ctx;20489var opts = me.options;2049020491if (!opts.display) {20492return;20493}2049420495var fontOpts = helpers$1.options._parseFont(opts);20496var lineHeight = fontOpts.lineHeight;20497var offset = lineHeight / 2 + opts.padding;20498var rotation = 0;20499var top = me.top;20500var left = me.left;20501var bottom = me.bottom;20502var right = me.right;20503var maxWidth, titleX, titleY;2050420505ctx.fillStyle = helpers$1.valueOrDefault(opts.fontColor, core_defaults.global.defaultFontColor); // render in correct colour20506ctx.font = fontOpts.string;2050720508// Horizontal20509if (me.isHorizontal()) {20510titleX = left + ((right - left) / 2); // midpoint of the width20511titleY = top + offset;20512maxWidth = right - left;20513} else {20514titleX = opts.position === 'left' ? left + offset : right - offset;20515titleY = top + ((bottom - top) / 2);20516maxWidth = bottom - top;20517rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5);20518}2051920520ctx.save();20521ctx.translate(titleX, titleY);20522ctx.rotate(rotation);20523ctx.textAlign = 'center';20524ctx.textBaseline = 'middle';2052520526var text = opts.text;20527if (helpers$1.isArray(text)) {20528var y = 0;20529for (var i = 0; i < text.length; ++i) {20530ctx.fillText(text[i], 0, y, maxWidth);20531y += lineHeight;20532}20533} else {20534ctx.fillText(text, 0, 0, maxWidth);20535}2053620537ctx.restore();20538}20539});2054020541function createNewTitleBlockAndAttach(chart, titleOpts) {20542var title = new Title({20543ctx: chart.ctx,20544options: titleOpts,20545chart: chart20546});2054720548core_layouts.configure(chart, title, titleOpts);20549core_layouts.addBox(chart, title);20550chart.titleBlock = title;20551}2055220553var plugin_title = {20554id: 'title',2055520556/**20557* Backward compatibility: since 2.1.5, the title is registered as a plugin, making20558* Chart.Title obsolete. To avoid a breaking change, we export the Title as part of20559* the plugin, which one will be re-exposed in the chart.js file.20560* https://github.com/chartjs/Chart.js/pull/264020561* @private20562*/20563_element: Title,2056420565beforeInit: function(chart) {20566var titleOpts = chart.options.title;2056720568if (titleOpts) {20569createNewTitleBlockAndAttach(chart, titleOpts);20570}20571},2057220573beforeUpdate: function(chart) {20574var titleOpts = chart.options.title;20575var titleBlock = chart.titleBlock;2057620577if (titleOpts) {20578helpers$1.mergeIf(titleOpts, core_defaults.global.title);2057920580if (titleBlock) {20581core_layouts.configure(chart, titleBlock, titleOpts);20582titleBlock.options = titleOpts;20583} else {20584createNewTitleBlockAndAttach(chart, titleOpts);20585}20586} else if (titleBlock) {20587core_layouts.removeBox(chart, titleBlock);20588delete chart.titleBlock;20589}20590}20591};2059220593var plugins = {};20594var filler = plugin_filler;20595var legend = plugin_legend;20596var title = plugin_title;20597plugins.filler = filler;20598plugins.legend = legend;20599plugins.title = title;2060020601/**20602* @namespace Chart20603*/206042060520606core_controller.helpers = helpers$1;2060720608// @todo dispatch these helpers into appropriated helpers/helpers.* file and write unit tests!20609core_helpers();2061020611core_controller._adapters = core_adapters;20612core_controller.Animation = core_animation;20613core_controller.animationService = core_animations;20614core_controller.controllers = controllers;20615core_controller.DatasetController = core_datasetController;20616core_controller.defaults = core_defaults;20617core_controller.Element = core_element;20618core_controller.elements = elements;20619core_controller.Interaction = core_interaction;20620core_controller.layouts = core_layouts;20621core_controller.platform = platform;20622core_controller.plugins = core_plugins;20623core_controller.Scale = core_scale;20624core_controller.scaleService = core_scaleService;20625core_controller.Ticks = core_ticks;20626core_controller.Tooltip = core_tooltip;2062720628// Register built-in scales2062920630core_controller.helpers.each(scales, function(scale, type) {20631core_controller.scaleService.registerScaleType(type, scale, scale._defaults);20632});2063320634// Load to register built-in adapters (as side effects)206352063620637// Loading built-in plugins2063820639for (var k in plugins) {20640if (plugins.hasOwnProperty(k)) {20641core_controller.plugins.register(plugins[k]);20642}20643}2064420645core_controller.platform.initialize();2064620647var src = core_controller;20648if (typeof window !== 'undefined') {20649window.Chart = core_controller;20650}2065120652// DEPRECATIONS2065320654/**20655* Provided for backward compatibility, not available anymore20656* @namespace Chart.Chart20657* @deprecated since version 2.8.020658* @todo remove at version 320659* @private20660*/20661core_controller.Chart = core_controller;2066220663/**20664* Provided for backward compatibility, not available anymore20665* @namespace Chart.Legend20666* @deprecated since version 2.1.520667* @todo remove at version 320668* @private20669*/20670core_controller.Legend = plugins.legend._element;2067120672/**20673* Provided for backward compatibility, not available anymore20674* @namespace Chart.Title20675* @deprecated since version 2.1.520676* @todo remove at version 320677* @private20678*/20679core_controller.Title = plugins.title._element;2068020681/**20682* Provided for backward compatibility, use Chart.plugins instead20683* @namespace Chart.pluginService20684* @deprecated since version 2.1.520685* @todo remove at version 320686* @private20687*/20688core_controller.pluginService = core_controller.plugins;2068920690/**20691* Provided for backward compatibility, inheriting from Chart.PlugingBase has no20692* effect, instead simply create/register plugins via plain JavaScript objects.20693* @interface Chart.PluginBase20694* @deprecated since version 2.5.020695* @todo remove at version 320696* @private20697*/20698core_controller.PluginBase = core_controller.Element.extend({});2069920700/**20701* Provided for backward compatibility, use Chart.helpers.canvas instead.20702* @namespace Chart.canvasHelpers20703* @deprecated since version 2.6.020704* @todo remove at version 320705* @private20706*/20707core_controller.canvasHelpers = core_controller.helpers.canvas;2070820709/**20710* Provided for backward compatibility, use Chart.layouts instead.20711* @namespace Chart.layoutService20712* @deprecated since version 2.7.320713* @todo remove at version 320714* @private20715*/20716core_controller.layoutService = core_controller.layouts;2071720718/**20719* Provided for backward compatibility, not available anymore.20720* @namespace Chart.LinearScaleBase20721* @deprecated since version 2.820722* @todo remove at version 320723* @private20724*/20725core_controller.LinearScaleBase = scale_linearbase;2072620727/**20728* Provided for backward compatibility, instead we should create a new Chart20729* by setting the type in the config (`new Chart(id, {type: '{chart-type}'}`).20730* @deprecated since version 2.8.020731* @todo remove at version 320732*/20733core_controller.helpers.each(20734[20735'Bar',20736'Bubble',20737'Doughnut',20738'Line',20739'PolarArea',20740'Radar',20741'Scatter'20742],20743function(klass) {20744core_controller[klass] = function(ctx, cfg) {20745return new core_controller(ctx, core_controller.helpers.merge(cfg || {}, {20746type: klass.charAt(0).toLowerCase() + klass.slice(1)20747}));20748};20749}20750);2075120752return src;2075320754})));207552075620757