diff --git a/dist/chart.esm.js b/dist/chart.esm.js new file mode 100644 index 00000000000..ca34603c395 --- /dev/null +++ b/dist/chart.esm.js @@ -0,0 +1,9264 @@ +/*! + * Chart.js v3.0.0-beta.2 + * https://www.chartjs.org + * (c) 2020 Chart.js Contributors + * Released under the MIT License + */ +import { r as requestAnimFrame, a as resolve, e as effects, c as color, i as isObject, d as defaults, n as noop, v as valueOrDefault, u as unlistenArrayEvents, l as listenArrayEvents, m as merge, b as isArray, f as resolveObjectKey, g as getHoverColor, _ as _capitalize, h as mergeIf, s as sign, j as _merger, k as _limitValue, o as clipArea, p as unclipArea, q as isNullOrUndef, t as isNumber, w as _lookupByKey, x as toRadians, y as getRelativePosition$1, z as _isPointInArea, A as _rlookupByKey, B as toPadding, C as each, D as getMaximumSize, E as _getParentNode, F as readUsedSize, G as throttled, H as supportsEventListenerOptions, I as log10, J as isNumberFinite, K as callback, L as toDegrees, M as _measureText, N as _int32Range, O as _alignPixel, P as toFont, Q as _factorize, R as uid, S as retinaScale, T as clear, U as _elementsEqual, V as getAngleFromPoint, W as _angleBetween, X as _updateBezierControlPoints, Y as _computeSegments, Z as _boundSegments, $ as _steppedInterpolation, a0 as _bezierInterpolation, a1 as _pointInLine, a2 as _steppedLineTo, a3 as _bezierCurveTo, a4 as drawPoint, a5 as toTRBL, a6 as _normalizeAngle, a7 as _boundSegment, a8 as getRtlAdapter, a9 as overrideTextDirection, aa as restoreTextDirection, ab as distanceBetweenPoints, ac as _setMinAndMaxByKey, ad as _decimalPlaces, ae as almostEquals, af as almostWhole, ag as _longestText, ah as _filterBetween, ai as _arrayUnique, aj as _lookup } from './chunks/helpers.rtl.js'; +export { d as defaults } from './chunks/helpers.rtl.js'; + +function drawFPS(chart, count, date, lastDate) { + const fps = (1000 / (date - lastDate)) | 0; + const ctx = chart.ctx; + ctx.save(); + ctx.clearRect(0, 0, 50, 24); + ctx.fillStyle = 'black'; + ctx.textAlign = 'right'; + if (count) { + ctx.fillText(count, 50, 8); + ctx.fillText(fps + ' fps', 50, 18); + } + ctx.restore(); +} +class Animator { + constructor() { + this._request = null; + this._charts = new Map(); + this._running = false; + this._lastDate = undefined; + } + _notify(chart, anims, date, type) { + const callbacks = anims.listeners[type] || []; + const numSteps = anims.duration; + callbacks.forEach(fn => fn({ + chart, + numSteps, + currentStep: Math.min(date - anims.start, numSteps) + })); + } + _refresh() { + const me = this; + if (me._request) { + return; + } + me._running = true; + me._request = requestAnimFrame.call(window, () => { + me._update(); + me._request = null; + if (me._running) { + me._refresh(); + } + }); + } + _update() { + const me = this; + const date = Date.now(); + let remaining = 0; + me._charts.forEach((anims, chart) => { + if (!anims.running || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + let draw = false; + let item; + for (; i >= 0; --i) { + item = items[i]; + if (item._active) { + item.tick(date); + draw = true; + } else { + items[i] = items[items.length - 1]; + items.pop(); + } + } + if (draw) { + chart.draw(); + me._notify(chart, anims, date, 'progress'); + } + if (chart.options.animation.debug) { + drawFPS(chart, items.length, date, me._lastDate); + } + if (!items.length) { + anims.running = false; + me._notify(chart, anims, date, 'complete'); + } + remaining += items.length; + }); + me._lastDate = date; + if (remaining === 0) { + me._running = false; + } + } + _getAnims(chart) { + const charts = this._charts; + let anims = charts.get(chart); + if (!anims) { + anims = { + running: false, + items: [], + listeners: { + complete: [], + progress: [] + } + }; + charts.set(chart, anims); + } + return anims; + } + listen(chart, event, cb) { + this._getAnims(chart).listeners[event].push(cb); + } + add(chart, items) { + if (!items || !items.length) { + return; + } + this._getAnims(chart).items.push(...items); + } + has(chart) { + return this._getAnims(chart).items.length > 0; + } + start(chart) { + const anims = this._charts.get(chart); + if (!anims) { + return; + } + anims.running = true; + anims.start = Date.now(); + anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0); + this._refresh(); + } + running(chart) { + if (!this._running) { + return false; + } + const anims = this._charts.get(chart); + if (!anims || !anims.running || !anims.items.length) { + return false; + } + return true; + } + stop(chart) { + const anims = this._charts.get(chart); + if (!anims || !anims.items.length) { + return; + } + const items = anims.items; + let i = items.length - 1; + for (; i >= 0; --i) { + items[i].cancel(); + } + anims.items = []; + this._notify(chart, anims, Date.now(), 'complete'); + } + remove(chart) { + return this._charts.delete(chart); + } +} +var animator = new Animator(); + +const transparent = 'transparent'; +const interpolators = { + boolean(from, to, factor) { + return factor > 0.5 ? to : from; + }, + color(from, to, factor) { + const c0 = color(from || transparent); + const c1 = c0.valid && color(to || transparent); + return c1 && c1.valid + ? c1.mix(c0, factor).hexString() + : to; + }, + number(from, to, factor) { + return from + (to - from) * factor; + } +}; +class Animation { + constructor(cfg, target, prop, to) { + const currentValue = target[prop]; + to = resolve([cfg.to, to, currentValue, cfg.from]); + const from = resolve([cfg.from, currentValue, to]); + this._active = true; + this._fn = cfg.fn || interpolators[cfg.type || typeof from]; + this._easing = effects[cfg.easing || 'linear']; + this._start = Math.floor(Date.now() + (cfg.delay || 0)); + this._duration = Math.floor(cfg.duration); + this._loop = !!cfg.loop; + this._target = target; + this._prop = prop; + this._from = from; + this._to = to; + this._promises = undefined; + } + active() { + return this._active; + } + update(cfg, to, date) { + const me = this; + if (me._active) { + const currentValue = me._target[me._prop]; + const elapsed = date - me._start; + const remain = me._duration - elapsed; + me._start = date; + me._duration = Math.floor(Math.max(remain, cfg.duration)); + me._loop = !!cfg.loop; + me._to = resolve([cfg.to, to, currentValue, cfg.from]); + me._from = resolve([cfg.from, currentValue, to]); + } + } + cancel() { + const me = this; + if (me._active) { + me.tick(Date.now()); + me._active = false; + me._notify(false); + } + } + tick(date) { + const me = this; + const elapsed = date - me._start; + const duration = me._duration; + const prop = me._prop; + const from = me._from; + const loop = me._loop; + const to = me._to; + let factor; + me._active = from !== to && (loop || (elapsed < duration)); + if (!me._active) { + me._target[prop] = to; + me._notify(true); + return; + } + if (elapsed < 0) { + me._target[prop] = from; + return; + } + factor = (elapsed / duration) % 2; + factor = loop && factor > 1 ? 2 - factor : factor; + factor = me._easing(Math.min(1, Math.max(0, factor))); + me._target[prop] = me._fn(from, to, factor); + } + wait() { + const promises = this._promises || (this._promises = []); + return new Promise((res, rej) => { + promises.push({res, rej}); + }); + } + _notify(resolved) { + const method = resolved ? 'res' : 'rej'; + const promises = this._promises || []; + for (let i = 0; i < promises.length; i++) { + promises[i][method](); + } + } +} + +const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; +const colors = ['borderColor', 'backgroundColor']; +defaults.set('animation', { + duration: 1000, + easing: 'easeOutQuart', + onProgress: noop, + onComplete: noop, + colors: { + type: 'color', + properties: colors + }, + numbers: { + type: 'number', + properties: numbers + }, + active: { + duration: 400 + }, + resize: { + duration: 0 + }, + show: { + colors: { + type: 'color', + properties: colors, + from: 'transparent' + }, + visible: { + type: 'boolean', + duration: 0 + }, + }, + hide: { + colors: { + type: 'color', + properties: colors, + to: 'transparent' + }, + visible: { + type: 'boolean', + easing: 'easeInExpo' + }, + } +}); +function copyOptions(target, values) { + const oldOpts = target.options; + const newOpts = values.options; + if (!oldOpts || !newOpts) { + return; + } + if (oldOpts.$shared && !newOpts.$shared) { + target.options = Object.assign({}, oldOpts, newOpts, {$shared: false}); + } else { + Object.assign(oldOpts, newOpts); + } + delete values.options; +} +function extensibleConfig(animations) { + const result = {}; + Object.keys(animations).forEach(key => { + const value = animations[key]; + if (!isObject(value)) { + result[key] = value; + } + }); + return result; +} +class Animations { + constructor(chart, animations) { + this._chart = chart; + this._properties = new Map(); + this.configure(animations); + } + configure(animations) { + if (!isObject(animations)) { + return; + } + const animatedProps = this._properties; + const animDefaults = extensibleConfig(animations); + Object.keys(animations).forEach(key => { + const cfg = animations[key]; + if (!isObject(cfg)) { + return; + } + (cfg.properties || [key]).forEach((prop) => { + if (!animatedProps.has(prop)) { + animatedProps.set(prop, Object.assign({}, animDefaults, cfg)); + } else if (prop === key) { + const {properties, ...inherited} = animatedProps.get(prop); + animatedProps.set(prop, Object.assign({}, inherited, cfg)); + } + }); + }); + } + _animateOptions(target, values) { + const newOptions = values.options; + const options = resolveTargetOptions(target, newOptions); + if (!options) { + return []; + } + const animations = this._createAnimations(options, newOptions); + if (newOptions.$shared && !options.$shared) { + awaitAll(target.options.$animations, newOptions).then(() => { + target.options = newOptions; + }); + } + return animations; + } + _createAnimations(target, values) { + const animatedProps = this._properties; + const animations = []; + const running = target.$animations || (target.$animations = {}); + const props = Object.keys(values); + const date = Date.now(); + let i; + for (i = props.length - 1; i >= 0; --i) { + const prop = props[i]; + if (prop.charAt(0) === '$') { + continue; + } + if (prop === 'options') { + animations.push(...this._animateOptions(target, values)); + continue; + } + const value = values[prop]; + let animation = running[prop]; + const cfg = animatedProps.get(prop); + if (animation) { + if (cfg && animation.active()) { + animation.update(cfg, value, date); + continue; + } else { + animation.cancel(); + } + } + if (!cfg || !cfg.duration) { + target[prop] = value; + continue; + } + running[prop] = animation = new Animation(cfg, target, prop, value); + animations.push(animation); + } + return animations; + } + update(target, values) { + if (this._properties.size === 0) { + copyOptions(target, values); + Object.assign(target, values); + return; + } + const animations = this._createAnimations(target, values); + if (animations.length) { + animator.add(this._chart, animations); + return true; + } + } +} +function awaitAll(animations, properties) { + const running = []; + const keys = Object.keys(properties); + for (let i = 0; i < keys.length; i++) { + const anim = animations[keys[i]]; + if (anim && anim.active()) { + running.push(anim.wait()); + } + } + return Promise.all(running); +} +function resolveTargetOptions(target, newOptions) { + if (!newOptions) { + return; + } + let options = target.options; + if (!options) { + target.options = newOptions; + return; + } + if (options.$shared && !newOptions.$shared) { + target.options = options = Object.assign({}, options, {$shared: false, $animations: {}}); + } + return options; +} + +function scaleClip(scale, allowedOverflow) { + const opts = scale && scale.options || {}; + const reverse = opts.reverse; + const min = opts.min === undefined ? allowedOverflow : 0; + const max = opts.max === undefined ? allowedOverflow : 0; + return { + start: reverse ? max : min, + end: reverse ? min : max + }; +} +function defaultClip(xScale, yScale, allowedOverflow) { + if (allowedOverflow === false) { + return false; + } + const x = scaleClip(xScale, allowedOverflow); + const y = scaleClip(yScale, allowedOverflow); + return { + top: y.end, + right: x.end, + bottom: y.start, + left: x.start + }; +} +function toClip(value) { + let t, r, b, l; + if (isObject(value)) { + t = value.top; + r = value.right; + b = value.bottom; + l = value.left; + } else { + t = r = b = l = value; + } + return { + top: t, + right: r, + bottom: b, + left: l + }; +} +function getSortedDatasetIndices(chart, filterVisible) { + const keys = []; + const metasets = chart._getSortedDatasetMetas(filterVisible); + let i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + keys.push(metasets[i].index); + } + return keys; +} +function applyStack(stack, value, dsIndex, allOther) { + const keys = stack.keys; + let i, ilen, datasetIndex, otherValue; + for (i = 0, ilen = keys.length; i < ilen; ++i) { + datasetIndex = +keys[i]; + if (datasetIndex === dsIndex) { + if (allOther) { + continue; + } + break; + } + otherValue = stack.values[datasetIndex]; + if (!isNaN(otherValue) && (value === 0 || sign(value) === sign(otherValue))) { + value += otherValue; + } + } + return value; +} +function convertObjectDataToArray(data) { + const keys = Object.keys(data); + const adata = new Array(keys.length); + let i, ilen, key; + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + adata[i] = { + x: key, + y: data[key] + }; + } + return adata; +} +function isStacked(scale, meta) { + const stacked = scale && scale.options.stacked; + return stacked || (stacked === undefined && meta.stack !== undefined); +} +function getStackKey(indexScale, valueScale, meta) { + return indexScale.id + '.' + valueScale.id + '.' + meta.stack + '.' + meta.type; +} +function getUserBounds(scale) { + const {min, max, minDefined, maxDefined} = scale.getUserBounds(); + return { + min: minDefined ? min : Number.NEGATIVE_INFINITY, + max: maxDefined ? max : Number.POSITIVE_INFINITY + }; +} +function getOrCreateStack(stacks, stackKey, indexValue) { + const subStack = stacks[stackKey] || (stacks[stackKey] = {}); + return subStack[indexValue] || (subStack[indexValue] = {}); +} +function updateStacks(controller, parsed) { + const {chart, _cachedMeta: meta} = controller; + const stacks = chart._stacks || (chart._stacks = {}); + const {iScale, vScale, index: datasetIndex} = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const key = getStackKey(iScale, vScale, meta); + const ilen = parsed.length; + let stack; + for (let i = 0; i < ilen; ++i) { + const item = parsed[i]; + const {[iAxis]: index, [vAxis]: value} = item; + const itemStacks = item._stacks || (item._stacks = {}); + stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); + stack[datasetIndex] = value; + } +} +function getFirstScaleId(chart, axis) { + const scales = chart.scales; + return Object.keys(scales).filter(key => scales[key].axis === axis).shift(); +} +function optionKeys(optionNames) { + return isArray(optionNames) ? optionNames : Object.keys(optionNames); +} +function optionKey(key, active) { + return active ? 'hover' + _capitalize(key) : key; +} +function isDirectUpdateMode(mode) { + return mode === 'reset' || mode === 'none'; +} +class DatasetController { + constructor(chart, datasetIndex) { + this.chart = chart; + this._ctx = chart.ctx; + this.index = datasetIndex; + this._cachedAnimations = {}; + this._cachedDataOpts = {}; + this._cachedMeta = this.getMeta(); + this._type = this._cachedMeta.type; + this._config = undefined; + this._parsing = false; + this._data = undefined; + this._objectData = undefined; + this._sharedOptions = undefined; + this._drawStart = undefined; + this._drawCount = undefined; + this.enableOptionSharing = false; + this.initialize(); + } + initialize() { + const me = this; + const meta = me._cachedMeta; + me.configure(); + me.linkScales(); + meta._stacked = isStacked(meta.vScale, meta); + me.addElements(); + } + updateIndex(datasetIndex) { + this.index = datasetIndex; + } + linkScales() { + const me = this; + const chart = me.chart; + const meta = me._cachedMeta; + const dataset = me.getDataset(); + const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y; + const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); + const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); + const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); + const indexAxis = meta.indexAxis; + const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); + const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); + meta.xScale = me.getScaleForId(xid); + meta.yScale = me.getScaleForId(yid); + meta.rScale = me.getScaleForId(rid); + meta.iScale = me.getScaleForId(iid); + meta.vScale = me.getScaleForId(vid); + } + getDataset() { + return this.chart.data.datasets[this.index]; + } + getMeta() { + return this.chart.getDatasetMeta(this.index); + } + getScaleForId(scaleID) { + return this.chart.scales[scaleID]; + } + _getOtherScale(scale) { + const meta = this._cachedMeta; + return scale === meta.iScale + ? meta.vScale + : meta.iScale; + } + reset() { + this._update('reset'); + } + _destroy() { + if (this._data) { + unlistenArrayEvents(this._data, this); + } + } + _dataCheck() { + const me = this; + const dataset = me.getDataset(); + const data = dataset.data || (dataset.data = []); + if (isObject(data)) { + me._data = convertObjectDataToArray(data); + } else if (me._data !== data) { + if (me._data) { + unlistenArrayEvents(me._data, me); + } + if (data && Object.isExtensible(data)) { + listenArrayEvents(data, me); + } + me._data = data; + } + } + addElements() { + const me = this; + const meta = me._cachedMeta; + me._dataCheck(); + const data = me._data; + const metaData = meta.data = new Array(data.length); + for (let i = 0, ilen = data.length; i < ilen; ++i) { + metaData[i] = new me.dataElementType(); + } + if (me.datasetElementType) { + meta.dataset = new me.datasetElementType(); + } + } + buildOrUpdateElements() { + const me = this; + const meta = me._cachedMeta; + const dataset = me.getDataset(); + let stackChanged = false; + me._dataCheck(); + meta._stacked = isStacked(meta.vScale, meta); + if (meta.stack !== dataset.stack) { + stackChanged = true; + meta._parsed.forEach((parsed) => { + delete parsed._stacks[meta.vScale.id][meta.index]; + }); + meta.stack = dataset.stack; + } + me._resyncElements(); + if (stackChanged) { + updateStacks(me, meta._parsed); + } + } + configure() { + const me = this; + me._config = merge({}, [ + me.chart.options[me._type].datasets, + me.getDataset(), + ], { + merger(key, target, source) { + if (key !== 'data') { + _merger(key, target, source); + } + } + }); + me._parsing = resolve([me._config.parsing, me.chart.options.parsing, true]); + } + parse(start, count) { + const me = this; + const {_cachedMeta: meta, _data: data} = me; + const {iScale, vScale, _stacked} = meta; + const iAxis = iScale.axis; + let sorted = true; + let i, parsed, cur, prev; + if (start > 0) { + sorted = meta._sorted; + prev = meta._parsed[start - 1]; + } + if (me._parsing === false) { + meta._parsed = data; + meta._sorted = true; + } else { + if (isArray(data[start])) { + parsed = me.parseArrayData(meta, data, start, count); + } else if (isObject(data[start])) { + parsed = me.parseObjectData(meta, data, start, count); + } else { + parsed = me.parsePrimitiveData(meta, data, start, count); + } + const isNotInOrderComparedToPrev = () => isNaN(cur[iAxis]) || (prev && cur[iAxis] < prev[iAxis]); + for (i = 0; i < count; ++i) { + meta._parsed[i + start] = cur = parsed[i]; + if (sorted) { + if (isNotInOrderComparedToPrev()) { + sorted = false; + } + prev = cur; + } + } + meta._sorted = sorted; + } + if (_stacked) { + updateStacks(me, parsed); + } + iScale.invalidateCaches(); + vScale.invalidateCaches(); + } + parsePrimitiveData(meta, data, start, count) { + const {iScale, vScale} = meta; + const iAxis = iScale.axis; + const vAxis = vScale.axis; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = new Array(count); + let i, ilen, index; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + parsed[i] = { + [iAxis]: singleScale || iScale.parse(labels[index], index), + [vAxis]: vScale.parse(data[index], index) + }; + } + return parsed; + } + parseArrayData(meta, data, start, count) { + const {xScale, yScale} = meta; + const parsed = new Array(count); + let i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(item[0], index), + y: yScale.parse(item[1], index) + }; + } + return parsed; + } + parseObjectData(meta, data, start, count) { + const {xScale, yScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const parsed = new Array(count); + let i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(resolveObjectKey(item, xAxisKey), index), + y: yScale.parse(resolveObjectKey(item, yAxisKey), index) + }; + } + return parsed; + } + getParsed(index) { + return this._cachedMeta._parsed[index]; + } + applyStack(scale, parsed) { + const chart = this.chart; + const meta = this._cachedMeta; + const value = parsed[scale.axis]; + const stack = { + keys: getSortedDatasetIndices(chart, true), + values: parsed._stacks[scale.axis] + }; + return applyStack(stack, value, meta.index); + } + updateRangeFromParsed(range, scale, parsed, stack) { + let value = parsed[scale.axis]; + const values = stack && parsed._stacks[scale.axis]; + if (stack && values) { + stack.values = values; + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + value = applyStack(stack, value, this._cachedMeta.index, true); + } + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + } + getMinMax(scale, canStack) { + const me = this; + const meta = me._cachedMeta; + const _parsed = meta._parsed; + const sorted = meta._sorted && scale === meta.iScale; + const ilen = _parsed.length; + const otherScale = me._getOtherScale(scale); + const stack = canStack && meta._stacked && {keys: getSortedDatasetIndices(me.chart, true), values: null}; + const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY}; + const {min: otherMin, max: otherMax} = getUserBounds(otherScale); + let i, value, parsed, otherValue; + function _skip() { + parsed = _parsed[i]; + value = parsed[scale.axis]; + otherValue = parsed[otherScale.axis]; + return (isNaN(value) || isNaN(otherValue) || otherMin > otherValue || otherMax < otherValue); + } + for (i = 0; i < ilen; ++i) { + if (_skip()) { + continue; + } + me.updateRangeFromParsed(range, scale, parsed, stack); + if (sorted) { + break; + } + } + if (sorted) { + for (i = ilen - 1; i >= 0; --i) { + if (_skip()) { + continue; + } + me.updateRangeFromParsed(range, scale, parsed, stack); + break; + } + } + return range; + } + getAllParsedValues(scale) { + const parsed = this._cachedMeta._parsed; + const values = []; + let i, ilen, value; + for (i = 0, ilen = parsed.length; i < ilen; ++i) { + value = parsed[i][scale.axis]; + if (!isNaN(value)) { + values.push(value); + } + } + return values; + } + getMaxOverflow() { + return false; + } + getLabelAndValue(index) { + const me = this; + const meta = me._cachedMeta; + const iScale = meta.iScale; + const vScale = meta.vScale; + const parsed = me.getParsed(index); + return { + label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', + value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' + }; + } + _update(mode) { + const me = this; + const meta = me._cachedMeta; + me.configure(); + me._cachedAnimations = {}; + me._cachedDataOpts = {}; + me.update(mode || 'default'); + meta._clip = toClip(valueOrDefault(me._config.clip, defaultClip(meta.xScale, meta.yScale, me.getMaxOverflow()))); + } + update(mode) {} + draw() { + const me = this; + const ctx = me._ctx; + const chart = me.chart; + const meta = me._cachedMeta; + const elements = meta.data || []; + const area = chart.chartArea; + const active = []; + const start = me._drawStart || 0; + const count = me._drawCount || (elements.length - start); + let i; + if (meta.dataset) { + meta.dataset.draw(ctx, area, start, count); + } + for (i = start; i < start + count; ++i) { + const element = elements[i]; + if (element.active) { + active.push(element); + } else { + element.draw(ctx, area); + } + } + for (i = 0; i < active.length; ++i) { + active[i].draw(ctx, area); + } + } + _addAutomaticHoverColors(index, options) { + const me = this; + const normalOptions = me.getStyle(index); + const missingColors = Object.keys(normalOptions).filter(key => key.indexOf('Color') !== -1 && !(key in options)); + let i = missingColors.length - 1; + let color; + for (; i >= 0; i--) { + color = missingColors[i]; + options[color] = getHoverColor(normalOptions[color]); + } + } + getStyle(index, active) { + const me = this; + const meta = me._cachedMeta; + const dataset = meta.dataset; + if (!me._config) { + me.configure(); + } + const options = dataset && index === undefined + ? me.resolveDatasetElementOptions(active) + : me.resolveDataElementOptions(index || 0, active && 'active'); + if (active) { + me._addAutomaticHoverColors(index, options); + } + return options; + } + _getContext(index, active) { + return { + chart: this.chart, + dataPoint: this.getParsed(index), + dataIndex: index, + dataset: this.getDataset(), + datasetIndex: this.index, + active + }; + } + resolveDatasetElementOptions(active) { + return this._resolveOptions(this.datasetElementOptions, { + active, + type: this.datasetElementType.id + }); + } + resolveDataElementOptions(index, mode) { + mode = mode || 'default'; + const me = this; + const active = mode === 'active'; + const cached = me._cachedDataOpts; + const sharing = me.enableOptionSharing; + if (cached[mode]) { + return cached[mode]; + } + const info = {cacheable: !active}; + const values = me._resolveOptions(me.dataElementOptions, { + index, + active, + info, + type: me.dataElementType.id + }); + if (info.cacheable) { + values.$shared = sharing; + cached[mode] = sharing ? Object.freeze(values) : values; + } + return values; + } + _resolveOptions(optionNames, args) { + const me = this; + const {index, active, type, info} = args; + const datasetOpts = me._config; + const options = me.chart.options.elements[type] || {}; + const values = {}; + const context = me._getContext(index, active); + const keys = optionKeys(optionNames); + for (let i = 0, ilen = keys.length; i < ilen; ++i) { + const key = keys[i]; + const readKey = optionKey(key, active); + const value = resolve([ + datasetOpts[optionNames[readKey]], + datasetOpts[readKey], + options[readKey] + ], context, index, info); + if (value !== undefined) { + values[key] = value; + } + } + return values; + } + _resolveAnimations(index, mode, active) { + const me = this; + const chart = me.chart; + const cached = me._cachedAnimations; + mode = mode || 'default'; + if (cached[mode]) { + return cached[mode]; + } + const info = {cacheable: true}; + const context = me._getContext(index, active); + const chartAnim = resolve([chart.options.animation], context, index, info); + const datasetAnim = resolve([me._config.animation], context, index, info); + let config = chartAnim && mergeIf({}, [datasetAnim, chartAnim]); + if (config[mode]) { + config = Object.assign({}, config, config[mode]); + } + const animations = new Animations(chart, config); + if (info.cacheable) { + cached[mode] = animations && Object.freeze(animations); + } + return animations; + } + getSharedOptions(options) { + if (!options.$shared) { + return; + } + return this._sharedOptions || (this._sharedOptions = Object.assign({}, options)); + } + includeOptions(mode, sharedOptions) { + return !sharedOptions || isDirectUpdateMode(mode); + } + updateElement(element, index, properties, mode) { + if (isDirectUpdateMode(mode)) { + Object.assign(element, properties); + } else { + this._resolveAnimations(index, mode).update(element, properties); + } + } + updateSharedOptions(sharedOptions, mode, newOptions) { + if (sharedOptions) { + this._resolveAnimations(undefined, mode).update({options: sharedOptions}, {options: newOptions}); + } + } + _setStyle(element, index, mode, active) { + element.active = active; + const options = this.getStyle(index, active); + this._resolveAnimations(index, mode, active).update(element, {options: this.getSharedOptions(options) || options}); + } + removeHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', false); + } + setHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', true); + } + _removeDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', false); + } + } + _setDatasetHoverStyle() { + const element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', true); + } + } + _resyncElements() { + const me = this; + const meta = me._cachedMeta; + const numMeta = meta.data.length; + const numData = me._data.length; + if (numData > numMeta) { + me._insertElements(numMeta, numData - numMeta); + } else if (numData < numMeta) { + meta.data.splice(numData, numMeta - numData); + meta._parsed.splice(numData, numMeta - numData); + } + me.parse(0, Math.min(numData, numMeta)); + } + _insertElements(start, count) { + const me = this; + const elements = new Array(count); + const meta = me._cachedMeta; + const data = meta.data; + let i; + for (i = 0; i < count; ++i) { + elements[i] = new me.dataElementType(); + } + data.splice(start, 0, ...elements); + if (me._parsing) { + meta._parsed.splice(start, 0, ...new Array(count)); + } + me.parse(start, count); + me.updateElements(data, start, count, 'reset'); + } + updateElements(element, start, count, mode) {} + _removeElements(start, count) { + const me = this; + if (me._parsing) { + me._cachedMeta._parsed.splice(start, count); + } + me._cachedMeta.data.splice(start, count); + } + _onDataPush() { + const count = arguments.length; + this._insertElements(this.getDataset().data.length - count, count); + } + _onDataPop() { + this._removeElements(this._cachedMeta.data.length - 1, 1); + } + _onDataShift() { + this._removeElements(0, 1); + } + _onDataSplice(start, count) { + this._removeElements(start, count); + this._insertElements(start, arguments.length - 2); + } + _onDataUnshift() { + this._insertElements(0, arguments.length); + } +} +DatasetController.defaults = {}; +DatasetController.prototype.datasetElementType = null; +DatasetController.prototype.dataElementType = null; +DatasetController.prototype.datasetElementOptions = [ + 'backgroundColor', + 'borderCapStyle', + 'borderColor', + 'borderDash', + 'borderDashOffset', + 'borderJoinStyle', + 'borderWidth' +]; +DatasetController.prototype.dataElementOptions = [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'pointStyle' +]; + +function computeMinSampleSize(scale, pixels) { + let min = scale._length; + let prev, curr, i, ilen; + for (i = 1, ilen = pixels.length; i < ilen; ++i) { + min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1])); + } + for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { + curr = scale.getPixelForTick(i); + min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min; + prev = curr; + } + return min; +} +function computeFitCategoryTraits(index, ruler, options) { + const thickness = options.barThickness; + const count = ruler.stackCount; + let size, ratio; + if (isNullOrUndef(thickness)) { + size = ruler.min * options.categoryPercentage; + ratio = options.barPercentage; + } else { + size = thickness * count; + ratio = 1; + } + return { + chunk: size / count, + ratio, + start: ruler.pixels[index] - (size / 2) + }; +} +function computeFlexCategoryTraits(index, ruler, options) { + const pixels = ruler.pixels; + const curr = pixels[index]; + let prev = index > 0 ? pixels[index - 1] : null; + let next = index < pixels.length - 1 ? pixels[index + 1] : null; + const percent = options.categoryPercentage; + if (prev === null) { + prev = curr - (next === null ? ruler.end - ruler.start : next - curr); + } + if (next === null) { + next = curr + curr - prev; + } + const start = curr - (curr - Math.min(prev, next)) / 2 * percent; + const size = Math.abs(next - prev) / 2 * percent; + return { + chunk: size / ruler.stackCount, + ratio: options.barPercentage, + start + }; +} +function parseFloatBar(entry, item, vScale, i) { + const startValue = vScale.parse(entry[0], i); + const endValue = vScale.parse(entry[1], i); + const min = Math.min(startValue, endValue); + const max = Math.max(startValue, endValue); + let barStart = min; + let barEnd = max; + if (Math.abs(min) > Math.abs(max)) { + barStart = max; + barEnd = min; + } + item[vScale.axis] = barEnd; + item._custom = { + barStart, + barEnd, + start: startValue, + end: endValue, + min, + max + }; +} +function parseValue(entry, item, vScale, i) { + if (isArray(entry)) { + parseFloatBar(entry, item, vScale, i); + } else { + item[vScale.axis] = vScale.parse(entry, i); + } + return item; +} +function parseArrayOrPrimitive(meta, data, start, count) { + const iScale = meta.iScale; + const vScale = meta.vScale; + const labels = iScale.getLabels(); + const singleScale = iScale === vScale; + const parsed = []; + let i, ilen, item, entry; + for (i = start, ilen = start + count; i < ilen; ++i) { + entry = data[i]; + item = {}; + item[iScale.axis] = singleScale || iScale.parse(labels[i], i); + parsed.push(parseValue(entry, item, vScale, i)); + } + return parsed; +} +function isFloatBar(custom) { + return custom && custom.barStart !== undefined && custom.barEnd !== undefined; +} +class BarController extends DatasetController { + parsePrimitiveData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseArrayData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + parseObjectData(meta, data, start, count) { + const {iScale, vScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; + const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; + const parsed = []; + let i, ilen, item, obj; + for (i = start, ilen = start + count; i < ilen; ++i) { + obj = data[i]; + item = {}; + item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); + parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); + } + return parsed; + } + updateRangeFromParsed(range, scale, parsed, stack) { + super.updateRangeFromParsed(range, scale, parsed, stack); + const custom = parsed._custom; + if (custom && scale === this._cachedMeta.vScale) { + range.min = Math.min(range.min, custom.min); + range.max = Math.max(range.max, custom.max); + } + } + getLabelAndValue(index) { + const me = this; + const meta = me._cachedMeta; + const {iScale, vScale} = meta; + const parsed = me.getParsed(index); + const custom = parsed._custom; + const value = isFloatBar(custom) + ? '[' + custom.start + ', ' + custom.end + ']' + : '' + vScale.getLabelForValue(parsed[vScale.axis]); + return { + label: '' + iScale.getLabelForValue(parsed[iScale.axis]), + value + }; + } + initialize() { + const me = this; + me.enableOptionSharing = true; + super.initialize(); + const meta = me._cachedMeta; + meta.stack = me.getDataset().stack; + } + update(mode) { + const me = this; + const meta = me._cachedMeta; + me.updateElements(meta.data, 0, meta.data.length, mode); + } + updateElements(rectangles, start, count, mode) { + const me = this; + const reset = mode === 'reset'; + const vscale = me._cachedMeta.vScale; + const base = vscale.getBasePixel(); + const horizontal = vscale.isHorizontal(); + const ruler = me._getRuler(); + const firstOpts = me.resolveDataElementOptions(start, mode); + const sharedOptions = me.getSharedOptions(firstOpts); + const includeOptions = me.includeOptions(mode, sharedOptions); + me.updateSharedOptions(sharedOptions, mode, firstOpts); + for (let i = start; i < start + count; i++) { + const options = sharedOptions || me.resolveDataElementOptions(i, mode); + const vpixels = me._calculateBarValuePixels(i, options); + const ipixels = me._calculateBarIndexPixels(i, ruler, options); + const properties = { + horizontal, + base: reset ? base : vpixels.base, + x: horizontal ? reset ? base : vpixels.head : ipixels.center, + y: horizontal ? ipixels.center : reset ? base : vpixels.head, + height: horizontal ? ipixels.size : undefined, + width: horizontal ? undefined : ipixels.size + }; + if (includeOptions) { + properties.options = options; + } + me.updateElement(rectangles[i], i, properties, mode); + } + } + _getStacks(last) { + const me = this; + const meta = me._cachedMeta; + const iScale = meta.iScale; + const metasets = iScale.getMatchingVisibleMetas(me._type); + const stacked = iScale.options.stacked; + const ilen = metasets.length; + const stacks = []; + let i, item; + for (i = 0; i < ilen; ++i) { + item = metasets[i]; + if (stacked === false || stacks.indexOf(item.stack) === -1 || + (stacked === undefined && item.stack === undefined)) { + stacks.push(item.stack); + } + if (item.index === last) { + break; + } + } + if (!stacks.length) { + stacks.push(undefined); + } + return stacks; + } + _getStackCount() { + return this._getStacks().length; + } + _getStackIndex(datasetIndex, name) { + const stacks = this._getStacks(datasetIndex); + const index = (name !== undefined) + ? stacks.indexOf(name) + : -1; + return (index === -1) + ? stacks.length - 1 + : index; + } + _getRuler() { + const me = this; + const meta = me._cachedMeta; + const iScale = meta.iScale; + const pixels = []; + let i, ilen; + for (i = 0, ilen = meta.data.length; i < ilen; ++i) { + pixels.push(iScale.getPixelForValue(me.getParsed(i)[iScale.axis], i)); + } + const min = computeMinSampleSize(iScale, pixels); + return { + min, + pixels, + start: iScale._startPixel, + end: iScale._endPixel, + stackCount: me._getStackCount(), + scale: iScale + }; + } + _calculateBarValuePixels(index, options) { + const me = this; + const meta = me._cachedMeta; + const vScale = meta.vScale; + const minBarLength = options.minBarLength; + const parsed = me.getParsed(index); + const custom = parsed._custom; + let value = parsed[vScale.axis]; + let start = 0; + let length = meta._stacked ? me.applyStack(vScale, parsed) : value; + let head, size; + if (length !== value) { + start = length - value; + length = value; + } + if (isFloatBar(custom)) { + value = custom.barStart; + length = custom.barEnd - custom.barStart; + if (value !== 0 && sign(value) !== sign(custom.barEnd)) { + start = 0; + } + start += value; + } + let base = _limitValue(vScale.getPixelForValue(start), + vScale._startPixel - 10, + vScale._endPixel + 10); + head = vScale.getPixelForValue(start + length); + size = head - base; + if (minBarLength !== undefined && Math.abs(size) < minBarLength) { + size = size < 0 ? -minBarLength : minBarLength; + if (value === 0) { + base -= size / 2; + } + head = base + size; + } + return { + size, + base, + head, + center: head + size / 2 + }; + } + _calculateBarIndexPixels(index, ruler, options) { + const me = this; + const range = options.barThickness === 'flex' + ? computeFlexCategoryTraits(index, ruler, options) + : computeFitCategoryTraits(index, ruler, options); + const stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack); + const center = range.start + (range.chunk * stackIndex) + (range.chunk / 2); + const size = Math.min( + valueOrDefault(options.maxBarThickness, Infinity), + range.chunk * range.ratio); + return { + base: center - size / 2, + head: center + size / 2, + center, + size + }; + } + draw() { + const me = this; + const chart = me.chart; + const meta = me._cachedMeta; + const vScale = meta.vScale; + const rects = meta.data; + const ilen = rects.length; + let i = 0; + clipArea(chart.ctx, chart.chartArea); + for (; i < ilen; ++i) { + if (!isNaN(me.getParsed(i)[vScale.axis])) { + rects[i].draw(me._ctx); + } + } + unclipArea(chart.ctx); + } +} +BarController.id = 'bar'; +BarController.defaults = { + datasetElementType: false, + dataElementType: 'rectangle', + dataElementOptions: [ + 'backgroundColor', + 'borderColor', + 'borderSkipped', + 'borderWidth', + 'barPercentage', + 'barThickness', + 'categoryPercentage', + 'maxBarThickness', + 'minBarLength' + ], + hover: { + mode: 'index' + }, + datasets: { + categoryPercentage: 0.8, + barPercentage: 0.9, + animation: { + numbers: { + type: 'number', + properties: ['x', 'y', 'base', 'width', 'height'] + } + } + }, + scales: { + _index_: { + type: 'category', + offset: true, + gridLines: { + offsetGridLines: true + } + }, + _value_: { + type: 'linear', + beginAtZero: true, + } + } +}; + +class BubbleController extends DatasetController { + initialize() { + this.enableOptionSharing = true; + super.initialize(); + } + parseObjectData(meta, data, start, count) { + const {xScale, yScale} = meta; + const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing; + const parsed = []; + let i, ilen, item; + for (i = start, ilen = start + count; i < ilen; ++i) { + item = data[i]; + parsed.push({ + x: xScale.parse(resolveObjectKey(item, xAxisKey), i), + y: yScale.parse(resolveObjectKey(item, yAxisKey), i), + _custom: item && item.r && +item.r + }); + } + return parsed; + } + getMaxOverflow() { + const me = this; + const meta = me._cachedMeta; + let i = (meta.data || []).length - 1; + let max = 0; + for (; i >= 0; --i) { + max = Math.max(max, me.getStyle(i, true).radius); + } + return max > 0 && max; + } + getLabelAndValue(index) { + const me = this; + const meta = me._cachedMeta; + const {xScale, yScale} = meta; + const parsed = me.getParsed(index); + const x = xScale.getLabelForValue(parsed.x); + const y = yScale.getLabelForValue(parsed.y); + const r = parsed._custom; + return { + label: meta.label, + value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' + }; + } + update(mode) { + const me = this; + const points = me._cachedMeta.data; + me.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const me = this; + const reset = mode === 'reset'; + const {xScale, yScale} = me._cachedMeta; + const firstOpts = me.resolveDataElementOptions(start, mode); + const sharedOptions = me.getSharedOptions(firstOpts); + const includeOptions = me.includeOptions(mode, sharedOptions); + for (let i = start; i < start + count; i++) { + const point = points[i]; + const parsed = !reset && me.getParsed(i); + const x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(parsed.x); + const y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(parsed.y); + const properties = { + x, + y, + skip: isNaN(x) || isNaN(y) + }; + if (includeOptions) { + properties.options = me.resolveDataElementOptions(i, mode); + if (reset) { + properties.options.radius = 0; + } + } + me.updateElement(point, i, properties, mode); + } + me.updateSharedOptions(sharedOptions, mode, firstOpts); + } + resolveDataElementOptions(index, mode) { + const me = this; + const chart = me.chart; + const dataset = me.getDataset(); + const parsed = me.getParsed(index); + let values = super.resolveDataElementOptions(index, mode); + const context = { + chart, + dataPoint: parsed, + dataIndex: index, + dataset, + datasetIndex: me.index + }; + if (values.$shared) { + values = Object.assign({}, values, {$shared: false}); + } + if (mode !== 'active') { + values.radius = 0; + } + values.radius += resolve([ + parsed && parsed._custom, + me._config.radius, + chart.options.elements.point.radius + ], context, index); + return values; + } +} +BubbleController.id = 'bubble'; +BubbleController.defaults = { + datasetElementType: false, + dataElementType: 'point', + dataElementOptions: [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'hitRadius', + 'radius', + 'pointStyle', + 'rotation' + ], + animation: { + numbers: { + properties: ['x', 'y', 'borderWidth', 'radius'] + } + }, + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + }, + tooltips: { + callbacks: { + title() { + return ''; + } + } + } +}; + +const PI = Math.PI; +const DOUBLE_PI = PI * 2; +const HALF_PI = PI / 2; +function getRatioAndOffset(rotation, circumference, cutout) { + let ratioX = 1; + let ratioY = 1; + let offsetX = 0; + let offsetY = 0; + if (circumference < DOUBLE_PI) { + let startAngle = rotation % DOUBLE_PI; + startAngle += startAngle >= PI ? -DOUBLE_PI : startAngle < -PI ? DOUBLE_PI : 0; + const endAngle = startAngle + circumference; + const startX = Math.cos(startAngle); + const startY = Math.sin(startAngle); + const endX = Math.cos(endAngle); + const endY = Math.sin(endAngle); + const contains0 = (startAngle <= 0 && endAngle >= 0) || endAngle >= DOUBLE_PI; + const contains90 = (startAngle <= HALF_PI && endAngle >= HALF_PI) || endAngle >= DOUBLE_PI + HALF_PI; + const contains180 = startAngle === -PI || endAngle >= PI; + const contains270 = (startAngle <= -HALF_PI && endAngle >= -HALF_PI) || endAngle >= PI + HALF_PI; + const minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout); + const minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout); + const maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout); + const maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout); + ratioX = (maxX - minX) / 2; + ratioY = (maxY - minY) / 2; + offsetX = -(maxX + minX) / 2; + offsetY = -(maxY + minY) / 2; + } + return {ratioX, ratioY, offsetX, offsetY}; +} +class DoughnutController extends DatasetController { + constructor(chart, datasetIndex) { + super(chart, datasetIndex); + this.enableOptionSharing = true; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.offsetX = undefined; + this.offsetY = undefined; + } + linkScales() {} + parse(start, count) { + const data = this.getDataset().data; + const meta = this._cachedMeta; + let i, ilen; + for (i = start, ilen = start + count; i < ilen; ++i) { + meta._parsed[i] = +data[i]; + } + } + getRingIndex(datasetIndex) { + let ringIndex = 0; + for (let j = 0; j < datasetIndex; ++j) { + if (this.chart.isDatasetVisible(j)) { + ++ringIndex; + } + } + return ringIndex; + } + update(mode) { + const me = this; + const chart = me.chart; + const {chartArea, options} = chart; + const meta = me._cachedMeta; + const arcs = meta.data; + const cutout = options.cutoutPercentage / 100 || 0; + const chartWeight = me._getRingWeight(me.index); + const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(options.rotation, options.circumference, cutout); + const spacing = me.getMaxBorderWidth() + me.getMaxOffset(arcs); + const maxWidth = (chartArea.right - chartArea.left - spacing) / ratioX; + const maxHeight = (chartArea.bottom - chartArea.top - spacing) / ratioY; + const outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); + const innerRadius = Math.max(outerRadius * cutout, 0); + const radiusLength = (outerRadius - innerRadius) / me._getVisibleDatasetWeightTotal(); + me.offsetX = offsetX * outerRadius; + me.offsetY = offsetY * outerRadius; + meta.total = me.calculateTotal(); + me.outerRadius = outerRadius - radiusLength * me._getRingWeightOffset(me.index); + me.innerRadius = Math.max(me.outerRadius - radiusLength * chartWeight, 0); + me.updateElements(arcs, 0, arcs.length, mode); + } + _circumference(i, reset) { + const me = this; + const opts = me.chart.options; + const meta = me._cachedMeta; + return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * opts.circumference / DOUBLE_PI) : 0; + } + updateElements(arcs, start, count, mode) { + const me = this; + const reset = mode === 'reset'; + const chart = me.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const animationOpts = opts.animation; + const centerX = (chartArea.left + chartArea.right) / 2; + const centerY = (chartArea.top + chartArea.bottom) / 2; + const animateScale = reset && animationOpts.animateScale; + const innerRadius = animateScale ? 0 : me.innerRadius; + const outerRadius = animateScale ? 0 : me.outerRadius; + const firstOpts = me.resolveDataElementOptions(start, mode); + const sharedOptions = me.getSharedOptions(firstOpts); + const includeOptions = me.includeOptions(mode, sharedOptions); + let startAngle = opts.rotation; + let i; + for (i = 0; i < start; ++i) { + startAngle += me._circumference(i, reset); + } + for (i = start; i < start + count; ++i) { + const circumference = me._circumference(i, reset); + const arc = arcs[i]; + const properties = { + x: centerX + me.offsetX, + y: centerY + me.offsetY, + startAngle, + endAngle: startAngle + circumference, + circumference, + outerRadius, + innerRadius + }; + if (includeOptions) { + properties.options = sharedOptions || me.resolveDataElementOptions(i, mode); + } + startAngle += circumference; + me.updateElement(arc, i, properties, mode); + } + me.updateSharedOptions(sharedOptions, mode, firstOpts); + } + calculateTotal() { + const meta = this._cachedMeta; + const metaData = meta.data; + let total = 0; + let i; + for (i = 0; i < metaData.length; i++) { + const value = meta._parsed[i]; + if (!isNaN(value) && this.chart.getDataVisibility(i)) { + total += Math.abs(value); + } + } + return total; + } + calculateCircumference(value) { + const total = this._cachedMeta.total; + if (total > 0 && !isNaN(value)) { + return DOUBLE_PI * (Math.abs(value) / total); + } + return 0; + } + getLabelAndValue(index) { + const me = this; + const meta = me._cachedMeta; + const chart = me.chart; + const labels = chart.data.labels || []; + return { + label: labels[index] || '', + value: meta._parsed[index], + }; + } + getMaxBorderWidth(arcs) { + const me = this; + let max = 0; + const chart = me.chart; + let i, ilen, meta, controller, options; + if (!arcs) { + for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { + if (chart.isDatasetVisible(i)) { + meta = chart.getDatasetMeta(i); + arcs = meta.data; + controller = meta.controller; + if (controller !== me) { + controller.configure(); + } + break; + } + } + } + if (!arcs) { + return 0; + } + for (i = 0, ilen = arcs.length; i < ilen; ++i) { + options = controller.resolveDataElementOptions(i); + if (options.borderAlign !== 'inner') { + max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); + } + } + return max; + } + getMaxOffset(arcs) { + let max = 0; + for (let i = 0, ilen = arcs.length; i < ilen; ++i) { + const options = this.resolveDataElementOptions(i); + max = Math.max(max, options.offset || 0, options.hoverOffset || 0); + } + return max; + } + _getRingWeightOffset(datasetIndex) { + let ringWeightOffset = 0; + for (let i = 0; i < datasetIndex; ++i) { + if (this.chart.isDatasetVisible(i)) { + ringWeightOffset += this._getRingWeight(i); + } + } + return ringWeightOffset; + } + _getRingWeight(datasetIndex) { + return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); + } + _getVisibleDatasetWeightTotal() { + return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; + } +} +DoughnutController.id = 'doughnut'; +DoughnutController.defaults = { + datasetElementType: false, + dataElementType: 'arc', + dataElementOptions: [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'borderAlign', + 'offset' + ], + animation: { + numbers: { + type: 'number', + properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth'] + }, + animateRotate: true, + animateScale: false + }, + aspectRatio: 1, + legend: { + labels: { + generateLabels(chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map((label, i) => { + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + cutoutPercentage: 50, + rotation: -HALF_PI, + circumference: DOUBLE_PI, + tooltips: { + callbacks: { + title() { + return ''; + }, + label(tooltipItem) { + let dataLabel = tooltipItem.label; + const value = ': ' + tooltipItem.formattedValue; + if (isArray(dataLabel)) { + dataLabel = dataLabel.slice(); + dataLabel[0] += value; + } else { + dataLabel += value; + } + return dataLabel; + } + } + } +}; + +class LineController extends DatasetController { + initialize() { + this.enableOptionSharing = true; + super.initialize(); + } + update(mode) { + const me = this; + const meta = me._cachedMeta; + const {dataset: line, data: points = []} = meta; + const animationsDisabled = me.chart._animationsDisabled; + let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled); + me._drawStart = start; + me._drawCount = count; + if (scaleRangesChanged(meta) && !animationsDisabled) { + start = 0; + count = points.length; + } + if (mode !== 'resize') { + const properties = { + points, + options: me.resolveDatasetElementOptions() + }; + me.updateElement(line, undefined, properties, mode); + } + me.updateElements(points, start, count, mode); + } + updateElements(points, start, count, mode) { + const me = this; + const reset = mode === 'reset'; + const {xScale, yScale, _stacked} = me._cachedMeta; + const firstOpts = me.resolveDataElementOptions(start, mode); + const sharedOptions = me.getSharedOptions(firstOpts); + const includeOptions = me.includeOptions(mode, sharedOptions); + const spanGaps = valueOrDefault(me._config.spanGaps, me.chart.options.spanGaps); + const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; + let prevParsed = start > 0 && me.getParsed(start - 1); + for (let i = start; i < start + count; ++i) { + const point = points[i]; + const parsed = me.getParsed(i); + const x = xScale.getPixelForValue(parsed.x, i); + const y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me.applyStack(yScale, parsed) : parsed.y, i); + const properties = { + x, + y, + skip: isNaN(x) || isNaN(y), + stop: i > 0 && (parsed.x - prevParsed.x) > maxGapLength + }; + if (includeOptions) { + properties.options = sharedOptions || me.resolveDataElementOptions(i, mode); + } + me.updateElement(point, i, properties, mode); + prevParsed = parsed; + } + me.updateSharedOptions(sharedOptions, mode, firstOpts); + } + resolveDatasetElementOptions(active) { + const me = this; + const config = me._config; + const options = me.chart.options; + const lineOptions = options.elements.line; + const values = super.resolveDatasetElementOptions(active); + const showLine = valueOrDefault(config.showLine, options.showLines); + values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps); + values.tension = valueOrDefault(config.lineTension, lineOptions.tension); + values.stepped = resolve([config.stepped, lineOptions.stepped]); + if (!showLine) { + values.borderWidth = 0; + } + return values; + } + getMaxOverflow() { + const me = this; + const meta = me._cachedMeta; + const border = meta.dataset.options.borderWidth || 0; + const data = meta.data || []; + if (!data.length) { + return border; + } + const firstPoint = data[0].size(); + const lastPoint = data[data.length - 1].size(); + return Math.max(border, firstPoint, lastPoint) / 2; + } + draw() { + this._cachedMeta.dataset.updateControlPoints(this.chart.chartArea); + super.draw(); + } +} +LineController.id = 'line'; +LineController.defaults = { + datasetElementType: 'line', + datasetElementOptions: [ + 'backgroundColor', + 'borderCapStyle', + 'borderColor', + 'borderDash', + 'borderDashOffset', + 'borderJoinStyle', + 'borderWidth', + 'capBezierPoints', + 'cubicInterpolationMode', + 'fill' + ], + dataElementType: 'point', + dataElementOptions: { + backgroundColor: 'pointBackgroundColor', + borderColor: 'pointBorderColor', + borderWidth: 'pointBorderWidth', + hitRadius: 'pointHitRadius', + hoverHitRadius: 'pointHitRadius', + hoverBackgroundColor: 'pointHoverBackgroundColor', + hoverBorderColor: 'pointHoverBorderColor', + hoverBorderWidth: 'pointHoverBorderWidth', + hoverRadius: 'pointHoverRadius', + pointStyle: 'pointStyle', + radius: 'pointRadius', + rotation: 'pointRotation' + }, + showLines: true, + spanGaps: false, + hover: { + mode: 'index' + }, + scales: { + _index_: { + type: 'category', + }, + _value_: { + type: 'linear', + }, + } +}; +function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { + const pointCount = points.length; + let start = 0; + let count = pointCount; + if (meta._sorted) { + const {iScale, _parsed} = meta; + const axis = iScale.axis; + const {min, max, minDefined, maxDefined} = iScale.getUserBounds(); + if (minDefined) { + start = _limitValue(Math.min( + _lookupByKey(_parsed, iScale.axis, min).lo, + animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), + 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(Math.max( + _lookupByKey(_parsed, iScale.axis, max).hi + 1, + animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), + start, pointCount) - start; + } else { + count = pointCount - start; + } + } + return {start, count}; +} +function scaleRangesChanged(meta) { + const {xScale, yScale, _scaleRanges} = meta; + const newRanges = { + xmin: xScale.min, + xmax: xScale.max, + ymin: yScale.min, + ymax: yScale.max + }; + if (!_scaleRanges) { + meta._scaleRanges = newRanges; + return true; + } + const changed = _scaleRanges.xmin !== xScale.min + || _scaleRanges.xmax !== xScale.max + || _scaleRanges.ymin !== yScale.min + || _scaleRanges.ymax !== yScale.max; + Object.assign(_scaleRanges, newRanges); + return changed; +} + +function getStartAngleRadians(deg) { + return toRadians(deg) - 0.5 * Math.PI; +} +class PolarAreaController extends DatasetController { + constructor(chart, datasetIndex) { + super(chart, datasetIndex); + this.innerRadius = undefined; + this.outerRadius = undefined; + } + update(mode) { + const arcs = this._cachedMeta.data; + this._updateRadius(); + this.updateElements(arcs, 0, arcs.length, mode); + } + _updateRadius() { + const me = this; + const chart = me.chart; + const chartArea = chart.chartArea; + const opts = chart.options; + const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + const outerRadius = Math.max(minSize / 2, 0); + const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0); + const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); + me.outerRadius = outerRadius - (radiusLength * me.index); + me.innerRadius = me.outerRadius - radiusLength; + } + updateElements(arcs, start, count, mode) { + const me = this; + const reset = mode === 'reset'; + const chart = me.chart; + const dataset = me.getDataset(); + const opts = chart.options; + const animationOpts = opts.animation; + const scale = me._cachedMeta.rScale; + const centerX = scale.xCenter; + const centerY = scale.yCenter; + const datasetStartAngle = getStartAngleRadians(opts.startAngle); + let angle = datasetStartAngle; + let i; + me._cachedMeta.count = me.countVisibleElements(); + for (i = 0; i < start; ++i) { + angle += me._computeAngle(i); + } + for (i = start; i < start + count; i++) { + const arc = arcs[i]; + let startAngle = angle; + let endAngle = angle + me._computeAngle(i); + let outerRadius = this.chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; + angle = endAngle; + if (reset) { + if (animationOpts.animateScale) { + outerRadius = 0; + } + if (animationOpts.animateRotate) { + startAngle = datasetStartAngle; + endAngle = datasetStartAngle; + } + } + const properties = { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius, + startAngle, + endAngle, + options: me.resolveDataElementOptions(i, mode) + }; + me.updateElement(arc, i, properties, mode); + } + } + countVisibleElements() { + const dataset = this.getDataset(); + const meta = this._cachedMeta; + let count = 0; + meta.data.forEach((element, index) => { + if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) { + count++; + } + }); + return count; + } + _computeAngle(index) { + const me = this; + const meta = me._cachedMeta; + const count = meta.count; + const dataset = me.getDataset(); + if (isNaN(dataset.data[index]) || !this.chart.getDataVisibility(index)) { + return 0; + } + const context = { + chart: me.chart, + dataPoint: this.getParsed(index), + dataIndex: index, + dataset, + datasetIndex: me.index + }; + return resolve([ + me.chart.options.elements.arc.angle, + (2 * Math.PI) / count + ], context, index); + } +} +PolarAreaController.id = 'polarArea'; +PolarAreaController.defaults = { + dataElementType: 'arc', + dataElementOptions: [ + 'backgroundColor', + 'borderColor', + 'borderWidth', + 'borderAlign', + 'offset' + ], + animation: { + numbers: { + type: 'number', + properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] + }, + animateRotate: true, + animateScale: true + }, + aspectRatio: 1, + datasets: { + indexAxis: 'r' + }, + scales: { + r: { + type: 'radialLinear', + angleLines: { + display: false + }, + beginAtZero: true, + gridLines: { + circular: true + }, + pointLabels: { + display: false + } + } + }, + startAngle: 0, + legend: { + labels: { + generateLabels(chart) { + const data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map((label, i) => { + const meta = chart.getDatasetMeta(0); + const style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + tooltips: { + callbacks: { + title() { + return ''; + }, + label(context) { + return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; + } + } + } +}; + +class PieController extends DoughnutController { +} +PieController.id = 'pie'; +PieController.defaults = { + cutoutPercentage: 0 +}; + +class RadarController extends DatasetController { + getLabelAndValue(index) { + const me = this; + const vScale = me._cachedMeta.vScale; + const parsed = me.getParsed(index); + return { + label: vScale.getLabels()[index], + value: '' + vScale.getLabelForValue(parsed[vScale.axis]) + }; + } + update(mode) { + const me = this; + const meta = me._cachedMeta; + const line = meta.dataset; + const points = meta.data || []; + const labels = meta.iScale.getLabels(); + if (mode !== 'resize') { + const properties = { + points, + _loop: true, + _fullLoop: labels.length === points.length, + options: me.resolveDatasetElementOptions() + }; + me.updateElement(line, undefined, properties, mode); + } + me.updateElements(points, 0, points.length, mode); + } + updateElements(points, start, count, mode) { + const me = this; + const dataset = me.getDataset(); + const scale = me._cachedMeta.rScale; + const reset = mode === 'reset'; + for (let i = start; i < start + count; i++) { + const point = points[i]; + const options = me.resolveDataElementOptions(i, mode); + const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); + const x = reset ? scale.xCenter : pointPosition.x; + const y = reset ? scale.yCenter : pointPosition.y; + const properties = { + x, + y, + angle: pointPosition.angle, + skip: isNaN(x) || isNaN(y), + options + }; + me.updateElement(point, i, properties, mode); + } + } + resolveDatasetElementOptions(active) { + const me = this; + const config = me._config; + const options = me.chart.options; + const values = super.resolveDatasetElementOptions(active); + const showLine = valueOrDefault(config.showLine, options.showLines); + values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps); + values.tension = valueOrDefault(config.lineTension, options.elements.line.tension); + if (!showLine) { + values.borderWidth = 0; + } + return values; + } +} +RadarController.id = 'radar'; +RadarController.defaults = { + datasetElementType: 'line', + datasetElementOptions: [ + 'backgroundColor', + 'borderColor', + 'borderCapStyle', + 'borderDash', + 'borderDashOffset', + 'borderJoinStyle', + 'borderWidth', + 'fill' + ], + dataElementType: 'point', + dataElementOptions: { + backgroundColor: 'pointBackgroundColor', + borderColor: 'pointBorderColor', + borderWidth: 'pointBorderWidth', + hitRadius: 'pointHitRadius', + hoverBackgroundColor: 'pointHoverBackgroundColor', + hoverBorderColor: 'pointHoverBorderColor', + hoverBorderWidth: 'pointHoverBorderWidth', + hoverRadius: 'pointHoverRadius', + pointStyle: 'pointStyle', + radius: 'pointRadius', + rotation: 'pointRotation' + }, + aspectRatio: 1, + spanGaps: false, + scales: { + r: { + type: 'radialLinear', + } + }, + datasets: { + indexAxis: 'r' + }, + elements: { + line: { + fill: 'start', + tension: 0 + } + } +}; + +class ScatterController extends LineController { +} +ScatterController.id = 'scatter'; +ScatterController.defaults = { + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + }, + datasets: { + showLine: false, + fill: false + }, + tooltips: { + callbacks: { + title() { + return ''; + }, + label(item) { + return '(' + item.label + ', ' + item.formattedValue + ')'; + } + } + } +}; + +function abstract() { + throw new Error('This method is not implemented: either no adapter can be found or an incomplete integration was provided.'); +} +class DateAdapter { + constructor(options) { + this.options = options || {}; + } + formats() { + return abstract(); + } + parse(value, format) { + return abstract(); + } + format(timestamp, format) { + return abstract(); + } + add(timestamp, amount, unit) { + return abstract(); + } + diff(a, b, unit) { + return abstract(); + } + startOf(timestamp, unit, weekday) { + return abstract(); + } + endOf(timestamp, unit) { + return abstract(); + } +} +DateAdapter.override = function(members) { + Object.assign(DateAdapter.prototype, members); +}; +var adapters = { + _date: DateAdapter +}; + +function getRelativePosition(e, chart) { + if ('native' in e) { + return { + x: e.x, + y: e.y + }; + } + return getRelativePosition$1(e, chart); +} +function evaluateAllVisibleItems(chart, handler) { + const metasets = chart.getSortedVisibleDatasetMetas(); + let index, data, element; + for (let i = 0, ilen = metasets.length; i < ilen; ++i) { + ({index, data} = metasets[i]); + for (let j = 0, jlen = data.length; j < jlen; ++j) { + element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function binarySearch(metaset, axis, value, intersect) { + const {controller, data, _sorted} = metaset; + const iScale = controller._cachedMeta.iScale; + if (iScale && axis === iScale.axis && _sorted && data.length) { + const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; + if (!intersect) { + return lookupMethod(data, axis, value); + } else if (controller._sharedOptions) { + const el = data[0]; + const range = typeof el.getRange === 'function' && el.getRange(axis); + if (range) { + const start = lookupMethod(data, axis, value - range); + const end = lookupMethod(data, axis, value + range); + return {lo: start.lo, hi: end.hi}; + } + } + } + return {lo: 0, hi: data.length - 1}; +} +function optimizedEvaluateItems(chart, axis, position, handler, intersect) { + const metasets = chart.getSortedVisibleDatasetMetas(); + const value = position[axis]; + for (let i = 0, ilen = metasets.length; i < ilen; ++i) { + const {index, data} = metasets[i]; + const {lo, hi} = binarySearch(metasets[i], axis, value, intersect); + for (let j = lo; j <= hi; ++j) { + const element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function getDistanceMetricForAxis(axis) { + const useX = axis.indexOf('x') !== -1; + const useY = axis.indexOf('y') !== -1; + return function(pt1, pt2) { + const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; + const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; + return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); + }; +} +function getIntersectItems(chart, position, axis, useFinalPosition) { + const items = []; + if (!_isPointInArea(position, chart.chartArea)) { + return items; + } + const evaluationFunc = function(element, datasetIndex, index) { + if (element.inRange(position.x, position.y, useFinalPosition)) { + items.push({element, datasetIndex, index}); + } + }; + optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); + return items; +} +function getNearestItems(chart, position, axis, intersect, useFinalPosition) { + const distanceMetric = getDistanceMetricForAxis(axis); + let minDistance = Number.POSITIVE_INFINITY; + let items = []; + if (!_isPointInArea(position, chart.chartArea)) { + return items; + } + const evaluationFunc = function(element, datasetIndex, index) { + if (intersect && !element.inRange(position.x, position.y, useFinalPosition)) { + return; + } + const center = element.getCenterPoint(useFinalPosition); + const distance = distanceMetric(position, center); + if (distance < minDistance) { + items = [{element, datasetIndex, index}]; + minDistance = distance; + } else if (distance === minDistance) { + items.push({element, datasetIndex, index}); + } + }; + optimizedEvaluateItems(chart, axis, position, evaluationFunc); + return items; +} +function getAxisItems(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const items = []; + const axis = options.axis; + const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; + let intersectsItem = false; + evaluateAllVisibleItems(chart, (element, datasetIndex, index) => { + if (element[rangeMethod](position[axis], useFinalPosition)) { + items.push({element, datasetIndex, index}); + } + if (element.inRange(position.x, position.y, useFinalPosition)) { + intersectsItem = true; + } + }); + if (options.intersect && !intersectsItem) { + return []; + } + return items; +} +var Interaction = { + modes: { + index(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'x'; + const items = options.intersect + ? getIntersectItems(chart, position, axis, useFinalPosition) + : getNearestItems(chart, position, axis, false, useFinalPosition); + const elements = []; + if (!items.length) { + return []; + } + chart.getSortedVisibleDatasetMetas().forEach((meta) => { + const index = items[0].index; + const element = meta.data[index]; + if (element && !element.skip) { + elements.push({element, datasetIndex: meta.index, index}); + } + }); + return elements; + }, + dataset(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + let items = options.intersect + ? getIntersectItems(chart, position, axis, useFinalPosition) : + getNearestItems(chart, position, axis, false, useFinalPosition); + if (items.length > 0) { + const datasetIndex = items[0].datasetIndex; + const data = chart.getDatasetMeta(datasetIndex).data; + items = []; + for (let i = 0; i < data.length; ++i) { + items.push({element: data[i], datasetIndex, index: i}); + } + } + return items; + }, + point(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + return getIntersectItems(chart, position, axis, useFinalPosition); + }, + nearest(chart, e, options, useFinalPosition) { + const position = getRelativePosition(e, chart); + const axis = options.axis || 'xy'; + return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); + }, + x(chart, e, options, useFinalPosition) { + options.axis = 'x'; + return getAxisItems(chart, e, options, useFinalPosition); + }, + y(chart, e, options, useFinalPosition) { + options.axis = 'y'; + return getAxisItems(chart, e, options, useFinalPosition); + } + } +}; + +const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; +function filterByPosition(array, position) { + return array.filter(v => v.pos === position); +} +function filterDynamicPositionByAxis(array, axis) { + return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis); +} +function sortByWeight(array, reverse) { + return array.sort((a, b) => { + const v0 = reverse ? b : a; + const v1 = reverse ? a : b; + return v0.weight === v1.weight ? + v0.index - v1.index : + v0.weight - v1.weight; + }); +} +function wrapBoxes(boxes) { + const layoutBoxes = []; + let i, ilen, box; + for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { + box = boxes[i]; + layoutBoxes.push({ + index: i, + box, + pos: box.position, + horizontal: box.isHorizontal(), + weight: box.weight + }); + } + return layoutBoxes; +} +function setLayoutDims(layouts, params) { + let i, ilen, layout; + for (i = 0, ilen = layouts.length; i < ilen; ++i) { + layout = layouts[i]; + layout.width = layout.horizontal + ? layout.box.fullWidth && params.availableWidth + : params.vBoxMaxWidth; + layout.height = layout.horizontal && params.hBoxMaxHeight; + } +} +function buildLayoutBoxes(boxes) { + const layoutBoxes = wrapBoxes(boxes); + const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); + const right = sortByWeight(filterByPosition(layoutBoxes, 'right')); + const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); + const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); + const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); + const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); + return { + leftAndTop: left.concat(top), + rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), + chartArea: filterByPosition(layoutBoxes, 'chartArea'), + vertical: left.concat(right).concat(centerVertical), + horizontal: top.concat(bottom).concat(centerHorizontal) + }; +} +function getCombinedMax(maxPadding, chartArea, a, b) { + return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); +} +function updateDims(chartArea, params, layout) { + const box = layout.box; + const maxPadding = chartArea.maxPadding; + if (layout.size) { + chartArea[layout.pos] -= layout.size; + } + layout.size = layout.horizontal ? box.height : box.width; + chartArea[layout.pos] += layout.size; + if (box.getPadding) { + const boxPadding = box.getPadding(); + maxPadding.top = Math.max(maxPadding.top, boxPadding.top); + maxPadding.left = Math.max(maxPadding.left, boxPadding.left); + maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); + maxPadding.right = Math.max(maxPadding.right, boxPadding.right); + } + const newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'); + const newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'); + if (newWidth !== chartArea.w || newHeight !== chartArea.h) { + chartArea.w = newWidth; + chartArea.h = newHeight; + return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h; + } +} +function handleMaxPadding(chartArea) { + const maxPadding = chartArea.maxPadding; + function updatePos(pos) { + const change = Math.max(maxPadding[pos] - chartArea[pos], 0); + chartArea[pos] += change; + return change; + } + chartArea.y += updatePos('top'); + chartArea.x += updatePos('left'); + updatePos('right'); + updatePos('bottom'); +} +function getMargins(horizontal, chartArea) { + const maxPadding = chartArea.maxPadding; + function marginForPositions(positions) { + const margin = {left: 0, top: 0, right: 0, bottom: 0}; + positions.forEach((pos) => { + margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); + }); + return margin; + } + return horizontal + ? marginForPositions(['left', 'right']) + : marginForPositions(['top', 'bottom']); +} +function fitBoxes(boxes, chartArea, params) { + const refitBoxes = []; + let i, ilen, layout, box, refit, changed; + for (i = 0, ilen = boxes.length; i < ilen; ++i) { + layout = boxes[i]; + box = layout.box; + box.update( + layout.width || chartArea.w, + layout.height || chartArea.h, + getMargins(layout.horizontal, chartArea) + ); + if (updateDims(chartArea, params, layout)) { + changed = true; + if (refitBoxes.length) { + refit = true; + } + } + if (!box.fullWidth) { + refitBoxes.push(layout); + } + } + return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed; +} +function placeBoxes(boxes, chartArea, params) { + const userPadding = params.padding; + let x = chartArea.x; + let y = chartArea.y; + let i, ilen, layout, box; + for (i = 0, ilen = boxes.length; i < ilen; ++i) { + layout = boxes[i]; + box = layout.box; + if (layout.horizontal) { + box.left = box.fullWidth ? userPadding.left : chartArea.left; + box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w; + box.top = y; + box.bottom = y + box.height; + box.width = box.right - box.left; + y = box.bottom; + } else { + box.left = x; + box.right = x + box.width; + box.top = chartArea.top; + box.bottom = chartArea.top + chartArea.h; + box.height = box.bottom - box.top; + x = box.right; + } + } + chartArea.x = x; + chartArea.y = y; +} +defaults.set('layout', { + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } +}); +var layouts = { + addBox(chart, item) { + if (!chart.boxes) { + chart.boxes = []; + } + item.fullWidth = item.fullWidth || false; + item.position = item.position || 'top'; + item.weight = item.weight || 0; + item._layers = item._layers || function() { + return [{ + z: 0, + draw(chartArea) { + item.draw(chartArea); + } + }]; + }; + chart.boxes.push(item); + }, + removeBox(chart, layoutItem) { + const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; + if (index !== -1) { + chart.boxes.splice(index, 1); + } + }, + configure(chart, item, options) { + const props = ['fullWidth', 'position', 'weight']; + const ilen = props.length; + let i = 0; + let prop; + for (; i < ilen; ++i) { + prop = props[i]; + if (Object.prototype.hasOwnProperty.call(options, prop)) { + item[prop] = options[prop]; + } + } + }, + update(chart, width, height) { + if (!chart) { + return; + } + const layoutOptions = chart.options.layout || {}; + const padding = toPadding(layoutOptions.padding); + const availableWidth = width - padding.width; + const availableHeight = height - padding.height; + const boxes = buildLayoutBoxes(chart.boxes); + const verticalBoxes = boxes.vertical; + const horizontalBoxes = boxes.horizontal; + const params = Object.freeze({ + outerWidth: width, + outerHeight: height, + padding, + availableWidth, + vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length, + hBoxMaxHeight: availableHeight / 2 + }); + const chartArea = Object.assign({ + maxPadding: Object.assign({}, padding), + w: availableWidth, + h: availableHeight, + x: padding.left, + y: padding.top + }, padding); + setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); + fitBoxes(verticalBoxes, chartArea, params); + if (fitBoxes(horizontalBoxes, chartArea, params)) { + fitBoxes(verticalBoxes, chartArea, params); + } + handleMaxPadding(chartArea); + placeBoxes(boxes.leftAndTop, chartArea, params); + chartArea.x += chartArea.w; + chartArea.y += chartArea.h; + placeBoxes(boxes.rightAndBottom, chartArea, params); + chart.chartArea = { + left: chartArea.left, + top: chartArea.top, + right: chartArea.left + chartArea.w, + bottom: chartArea.top + chartArea.h, + height: chartArea.h, + width: chartArea.w, + }; + each(boxes.chartArea, (layout) => { + const box = layout.box; + Object.assign(box, chart.chartArea); + box.update(chartArea.w, chartArea.h); + }); + } +}; + +class BasePlatform { + acquireContext(canvas, options) {} + releaseContext(context) { + return false; + } + addEventListener(chart, type, listener) {} + removeEventListener(chart, type, listener) {} + getDevicePixelRatio() { + return 1; + } + getMaximumSize(element, width, height, aspectRatio) { + width = Math.max(0, width || element.width); + height = height || element.height; + return { + width, + height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) + }; + } + isAttached(canvas) { + return true; + } +} + +class BasicPlatform extends BasePlatform { + acquireContext(item) { + return item && item.getContext && item.getContext('2d') || null; + } +} + +const EXPANDO_KEY = '$chartjs'; +const EVENT_TYPES = { + touchstart: 'mousedown', + touchmove: 'mousemove', + touchend: 'mouseup', + pointerenter: 'mouseenter', + pointerdown: 'mousedown', + pointermove: 'mousemove', + pointerup: 'mouseup', + pointerleave: 'mouseout', + pointerout: 'mouseout' +}; +const isNullOrEmpty = value => value === null || value === ''; +function initCanvas(canvas, config) { + const style = canvas.style; + const renderHeight = canvas.getAttribute('height'); + const renderWidth = canvas.getAttribute('width'); + canvas[EXPANDO_KEY] = { + initial: { + height: renderHeight, + width: renderWidth, + style: { + display: style.display, + height: style.height, + width: style.width + } + } + }; + style.display = style.display || 'block'; + style.boxSizing = style.boxSizing || 'border-box'; + if (isNullOrEmpty(renderWidth)) { + const displayWidth = readUsedSize(canvas, 'width'); + if (displayWidth !== undefined) { + canvas.width = displayWidth; + } + } + if (isNullOrEmpty(renderHeight)) { + if (canvas.style.height === '') { + canvas.height = canvas.width / (config.options.aspectRatio || 2); + } else { + const displayHeight = readUsedSize(canvas, 'height'); + if (displayHeight !== undefined) { + canvas.height = displayHeight; + } + } + } + return canvas; +} +const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false; +function addListener(node, type, listener) { + node.addEventListener(type, listener, eventListenerOptions); +} +function removeListener(chart, type, listener) { + chart.canvas.removeEventListener(type, listener, eventListenerOptions); +} +function fromNativeEvent(event, chart) { + const type = EVENT_TYPES[event.type] || event.type; + const {x, y} = getRelativePosition$1(event, chart); + return { + type, + chart, + native: event, + x: x !== undefined ? x : null, + y: y !== undefined ? y : null, + }; +} +function createAttachObserver(chart, type, listener) { + const canvas = chart.canvas; + const container = canvas && _getParentNode(canvas); + const element = container || canvas; + const observer = new MutationObserver(entries => { + const parent = _getParentNode(element); + entries.forEach(entry => { + for (let i = 0; i < entry.addedNodes.length; i++) { + const added = entry.addedNodes[i]; + if (added === element || added === parent) { + listener(entry.target); + } + } + }); + }); + observer.observe(document, {childList: true, subtree: true}); + return observer; +} +function createDetachObserver(chart, type, listener) { + const canvas = chart.canvas; + const container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + const observer = new MutationObserver(entries => { + entries.forEach(entry => { + for (let i = 0; i < entry.removedNodes.length; i++) { + if (entry.removedNodes[i] === canvas) { + listener(); + break; + } + } + }); + }); + observer.observe(container, {childList: true}); + return observer; +} +const drpListeningCharts = new Map(); +let oldDevicePixelRatio = 0; +function onWindowResize() { + const dpr = window.devicePixelRatio; + if (dpr === oldDevicePixelRatio) { + return; + } + oldDevicePixelRatio = dpr; + drpListeningCharts.forEach((resize, chart) => { + if (chart.currentDevicePixelRatio !== dpr) { + resize(); + } + }); +} +function listenDevicePixelRatioChanges(chart, resize) { + if (!drpListeningCharts.size) { + window.addEventListener('resize', onWindowResize); + } + drpListeningCharts.set(chart, resize); +} +function unlistenDevicePixelRatioChanges(chart) { + drpListeningCharts.delete(chart); + if (!drpListeningCharts.size) { + window.removeEventListener('resize', onWindowResize); + } +} +function createResizeObserver(chart, type, listener) { + const canvas = chart.canvas; + const container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + const resize = throttled((width, height) => { + const w = container.clientWidth; + listener(width, height); + if (w < container.clientWidth) { + listener(); + } + }, window); + const observer = new ResizeObserver(entries => { + const entry = entries[0]; + const width = entry.contentRect.width; + const height = entry.contentRect.height; + if (width === 0 && height === 0) { + return; + } + resize(width, height); + }); + observer.observe(container); + listenDevicePixelRatioChanges(chart, resize); + return observer; +} +function releaseObserver(chart, type, observer) { + if (observer) { + observer.disconnect(); + } + if (type === 'resize') { + unlistenDevicePixelRatioChanges(chart); + } +} +function createProxyAndListen(chart, type, listener) { + const canvas = chart.canvas; + const proxy = throttled((event) => { + if (chart.ctx !== null) { + listener(fromNativeEvent(event, chart)); + } + }, chart, (args) => { + const event = args[0]; + return [event, event.offsetX, event.offsetY]; + }); + addListener(canvas, type, proxy); + return proxy; +} +class DomPlatform extends BasePlatform { + acquireContext(canvas, config) { + const context = canvas && canvas.getContext && canvas.getContext('2d'); + if (context && context.canvas === canvas) { + initCanvas(canvas, config); + return context; + } + return null; + } + releaseContext(context) { + const canvas = context.canvas; + if (!canvas[EXPANDO_KEY]) { + return false; + } + const initial = canvas[EXPANDO_KEY].initial; + ['height', 'width'].forEach((prop) => { + const value = initial[prop]; + if (isNullOrUndef(value)) { + canvas.removeAttribute(prop); + } else { + canvas.setAttribute(prop, value); + } + }); + const style = initial.style || {}; + Object.keys(style).forEach((key) => { + canvas.style[key] = style[key]; + }); + canvas.width = canvas.width; + delete canvas[EXPANDO_KEY]; + return true; + } + addEventListener(chart, type, listener) { + this.removeEventListener(chart, type); + const proxies = chart.$proxies || (chart.$proxies = {}); + const handlers = { + attach: createAttachObserver, + detach: createDetachObserver, + resize: createResizeObserver + }; + const handler = handlers[type] || createProxyAndListen; + proxies[type] = handler(chart, type, listener); + } + removeEventListener(chart, type) { + const proxies = chart.$proxies || (chart.$proxies = {}); + const proxy = proxies[type]; + if (!proxy) { + return; + } + const handlers = { + attach: releaseObserver, + detach: releaseObserver, + resize: releaseObserver + }; + const handler = handlers[type] || removeListener; + handler(chart, type, proxy); + proxies[type] = undefined; + } + getDevicePixelRatio() { + return window.devicePixelRatio; + } + getMaximumSize(canvas, width, height, aspectRatio) { + return getMaximumSize(canvas, width, height, aspectRatio); + } + isAttached(canvas) { + const container = _getParentNode(canvas); + return !!(container && _getParentNode(container)); + } +} + +class Element { + constructor() { + this.x = undefined; + this.y = undefined; + this.active = false; + this.options = undefined; + this.$animations = undefined; + } + tooltipPosition(useFinalPosition) { + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return {x, y}; + } + hasValue() { + return isNumber(this.x) && isNumber(this.y); + } + getProps(props, final) { + const me = this; + const anims = this.$animations; + if (!final || !anims) { + return me; + } + const ret = {}; + props.forEach(prop => { + ret[prop] = anims[prop] && anims[prop].active ? anims[prop]._to : me[prop]; + }); + return ret; + } +} +Element.defaults = {}; +Element.defaultRoutes = undefined; + +const intlCache = new Map(); +const formatters = { + values(value) { + return isArray(value) ? value : '' + value; + }, + numeric(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + const locale = this.chart.options.locale; + const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); + let notation; + if (maxTick < 1e-4 || maxTick > 1e+15) { + notation = 'scientific'; + } + let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; + if (Math.abs(delta) > 1 && tickValue !== Math.floor(tickValue)) { + delta = tickValue - Math.floor(tickValue); + } + const logDelta = log10(Math.abs(delta)); + const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); + const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal}; + Object.assign(options, this.options.ticks.format); + const cacheKey = locale + JSON.stringify(options); + let formatter = intlCache.get(cacheKey); + if (!formatter) { + formatter = new Intl.NumberFormat(locale, options); + intlCache.set(cacheKey, formatter); + } + return formatter.format(tickValue); + } +}; +formatters.logarithmic = function(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue)))); + if (remain === 1 || remain === 2 || remain === 5) { + return formatters.numeric.call(this, tickValue, index, ticks); + } + return ''; +}; +var Ticks = {formatters}; + +defaults.set('scale', { + display: true, + offset: false, + reverse: false, + beginAtZero: false, + gridLines: { + display: true, + color: 'rgba(0,0,0,0.1)', + lineWidth: 1, + drawBorder: true, + drawOnChartArea: true, + drawTicks: true, + tickMarkLength: 10, + offsetGridLines: false, + borderDash: [], + borderDashOffset: 0.0 + }, + scaleLabel: { + display: false, + labelString: '', + padding: { + top: 4, + bottom: 4 + } + }, + ticks: { + minRotation: 0, + maxRotation: 50, + mirror: false, + lineWidth: 0, + strokeStyle: '', + padding: 0, + display: true, + autoSkip: true, + autoSkipPadding: 0, + labelOffset: 0, + callback: Ticks.formatters.values, + minor: {}, + major: {} + } +}); +function sample(arr, numItems) { + const result = []; + const increment = arr.length / numItems; + const len = arr.length; + let i = 0; + for (; i < len; i += increment) { + result.push(arr[Math.floor(i)]); + } + return result; +} +function getPixelForGridLine(scale, index, offsetGridLines) { + const length = scale.ticks.length; + const validIndex = Math.min(index, length - 1); + const start = scale._startPixel; + const end = scale._endPixel; + const epsilon = 1e-6; + let lineValue = scale.getPixelForTick(validIndex); + let offset; + if (offsetGridLines) { + if (length === 1) { + offset = Math.max(lineValue - start, end - lineValue); + } else if (index === 0) { + offset = (scale.getPixelForTick(1) - lineValue) / 2; + } else { + offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; + } + lineValue += validIndex < index ? offset : -offset; + if (lineValue < start - epsilon || lineValue > end + epsilon) { + return; + } + } + return lineValue; +} +function garbageCollect(caches, length) { + each(caches, (cache) => { + const gc = cache.gc; + const gcLen = gc.length / 2; + let i; + if (gcLen > length) { + for (i = 0; i < gcLen; ++i) { + delete cache.data[gc[i]]; + } + gc.splice(0, gcLen); + } + }); +} +function getTickMarkLength(options) { + return options.drawTicks ? options.tickMarkLength : 0; +} +function getScaleLabelHeight(options, fallback) { + if (!options.display) { + return 0; + } + const font = toFont(options.font, fallback); + const padding = toPadding(options.padding); + return font.lineHeight + padding.height; +} +function getEvenSpacing(arr) { + const len = arr.length; + let i, diff; + if (len < 2) { + return false; + } + for (diff = arr[0], i = 1; i < len; ++i) { + if (arr[i] - arr[i - 1] !== diff) { + return false; + } + } + return diff; +} +function calculateSpacing(majorIndices, ticks, ticksLimit) { + const evenMajorSpacing = getEvenSpacing(majorIndices); + const spacing = ticks.length / ticksLimit; + if (!evenMajorSpacing) { + return Math.max(spacing, 1); + } + const factors = _factorize(evenMajorSpacing); + for (let i = 0, ilen = factors.length - 1; i < ilen; i++) { + const factor = factors[i]; + if (factor > spacing) { + return factor; + } + } + return Math.max(spacing, 1); +} +function getMajorIndices(ticks) { + const result = []; + let i, ilen; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + if (ticks[i].major) { + result.push(i); + } + } + return result; +} +function skipMajors(ticks, newTicks, majorIndices, spacing) { + let count = 0; + let next = majorIndices[0]; + let i; + spacing = Math.ceil(spacing); + for (i = 0; i < ticks.length; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = majorIndices[count * spacing]; + } + } +} +function skip(ticks, newTicks, spacing, majorStart, majorEnd) { + const start = valueOrDefault(majorStart, 0); + const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); + let count = 0; + let length, i, next; + spacing = Math.ceil(spacing); + if (majorEnd) { + length = majorEnd - majorStart; + spacing = length / Math.floor(length / spacing); + } + next = start; + while (next < 0) { + count++; + next = Math.round(start + count * spacing); + } + for (i = Math.max(start, 0); i < end; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = Math.round(start + count * spacing); + } + } +} +class Scale extends Element { + constructor(cfg) { + super(); + this.id = cfg.id; + this.type = cfg.type; + this.options = undefined; + this.ctx = cfg.ctx; + this.chart = cfg.chart; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this._margins = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + this.maxWidth = undefined; + this.maxHeight = undefined; + this.paddingTop = undefined; + this.paddingBottom = undefined; + this.paddingLeft = undefined; + this.paddingRight = undefined; + this.axis = undefined; + this.labelRotation = undefined; + this.min = undefined; + this.max = undefined; + this.ticks = []; + this._gridLineItems = null; + this._labelItems = null; + this._labelSizes = null; + this._length = 0; + this._longestTextCache = {}; + this._startPixel = undefined; + this._endPixel = undefined; + this._reversePixels = false; + this._userMax = undefined; + this._userMin = undefined; + this._ticksLength = 0; + this._borderValue = 0; + } + init(options) { + const me = this; + me.options = options; + me.axis = me.isHorizontal() ? 'x' : 'y'; + me._userMin = me.parse(options.min); + me._userMax = me.parse(options.max); + } + parse(raw, index) { + return raw; + } + getUserBounds() { + let min = this._userMin; + let max = this._userMax; + if (isNullOrUndef(min) || isNaN(min)) { + min = Number.POSITIVE_INFINITY; + } + if (isNullOrUndef(max) || isNaN(max)) { + max = Number.NEGATIVE_INFINITY; + } + return {min, max, minDefined: isNumberFinite(min), maxDefined: isNumberFinite(max)}; + } + getMinMax(canStack) { + const me = this; + let {min, max, minDefined, maxDefined} = me.getUserBounds(); + let range; + if (minDefined && maxDefined) { + return {min, max}; + } + const metas = me.getMatchingVisibleMetas(); + for (let i = 0, ilen = metas.length; i < ilen; ++i) { + range = metas[i].controller.getMinMax(me, canStack); + if (!minDefined) { + min = Math.min(min, range.min); + } + if (!maxDefined) { + max = Math.max(max, range.max); + } + } + return {min, max}; + } + invalidateCaches() {} + getPadding() { + const me = this; + return { + left: me.paddingLeft || 0, + top: me.paddingTop || 0, + right: me.paddingRight || 0, + bottom: me.paddingBottom || 0 + }; + } + getTicks() { + return this.ticks; + } + getLabels() { + const data = this.chart.data; + return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; + } + beforeUpdate() { + callback(this.options.beforeUpdate, [this]); + } + update(maxWidth, maxHeight, margins) { + const me = this; + const tickOpts = me.options.ticks; + const sampleSize = tickOpts.sampleSize; + me.beforeUpdate(); + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me._margins = Object.assign({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + me.ticks = null; + me._labelSizes = null; + me._gridLineItems = null; + me._labelItems = null; + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + me.beforeDataLimits(); + me.determineDataLimits(); + me.afterDataLimits(); + me.beforeBuildTicks(); + me.ticks = me.buildTicks() || []; + me.afterBuildTicks(); + const samplingEnabled = sampleSize < me.ticks.length; + me._convertTicksToLabels(samplingEnabled ? sample(me.ticks, sampleSize) : me.ticks); + me.configure(); + me.beforeCalculateLabelRotation(); + me.calculateLabelRotation(); + me.afterCalculateLabelRotation(); + me.beforeFit(); + me.fit(); + me.afterFit(); + me.ticks = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(me.ticks) : me.ticks; + if (samplingEnabled) { + me._convertTicksToLabels(me.ticks); + } + me.afterUpdate(); + } + configure() { + const me = this; + let reversePixels = me.options.reverse; + let startPixel, endPixel; + if (me.isHorizontal()) { + startPixel = me.left; + endPixel = me.right; + } else { + startPixel = me.top; + endPixel = me.bottom; + reversePixels = !reversePixels; + } + me._startPixel = startPixel; + me._endPixel = endPixel; + me._reversePixels = reversePixels; + me._length = endPixel - startPixel; + } + afterUpdate() { + callback(this.options.afterUpdate, [this]); + } + beforeSetDimensions() { + callback(this.options.beforeSetDimensions, [this]); + } + setDimensions() { + const me = this; + if (me.isHorizontal()) { + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + me.top = 0; + me.bottom = me.height; + } + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + } + afterSetDimensions() { + callback(this.options.afterSetDimensions, [this]); + } + beforeDataLimits() { + callback(this.options.beforeDataLimits, [this]); + } + determineDataLimits() {} + afterDataLimits() { + callback(this.options.afterDataLimits, [this]); + } + beforeBuildTicks() { + callback(this.options.beforeBuildTicks, [this]); + } + buildTicks() { + return []; + } + afterBuildTicks() { + callback(this.options.afterBuildTicks, [this]); + } + beforeTickToLabelConversion() { + callback(this.options.beforeTickToLabelConversion, [this]); + } + generateTickLabels(ticks) { + const me = this; + const tickOpts = me.options.ticks; + let i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + tick = ticks[i]; + tick.label = callback(tickOpts.callback, [tick.value, i, ticks], me); + } + } + afterTickToLabelConversion() { + callback(this.options.afterTickToLabelConversion, [this]); + } + beforeCalculateLabelRotation() { + callback(this.options.beforeCalculateLabelRotation, [this]); + } + calculateLabelRotation() { + const me = this; + const options = me.options; + const tickOpts = options.ticks; + const numTicks = me.ticks.length; + const minRotation = tickOpts.minRotation || 0; + const maxRotation = tickOpts.maxRotation; + let labelRotation = minRotation; + let tickWidth, maxHeight, maxLabelDiagonal; + if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) { + me.labelRotation = minRotation; + return; + } + const labelSizes = me._getLabelSizes(); + const maxLabelWidth = labelSizes.widest.width; + const maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset; + const maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth); + tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1); + if (maxLabelWidth + 6 > tickWidth) { + tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); + maxHeight = me.maxHeight - getTickMarkLength(options.gridLines) + - tickOpts.padding - getScaleLabelHeight(options.scaleLabel, me.chart.options.font); + maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); + labelRotation = toDegrees(Math.min( + Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)), + Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal) + )); + labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); + } + me.labelRotation = labelRotation; + } + afterCalculateLabelRotation() { + callback(this.options.afterCalculateLabelRotation, [this]); + } + beforeFit() { + callback(this.options.beforeFit, [this]); + } + fit() { + const me = this; + const minSize = { + width: 0, + height: 0 + }; + const chart = me.chart; + const opts = me.options; + const tickOpts = opts.ticks; + const scaleLabelOpts = opts.scaleLabel; + const gridLineOpts = opts.gridLines; + const display = me._isVisible(); + const labelsBelowTicks = opts.position !== 'top' && me.axis === 'x'; + const isHorizontal = me.isHorizontal(); + const scaleLabelHeight = display && getScaleLabelHeight(scaleLabelOpts, chart.options.font); + if (isHorizontal) { + minSize.width = me.maxWidth; + } else if (display) { + minSize.width = getTickMarkLength(gridLineOpts) + scaleLabelHeight; + } + if (!isHorizontal) { + minSize.height = me.maxHeight; + } else if (display) { + minSize.height = getTickMarkLength(gridLineOpts) + scaleLabelHeight; + } + if (tickOpts.display && display && me.ticks.length) { + const labelSizes = me._getLabelSizes(); + const firstLabelSize = labelSizes.first; + const lastLabelSize = labelSizes.last; + const widestLabelSize = labelSizes.widest; + const highestLabelSize = labelSizes.highest; + const lineSpace = highestLabelSize.offset * 0.8; + const tickPadding = tickOpts.padding; + if (isHorizontal) { + const isRotated = me.labelRotation !== 0; + const angleRadians = toRadians(me.labelRotation); + const cosRotation = Math.cos(angleRadians); + const sinRotation = Math.sin(angleRadians); + const labelHeight = sinRotation * widestLabelSize.width + + cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0)) + + (isRotated ? 0 : lineSpace); + minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding); + const offsetLeft = me.getPixelForTick(0) - me.left; + const offsetRight = me.right - me.getPixelForTick(me.ticks.length - 1); + let paddingLeft, paddingRight; + if (isRotated) { + paddingLeft = labelsBelowTicks ? + cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset : + sinRotation * (firstLabelSize.height - firstLabelSize.offset); + paddingRight = labelsBelowTicks ? + sinRotation * (lastLabelSize.height - lastLabelSize.offset) : + cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset; + } else { + paddingLeft = firstLabelSize.width / 2; + paddingRight = lastLabelSize.width / 2; + } + me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3; + me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3; + } else { + const labelWidth = tickOpts.mirror ? 0 : + widestLabelSize.width + tickPadding + lineSpace; + minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth); + me.paddingTop = lastLabelSize.height / 2; + me.paddingBottom = firstLabelSize.height / 2; + } + } + me._handleMargins(); + if (isHorizontal) { + me.width = me._length = chart.width - me._margins.left - me._margins.right; + me.height = minSize.height; + } else { + me.width = minSize.width; + me.height = me._length = chart.height - me._margins.top - me._margins.bottom; + } + } + _handleMargins() { + const me = this; + if (me._margins) { + me._margins.left = Math.max(me.paddingLeft, me._margins.left); + me._margins.top = Math.max(me.paddingTop, me._margins.top); + me._margins.right = Math.max(me.paddingRight, me._margins.right); + me._margins.bottom = Math.max(me.paddingBottom, me._margins.bottom); + } + } + afterFit() { + callback(this.options.afterFit, [this]); + } + isHorizontal() { + const {axis, position} = this.options; + return position === 'top' || position === 'bottom' || axis === 'x'; + } + isFullWidth() { + return this.options.fullWidth; + } + _convertTicksToLabels(ticks) { + const me = this; + me.beforeTickToLabelConversion(); + me.generateTickLabels(ticks); + me.afterTickToLabelConversion(); + } + _getLabelSizes() { + const me = this; + let labelSizes = me._labelSizes; + if (!labelSizes) { + me._labelSizes = labelSizes = me._computeLabelSizes(); + } + return labelSizes; + } + _computeLabelSizes() { + const me = this; + const ctx = me.ctx; + const caches = me._longestTextCache; + const sampleSize = me.options.ticks.sampleSize; + const widths = []; + const heights = []; + const offsets = []; + let ticks = me.ticks; + if (sampleSize < ticks.length) { + ticks = sample(ticks, sampleSize); + } + const length = ticks.length; + let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; + for (i = 0; i < length; ++i) { + label = ticks[i].label; + tickFont = me._resolveTickFontOptions(i); + ctx.font = fontString = tickFont.string; + cache = caches[fontString] = caches[fontString] || {data: {}, gc: []}; + lineHeight = tickFont.lineHeight; + width = height = 0; + if (!isNullOrUndef(label) && !isArray(label)) { + width = _measureText(ctx, cache.data, cache.gc, width, label); + height = lineHeight; + } else if (isArray(label)) { + for (j = 0, jlen = label.length; j < jlen; ++j) { + nestedLabel = label[j]; + if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { + width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); + height += lineHeight; + } + } + } + widths.push(width); + heights.push(height); + offsets.push(lineHeight / 2); + } + garbageCollect(caches, length); + const widest = widths.indexOf(Math.max.apply(null, widths)); + const highest = heights.indexOf(Math.max.apply(null, heights)); + function valueAt(idx) { + return { + width: widths[idx] || 0, + height: heights[idx] || 0, + offset: offsets[idx] || 0 + }; + } + return { + first: valueAt(0), + last: valueAt(length - 1), + widest: valueAt(widest), + highest: valueAt(highest) + }; + } + getLabelForValue(value) { + return value; + } + getPixelForValue(value, index) { + return NaN; + } + getValueForPixel(pixel) {} + getPixelForTick(index) { + const ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + getPixelForDecimal(decimal) { + const me = this; + if (me._reversePixels) { + decimal = 1 - decimal; + } + return _int32Range(me._startPixel + decimal * me._length); + } + getDecimalForPixel(pixel) { + const decimal = (pixel - this._startPixel) / this._length; + return this._reversePixels ? 1 - decimal : decimal; + } + getBasePixel() { + return this.getPixelForValue(this.getBaseValue()); + } + getBaseValue() { + const {min, max} = this; + return min < 0 && max < 0 ? max : + min > 0 && max > 0 ? min : + 0; + } + _autoSkip(ticks) { + const me = this; + const tickOpts = me.options.ticks; + const ticksLimit = tickOpts.maxTicksLimit || me._length / me._tickSize(); + const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; + const numMajorIndices = majorIndices.length; + const first = majorIndices[0]; + const last = majorIndices[numMajorIndices - 1]; + const newTicks = []; + if (numMajorIndices > ticksLimit) { + skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); + return newTicks; + } + const spacing = calculateSpacing(majorIndices, ticks, ticksLimit); + if (numMajorIndices > 0) { + let i, ilen; + const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; + skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); + for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { + skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); + } + skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); + return newTicks; + } + skip(ticks, newTicks, spacing); + return newTicks; + } + _tickSize() { + const me = this; + const optionTicks = me.options.ticks; + const rot = toRadians(me.labelRotation); + const cos = Math.abs(Math.cos(rot)); + const sin = Math.abs(Math.sin(rot)); + const labelSizes = me._getLabelSizes(); + const padding = optionTicks.autoSkipPadding || 0; + const w = labelSizes ? labelSizes.widest.width + padding : 0; + const h = labelSizes ? labelSizes.highest.height + padding : 0; + return me.isHorizontal() + ? h * cos > w * sin ? w / cos : h / sin + : h * sin < w * cos ? h / cos : w / sin; + } + _isVisible() { + const display = this.options.display; + if (display !== 'auto') { + return !!display; + } + return this.getMatchingVisibleMetas().length > 0; + } + _computeGridLineItems(chartArea) { + const me = this; + const axis = me.axis; + const chart = me.chart; + const options = me.options; + const {gridLines, position} = options; + const offsetGridLines = gridLines.offsetGridLines; + const isHorizontal = me.isHorizontal(); + const ticks = me.ticks; + const ticksLength = ticks.length + (offsetGridLines ? 1 : 0); + const tl = getTickMarkLength(gridLines); + const items = []; + let context = { + chart, + scale: me, + tick: ticks[0], + index: 0, + }; + const axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0; + const axisHalfWidth = axisWidth / 2; + const alignBorderValue = function(pixel) { + return _alignPixel(chart, pixel, axisWidth); + }; + let borderValue, i, lineValue, alignedLineValue; + let tx1, ty1, tx2, ty2, x1, y1, x2, y2; + if (position === 'top') { + borderValue = alignBorderValue(me.bottom); + ty1 = me.bottom - tl; + ty2 = borderValue - axisHalfWidth; + y1 = alignBorderValue(chartArea.top) + axisHalfWidth; + y2 = chartArea.bottom; + } else if (position === 'bottom') { + borderValue = alignBorderValue(me.top); + y1 = chartArea.top; + y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; + ty1 = borderValue + axisHalfWidth; + ty2 = me.top + tl; + } else if (position === 'left') { + borderValue = alignBorderValue(me.right); + tx1 = me.right - tl; + tx2 = borderValue - axisHalfWidth; + x1 = alignBorderValue(chartArea.left) + axisHalfWidth; + x2 = chartArea.right; + } else if (position === 'right') { + borderValue = alignBorderValue(me.left); + x1 = chartArea.left; + x2 = alignBorderValue(chartArea.right) - axisHalfWidth; + tx1 = borderValue + axisHalfWidth; + tx2 = me.left + tl; + } else if (axis === 'x') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value)); + } + y1 = chartArea.top; + y2 = chartArea.bottom; + ty1 = borderValue + axisHalfWidth; + ty2 = ty1 + tl; + } else if (axis === 'y') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value)); + } + tx1 = borderValue - axisHalfWidth; + tx2 = tx1 - tl; + x1 = chartArea.left; + x2 = chartArea.right; + } + for (i = 0; i < ticksLength; ++i) { + const tick = ticks[i] || {}; + context = { + chart, + scale: me, + tick, + index: i, + }; + const lineWidth = resolve([gridLines.lineWidth], context, i); + const lineColor = resolve([gridLines.color], context, i); + const borderDash = gridLines.borderDash || []; + const borderDashOffset = resolve([gridLines.borderDashOffset], context, i); + lineValue = getPixelForGridLine(me, i, offsetGridLines); + if (lineValue === undefined) { + continue; + } + alignedLineValue = _alignPixel(chart, lineValue, lineWidth); + if (isHorizontal) { + tx1 = tx2 = x1 = x2 = alignedLineValue; + } else { + ty1 = ty2 = y1 = y2 = alignedLineValue; + } + items.push({ + tx1, + ty1, + tx2, + ty2, + x1, + y1, + x2, + y2, + width: lineWidth, + color: lineColor, + borderDash, + borderDashOffset, + }); + } + me._ticksLength = ticksLength; + me._borderValue = borderValue; + return items; + } + _computeLabelItems(chartArea) { + const me = this; + const axis = me.axis; + const options = me.options; + const {position, ticks: optionTicks} = options; + const isMirrored = optionTicks.mirror; + const isHorizontal = me.isHorizontal(); + const ticks = me.ticks; + const tickPadding = optionTicks.padding; + const tl = getTickMarkLength(options.gridLines); + const rotation = -toRadians(me.labelRotation); + const items = []; + let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; + if (position === 'top') { + y = me.bottom - tl - tickPadding; + textAlign = !rotation ? 'center' : 'left'; + } else if (position === 'bottom') { + y = me.top + tl + tickPadding; + textAlign = !rotation ? 'center' : 'right'; + } else if (position === 'left') { + x = me.right - (isMirrored ? 0 : tl) - tickPadding; + textAlign = isMirrored ? 'left' : 'right'; + } else if (position === 'right') { + x = me.left + (isMirrored ? 0 : tl) + tickPadding; + textAlign = isMirrored ? 'right' : 'left'; + } else if (axis === 'x') { + if (position === 'center') { + y = ((chartArea.top + chartArea.bottom) / 2) + tl + tickPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + y = me.chart.scales[positionAxisID].getPixelForValue(value) + tl + tickPadding; + } + textAlign = !rotation ? 'center' : 'right'; + } else if (axis === 'y') { + if (position === 'center') { + x = ((chartArea.left + chartArea.right) / 2) - tl - tickPadding; + } else if (isObject(position)) { + const positionAxisID = Object.keys(position)[0]; + const value = position[positionAxisID]; + x = me.chart.scales[positionAxisID].getPixelForValue(value); + } + textAlign = 'right'; + } + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + label = tick.label; + pixel = me.getPixelForTick(i) + optionTicks.labelOffset; + font = me._resolveTickFontOptions(i); + lineHeight = font.lineHeight; + lineCount = isArray(label) ? label.length : 1; + if (isHorizontal) { + x = pixel; + if (position === 'top') { + textOffset = (Math.sin(rotation) * (lineCount / 2) + 0.5) * lineHeight; + textOffset -= (rotation === 0 ? (lineCount - 0.5) : Math.cos(rotation) * (lineCount / 2)) * lineHeight; + } else { + textOffset = Math.sin(rotation) * (lineCount / 2) * lineHeight; + textOffset += (rotation === 0 ? 0.5 : Math.cos(rotation) * (lineCount / 2)) * lineHeight; + } + } else { + y = pixel; + textOffset = (1 - lineCount) * lineHeight / 2; + } + items.push({ + x, + y, + rotation, + label, + font, + textOffset, + textAlign + }); + } + return items; + } + drawGrid(chartArea) { + const me = this; + const gridLines = me.options.gridLines; + const ctx = me.ctx; + const chart = me.chart; + let context = { + chart, + scale: me, + tick: me.ticks[0], + index: 0, + }; + const axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0; + const items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea)); + let i, ilen; + if (gridLines.display) { + for (i = 0, ilen = items.length; i < ilen; ++i) { + const item = items[i]; + const width = item.width; + const color = item.color; + if (width && color) { + ctx.save(); + ctx.lineWidth = width; + ctx.strokeStyle = color; + if (ctx.setLineDash) { + ctx.setLineDash(item.borderDash); + ctx.lineDashOffset = item.borderDashOffset; + } + ctx.beginPath(); + if (gridLines.drawTicks) { + ctx.moveTo(item.tx1, item.ty1); + ctx.lineTo(item.tx2, item.ty2); + } + if (gridLines.drawOnChartArea) { + ctx.moveTo(item.x1, item.y1); + ctx.lineTo(item.x2, item.y2); + } + ctx.stroke(); + ctx.restore(); + } + } + } + if (axisWidth) { + const firstLineWidth = axisWidth; + context = { + chart, + scale: me, + tick: me.ticks[me._ticksLength - 1], + index: me._ticksLength - 1, + }; + const lastLineWidth = resolve([gridLines.lineWidth, 1], context, me._ticksLength - 1); + const borderValue = me._borderValue; + let x1, x2, y1, y2; + if (me.isHorizontal()) { + x1 = _alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2; + x2 = _alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2; + y1 = y2 = borderValue; + } else { + y1 = _alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2; + y2 = _alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2; + x1 = x2 = borderValue; + } + ctx.lineWidth = axisWidth; + ctx.strokeStyle = resolve([gridLines.borderColor, gridLines.color], context, 0); + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + } + } + drawLabels(chartArea) { + const me = this; + const optionTicks = me.options.ticks; + if (!optionTicks.display) { + return; + } + const ctx = me.ctx; + const items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea)); + let i, j, ilen, jlen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + const item = items[i]; + const tickFont = item.font; + const useStroke = tickFont.lineWidth > 0 && tickFont.strokeStyle !== ''; + ctx.save(); + ctx.translate(item.x, item.y); + ctx.rotate(item.rotation); + ctx.font = tickFont.string; + ctx.fillStyle = tickFont.color; + ctx.textBaseline = 'middle'; + ctx.textAlign = item.textAlign; + if (useStroke) { + ctx.strokeStyle = tickFont.strokeStyle; + ctx.lineWidth = tickFont.lineWidth; + } + const label = item.label; + let y = item.textOffset; + if (isArray(label)) { + for (j = 0, jlen = label.length; j < jlen; ++j) { + if (useStroke) { + ctx.strokeText('' + label[j], 0, y); + } + ctx.fillText('' + label[j], 0, y); + y += tickFont.lineHeight; + } + } else { + if (useStroke) { + ctx.strokeText(label, 0, y); + } + ctx.fillText(label, 0, y); + } + ctx.restore(); + } + } + drawTitle(chartArea) { + const me = this; + const ctx = me.ctx; + const options = me.options; + const scaleLabel = options.scaleLabel; + if (!scaleLabel.display) { + return; + } + const scaleLabelFont = toFont(scaleLabel.font, me.chart.options.font); + const scaleLabelPadding = toPadding(scaleLabel.padding); + const halfLineHeight = scaleLabelFont.lineHeight / 2; + const scaleLabelAlign = scaleLabel.align; + const position = options.position; + const isReverse = me.options.reverse; + let rotation = 0; + let textAlign; + let scaleLabelX, scaleLabelY; + if (me.isHorizontal()) { + switch (scaleLabelAlign) { + case 'start': + scaleLabelX = me.left + (isReverse ? me.width : 0); + textAlign = isReverse ? 'right' : 'left'; + break; + case 'end': + scaleLabelX = me.left + (isReverse ? 0 : me.width); + textAlign = isReverse ? 'left' : 'right'; + break; + default: + scaleLabelX = me.left + me.width / 2; + textAlign = 'center'; + } + scaleLabelY = position === 'top' + ? me.top + halfLineHeight + scaleLabelPadding.top + : me.bottom - halfLineHeight - scaleLabelPadding.bottom; + } else { + const isLeft = position === 'left'; + scaleLabelX = isLeft + ? me.left + halfLineHeight + scaleLabelPadding.top + : me.right - halfLineHeight - scaleLabelPadding.top; + switch (scaleLabelAlign) { + case 'start': + scaleLabelY = me.top + (isReverse ? 0 : me.height); + textAlign = isReverse === isLeft ? 'right' : 'left'; + break; + case 'end': + scaleLabelY = me.top + (isReverse ? me.height : 0); + textAlign = isReverse === isLeft ? 'left' : 'right'; + break; + default: + scaleLabelY = me.top + me.height / 2; + textAlign = 'center'; + } + rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI; + } + ctx.save(); + ctx.translate(scaleLabelX, scaleLabelY); + ctx.rotate(rotation); + ctx.textAlign = textAlign; + ctx.textBaseline = 'middle'; + ctx.fillStyle = scaleLabelFont.color; + ctx.font = scaleLabelFont.string; + ctx.fillText(scaleLabel.labelString, 0, 0); + ctx.restore(); + } + draw(chartArea) { + const me = this; + if (!me._isVisible()) { + return; + } + me.drawGrid(chartArea); + me.drawTitle(); + me.drawLabels(chartArea); + } + _layers() { + const me = this; + const opts = me.options; + const tz = opts.ticks && opts.ticks.z || 0; + const gz = opts.gridLines && opts.gridLines.z || 0; + if (!me._isVisible() || tz === gz || me.draw !== me._draw) { + return [{ + z: tz, + draw(chartArea) { + me.draw(chartArea); + } + }]; + } + return [{ + z: gz, + draw(chartArea) { + me.drawGrid(chartArea); + me.drawTitle(); + } + }, { + z: tz, + draw(chartArea) { + me.drawLabels(chartArea); + } + }]; + } + getMatchingVisibleMetas(type) { + const me = this; + const metas = me.chart.getSortedVisibleDatasetMetas(); + const axisID = me.axis + 'AxisID'; + const result = []; + let i, ilen; + for (i = 0, ilen = metas.length; i < ilen; ++i) { + const meta = metas[i]; + if (meta[axisID] === me.id && (!type || meta.type === type)) { + result.push(meta); + } + } + return result; + } + _resolveTickFontOptions(index) { + const me = this; + const chart = me.chart; + const options = me.options.ticks; + const ticks = me.ticks || []; + const context = { + chart, + scale: me, + tick: ticks[index], + index + }; + return toFont(resolve([options.font], context), chart.options.font); + } +} +Scale.prototype._draw = Scale.prototype.draw; + +class TypedRegistry { + constructor(type, scope) { + this.type = type; + this.scope = scope; + this.items = Object.create(null); + } + isForType(type) { + return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); + } + register(item) { + const proto = Object.getPrototypeOf(item); + let parentScope; + if (isIChartComponent(proto)) { + parentScope = this.register(proto); + } + const items = this.items; + const id = item.id; + const baseScope = this.scope; + const scope = baseScope ? baseScope + '.' + id : id; + if (!id) { + throw new Error('class does not have id: ' + item); + } + if (id in items) { + return scope; + } + if (Object.keys(defaults.get(scope)).length) { + throw new Error('Can not register "' + id + '", because "defaults.' + scope + '" would collide with existing defaults'); + } + items[id] = item; + registerDefaults(item, scope, parentScope); + return scope; + } + get(id) { + return this.items[id]; + } + unregister(item) { + const items = this.items; + const id = item.id; + const scope = this.scope; + if (id in items) { + delete items[id]; + } + if (scope && id in defaults[scope]) { + delete defaults[scope][id]; + } else if (id in defaults) { + delete defaults[id]; + } + } +} +function registerDefaults(item, scope, parentScope) { + const itemDefaults = parentScope + ? Object.assign({}, defaults.get(parentScope), item.defaults) + : item.defaults; + defaults.set(scope, itemDefaults); + if (item.defaultRoutes) { + routeDefaults(scope, item.defaultRoutes); + } +} +function routeDefaults(scope, routes) { + Object.keys(routes).forEach(property => { + const parts = routes[property].split('.'); + const targetName = parts.pop(); + const targetScope = parts.join('.'); + defaults.route(scope, property, targetScope, targetName); + }); +} +function isIChartComponent(proto) { + return 'id' in proto && 'defaults' in proto; +} + +class Registry { + constructor() { + this.controllers = new TypedRegistry(DatasetController, ''); + this.elements = new TypedRegistry(Element, 'elements'); + this.plugins = new TypedRegistry(Object, 'plugins'); + this.scales = new TypedRegistry(Scale, 'scales'); + this._typedRegistries = [this.controllers, this.scales, this.elements]; + } + add(...args) { + this._each('register', args); + } + remove(...args) { + this._each('unregister', args); + } + addControllers(...args) { + this._each('register', args, this.controllers); + } + addElements(...args) { + this._each('register', args, this.elements); + } + addPlugins(...args) { + this._each('register', args, this.plugins); + } + addScales(...args) { + this._each('register', args, this.scales); + } + getController(id) { + return this._get(id, this.controllers, 'controller'); + } + getElement(id) { + return this._get(id, this.elements, 'element'); + } + getPlugin(id) { + return this._get(id, this.plugins, 'plugin'); + } + getScale(id) { + return this._get(id, this.scales, 'scale'); + } + removeControllers(...args) { + this._each('unregister', args, this.controllers); + } + removeElements(...args) { + this._each('unregister', args, this.elements); + } + removePlugins(...args) { + this._each('unregister', args, this.plugins); + } + removeScales(...args) { + this._each('unregister', args, this.scales); + } + _each(method, args, typedRegistry) { + const me = this; + [...args].forEach(arg => { + const reg = typedRegistry || me._getRegistryForType(arg); + if (typedRegistry || reg.isForType(arg) || (reg === me.plugins && arg.id)) { + me._exec(method, reg, arg); + } else { + each(arg, item => { + const itemReg = typedRegistry || me._getRegistryForType(item); + me._exec(method, itemReg, item); + }); + } + }); + } + _exec(method, registry, component) { + const camelMethod = _capitalize(method); + callback(component['before' + camelMethod], [], component); + registry[method](component); + callback(component['after' + camelMethod], [], component); + } + _getRegistryForType(type) { + for (let i = 0; i < this._typedRegistries.length; i++) { + const reg = this._typedRegistries[i]; + if (reg.isForType(type)) { + return reg; + } + } + return this.plugins; + } + _get(id, typedRegistry, type) { + const item = typedRegistry.get(id); + if (item === undefined) { + throw new Error('"' + id + '" is not a registered ' + type + '.'); + } + return item; + } +} +var registry = new Registry(); + +class PluginService { + notify(chart, hook, args) { + const descriptors = this._descriptors(chart); + for (let i = 0; i < descriptors.length; ++i) { + const descriptor = descriptors[i]; + const plugin = descriptor.plugin; + const method = plugin[hook]; + if (typeof method === 'function') { + const params = [chart].concat(args || []); + params.push(descriptor.options); + if (method.apply(plugin, params) === false) { + return false; + } + } + } + return true; + } + invalidate() { + this._cache = undefined; + } + _descriptors(chart) { + if (this._cache) { + return this._cache; + } + const config = (chart && chart.config) || {}; + const options = (config.options && config.options.plugins) || {}; + const plugins = allPlugins(config); + const descriptors = createDescriptors(plugins, options); + this._cache = descriptors; + return descriptors; + } +} +function allPlugins(config) { + const plugins = []; + const keys = Object.keys(registry.plugins.items); + for (let i = 0; i < keys.length; i++) { + plugins.push(registry.getPlugin(keys[i])); + } + const local = config.plugins || []; + for (let i = 0; i < local.length; i++) { + const plugin = local[i]; + if (plugins.indexOf(plugin) === -1) { + plugins.push(plugin); + } + } + return plugins; +} +function createDescriptors(plugins, options) { + const result = []; + for (let i = 0; i < plugins.length; i++) { + const plugin = plugins[i]; + const id = plugin.id; + let opts = options[id]; + if (opts === false) { + continue; + } + if (opts === true) { + opts = {}; + } + result.push({ + plugin, + options: mergeIf({}, [opts, defaults.plugins[id]]) + }); + } + return result; +} + +var version = "3.0.0-beta.2"; + +function getIndexAxis(type, options) { + const typeDefaults = defaults[type] || {}; + const datasetDefaults = typeDefaults.datasets || {}; + const typeOptions = options[type] || {}; + const datasetOptions = typeOptions.datasets || {}; + return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; +} +function getAxisFromDefaultScaleID(id, indexAxis) { + let axis = id; + if (id === '_index_') { + axis = indexAxis; + } else if (id === '_value_') { + axis = indexAxis === 'x' ? 'y' : 'x'; + } + return axis; +} +function getDefaultScaleIDFromAxis(axis, indexAxis) { + return axis === indexAxis ? '_index_' : '_value_'; +} +function mergeScaleConfig(config, options) { + options = options || {}; + const chartDefaults = defaults[config.type] || {scales: {}}; + const configScales = options.scales || {}; + const chartIndexAxis = getIndexAxis(config.type, options); + const firstIDs = {}; + const scales = {}; + Object.keys(configScales).forEach(id => { + const scaleConf = configScales[id]; + const axis = determineAxis(id, scaleConf); + const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); + firstIDs[axis] = firstIDs[axis] || id; + scales[id] = mergeIf({axis}, [scaleConf, chartDefaults.scales[axis], chartDefaults.scales[defaultId]]); + }); + if (options.scale) { + scales[options.scale.id || 'r'] = mergeIf({axis: 'r'}, [options.scale, chartDefaults.scales.r]); + firstIDs.r = firstIDs.r || options.scale.id || 'r'; + } + config.data.datasets.forEach(dataset => { + const type = dataset.type || config.type; + const indexAxis = dataset.indexAxis || getIndexAxis(type, options); + const datasetDefaults = defaults[type] || {}; + const defaultScaleOptions = datasetDefaults.scales || {}; + Object.keys(defaultScaleOptions).forEach(defaultID => { + const axis = getAxisFromDefaultScaleID(defaultID, indexAxis); + const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; + scales[id] = scales[id] || {}; + mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]); + }); + }); + Object.keys(scales).forEach(key => { + const scale = scales[key]; + mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); + }); + return scales; +} +function mergeConfig(...args) { + return merge({}, args, { + merger(key, target, source, options) { + if (key !== 'scales' && key !== 'scale') { + _merger(key, target, source, options); + } + } + }); +} +function initConfig(config) { + config = config || {}; + const data = config.data = config.data || {datasets: [], labels: []}; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + const scaleConfig = mergeScaleConfig(config, config.options); + const options = config.options = mergeConfig( + defaults, + defaults[config.type], + config.options || {}); + options.scales = scaleConfig; + options.title = (options.title !== false) && merge({}, [defaults.plugins.title, options.title]); + options.tooltips = (options.tooltips !== false) && merge({}, [defaults.plugins.tooltip, options.tooltips]); + return config; +} +function isAnimationDisabled(config) { + return !config.animation; +} +function updateConfig(chart) { + let newOptions = chart.options; + each(chart.scales, (scale) => { + layouts.removeBox(chart, scale); + }); + const scaleConfig = mergeScaleConfig(chart.config, newOptions); + newOptions = mergeConfig( + defaults, + defaults[chart.config.type], + newOptions); + chart.options = chart.config.options = newOptions; + chart.options.scales = scaleConfig; + chart._animationsDisabled = isAnimationDisabled(newOptions); +} +const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; +function positionIsHorizontal(position, axis) { + return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'); +} +function axisFromPosition(position) { + if (position === 'top' || position === 'bottom') { + return 'x'; + } + if (position === 'left' || position === 'right') { + return 'y'; + } +} +function determineAxis(id, scaleOptions) { + if (id === 'x' || id === 'y' || id === 'r') { + return id; + } + return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); +} +function compare2Level(l1, l2) { + return function(a, b) { + return a[l1] === b[l1] + ? a[l2] - b[l2] + : a[l1] - b[l1]; + }; +} +function onAnimationsComplete(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + chart._plugins.notify(chart, 'afterRender'); + callback(animationOptions && animationOptions.onComplete, [context], chart); +} +function onAnimationProgress(context) { + const chart = context.chart; + const animationOptions = chart.options.animation; + callback(animationOptions && animationOptions.onProgress, [context], chart); +} +function isDomSupported() { + return typeof window !== 'undefined' && typeof document !== 'undefined'; +} +function getCanvas(item) { + if (isDomSupported() && typeof item === 'string') { + item = document.getElementById(item); + } else if (item && item.length) { + item = item[0]; + } + if (item && item.canvas) { + item = item.canvas; + } + return item; +} +class Chart { + constructor(item, config) { + const me = this; + config = initConfig(config); + const initialCanvas = getCanvas(item); + this.platform = me._initializePlatform(initialCanvas, config); + const context = me.platform.acquireContext(initialCanvas, config); + const canvas = context && context.canvas; + const height = canvas && canvas.height; + const width = canvas && canvas.width; + this.id = uid(); + this.ctx = context; + this.canvas = canvas; + this.config = config; + this.width = width; + this.height = height; + this.aspectRatio = height ? width / height : null; + this.options = config.options; + this._bufferedRender = false; + this._layers = []; + this._metasets = []; + this.boxes = []; + this.currentDevicePixelRatio = undefined; + this.chartArea = undefined; + this.data = undefined; + this._active = []; + this._lastEvent = undefined; + this._listeners = {}; + this._sortedMetasets = []; + this._updating = false; + this.scales = {}; + this.scale = undefined; + this._plugins = new PluginService(); + this.$proxies = {}; + this._hiddenIndices = {}; + this.attached = false; + Chart.instances[me.id] = me; + Object.defineProperty(me, 'data', { + get() { + return me.config.data; + }, + set(value) { + me.config.data = value; + } + }); + if (!context || !canvas) { + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } + animator.listen(me, 'complete', onAnimationsComplete); + animator.listen(me, 'progress', onAnimationProgress); + me._initialize(); + if (me.attached) { + me.update(); + } + } + _initialize() { + const me = this; + me._plugins.notify(me, 'beforeInit'); + if (me.options.responsive) { + me.resize(true); + } else { + retinaScale(me, me.options.devicePixelRatio); + } + me.bindEvents(); + me._plugins.notify(me, 'afterInit'); + return me; + } + _initializePlatform(canvas, config) { + if (config.platform) { + return new config.platform(); + } else if (!isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) { + return new BasicPlatform(); + } + return new DomPlatform(); + } + clear() { + clear(this); + return this; + } + stop() { + animator.stop(this); + return this; + } + resize(silent, width, height) { + const me = this; + const options = me.options; + const canvas = me.canvas; + const aspectRatio = options.maintainAspectRatio && me.aspectRatio; + const newSize = me.platform.getMaximumSize(canvas, width, height, aspectRatio); + const oldRatio = me.currentDevicePixelRatio; + const newRatio = options.devicePixelRatio || me.platform.getDevicePixelRatio(); + if (me.width === newSize.width && me.height === newSize.height && oldRatio === newRatio) { + return; + } + canvas.width = me.width = newSize.width; + canvas.height = me.height = newSize.height; + if (canvas.style) { + canvas.style.width = newSize.width + 'px'; + canvas.style.height = newSize.height + 'px'; + } + retinaScale(me, newRatio); + if (!silent) { + me._plugins.notify(me, 'resize', [newSize]); + callback(options.onResize, [newSize], me); + if (me.attached) { + me.update('resize'); + } + } + } + ensureScalesHaveIDs() { + const options = this.options; + const scalesOptions = options.scales || {}; + const scaleOptions = options.scale; + each(scalesOptions, (axisOptions, axisID) => { + axisOptions.id = axisID; + }); + if (scaleOptions) { + scaleOptions.id = scaleOptions.id || 'scale'; + } + } + buildOrUpdateScales() { + const me = this; + const options = me.options; + const scaleOpts = options.scales; + const scales = me.scales || {}; + const updated = Object.keys(scales).reduce((obj, id) => { + obj[id] = false; + return obj; + }, {}); + let items = []; + if (scaleOpts) { + items = items.concat( + Object.keys(scaleOpts).map((id) => { + const scaleOptions = scaleOpts[id]; + const axis = determineAxis(id, scaleOptions); + const isRadial = axis === 'r'; + const isHorizontal = axis === 'x'; + return { + options: scaleOptions, + dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', + dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' + }; + }) + ); + } + each(items, (item) => { + const scaleOptions = item.options; + const id = scaleOptions.id; + const axis = determineAxis(id, scaleOptions); + const scaleType = valueOrDefault(scaleOptions.type, item.dtype); + if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } + updated[id] = true; + let scale = null; + if (id in scales && scales[id].type === scaleType) { + scale = scales[id]; + } else { + const scaleClass = registry.getScale(scaleType); + scale = new scaleClass({ + id, + type: scaleType, + ctx: me.ctx, + chart: me + }); + scales[scale.id] = scale; + } + scale.init(scaleOptions, options); + if (item.isDefault) { + me.scale = scale; + } + }); + each(updated, (hasUpdated, id) => { + if (!hasUpdated) { + delete scales[id]; + } + }); + me.scales = scales; + each(scales, (scale) => { + scale.fullWidth = scale.options.fullWidth; + scale.position = scale.options.position; + scale.weight = scale.options.weight; + layouts.addBox(me, scale); + }); + } + _updateMetasetIndex(meta, index) { + const metasets = this._metasets; + const oldIndex = meta.index; + if (oldIndex !== index) { + metasets[oldIndex] = metasets[index]; + metasets[index] = meta; + meta.index = index; + } + } + _updateMetasets() { + const me = this; + const metasets = me._metasets; + const numData = me.data.datasets.length; + const numMeta = metasets.length; + if (numMeta > numData) { + for (let i = numData; i < numMeta; ++i) { + me._destroyDatasetMeta(i); + } + metasets.splice(numData, numMeta - numData); + } + me._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); + } + buildOrUpdateControllers() { + const me = this; + const newControllers = []; + const datasets = me.data.datasets; + let i, ilen; + for (i = 0, ilen = datasets.length; i < ilen; i++) { + const dataset = datasets[i]; + let meta = me.getDatasetMeta(i); + const type = dataset.type || me.config.type; + if (meta.type && meta.type !== type) { + me._destroyDatasetMeta(i); + meta = me.getDatasetMeta(i); + } + meta.type = type; + meta.indexAxis = dataset.indexAxis || getIndexAxis(type, me.options); + meta.order = dataset.order || 0; + me._updateMetasetIndex(meta, i); + meta.label = '' + dataset.label; + meta.visible = me.isDatasetVisible(i); + if (meta.controller) { + meta.controller.updateIndex(i); + meta.controller.linkScales(); + } else { + const controllerDefaults = defaults[type]; + const ControllerClass = registry.getController(type); + Object.assign(ControllerClass.prototype, { + dataElementType: registry.getElement(controllerDefaults.dataElementType), + datasetElementType: controllerDefaults.datasetElementType && registry.getElement(controllerDefaults.datasetElementType), + dataElementOptions: controllerDefaults.dataElementOptions, + datasetElementOptions: controllerDefaults.datasetElementOptions + }); + meta.controller = new ControllerClass(me, i); + newControllers.push(meta.controller); + } + } + me._updateMetasets(); + return newControllers; + } + _resetElements() { + const me = this; + each(me.data.datasets, (dataset, datasetIndex) => { + me.getDatasetMeta(datasetIndex).controller.reset(); + }, me); + } + reset() { + this._resetElements(); + this._plugins.notify(this, 'reset'); + } + update(mode) { + const me = this; + let i, ilen; + me._updating = true; + updateConfig(me); + me.ensureScalesHaveIDs(); + me.buildOrUpdateScales(); + me._plugins.invalidate(); + if (me._plugins.notify(me, 'beforeUpdate') === false) { + return; + } + const newControllers = me.buildOrUpdateControllers(); + for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) { + me.getDatasetMeta(i).controller.buildOrUpdateElements(); + } + me._updateLayout(); + each(newControllers, (controller) => { + controller.reset(); + }); + me._updateDatasets(mode); + me._plugins.notify(me, 'afterUpdate'); + me._layers.sort(compare2Level('z', '_idx')); + if (me._lastEvent) { + me._eventHandler(me._lastEvent, true); + } + me.render(); + me._updating = false; + } + _updateLayout() { + const me = this; + if (me._plugins.notify(me, 'beforeLayout') === false) { + return; + } + layouts.update(me, me.width, me.height); + me._layers = []; + each(me.boxes, (box) => { + if (box.configure) { + box.configure(); + } + me._layers.push(...box._layers()); + }, me); + me._layers.forEach((item, index) => { + item._idx = index; + }); + me._plugins.notify(me, 'afterLayout'); + } + _updateDatasets(mode) { + const me = this; + const isFunction = typeof mode === 'function'; + if (me._plugins.notify(me, 'beforeDatasetsUpdate') === false) { + return; + } + for (let i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me._updateDataset(i, isFunction ? mode({datasetIndex: i}) : mode); + } + me._plugins.notify(me, 'afterDatasetsUpdate'); + } + _updateDataset(index, mode) { + const me = this; + const meta = me.getDatasetMeta(index); + const args = {meta, index, mode}; + if (me._plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) { + return; + } + meta.controller._update(mode); + me._plugins.notify(me, 'afterDatasetUpdate', [args]); + } + render() { + const me = this; + if (me._plugins.notify(me, 'beforeRender') === false) { + return; + } + if (animator.has(me)) { + if (me.attached && !animator.running(me)) { + animator.start(me); + } + } else { + me.draw(); + onAnimationsComplete({chart: me}); + } + } + draw() { + const me = this; + let i; + me.clear(); + if (me.width <= 0 || me.height <= 0) { + return; + } + if (me._plugins.notify(me, 'beforeDraw') === false) { + return; + } + const layers = me._layers; + for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { + layers[i].draw(me.chartArea); + } + me._drawDatasets(); + for (; i < layers.length; ++i) { + layers[i].draw(me.chartArea); + } + me._plugins.notify(me, 'afterDraw'); + } + _getSortedDatasetMetas(filterVisible) { + const me = this; + const metasets = me._sortedMetasets; + const result = []; + let i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + const meta = metasets[i]; + if (!filterVisible || meta.visible) { + result.push(meta); + } + } + return result; + } + getSortedVisibleDatasetMetas() { + return this._getSortedDatasetMetas(true); + } + _drawDatasets() { + const me = this; + if (me._plugins.notify(me, 'beforeDatasetsDraw') === false) { + return; + } + const metasets = me.getSortedVisibleDatasetMetas(); + for (let i = metasets.length - 1; i >= 0; --i) { + me._drawDataset(metasets[i]); + } + me._plugins.notify(me, 'afterDatasetsDraw'); + } + _drawDataset(meta) { + const me = this; + const ctx = me.ctx; + const clip = meta._clip; + const area = me.chartArea; + const args = { + meta, + index: meta.index, + }; + if (me._plugins.notify(me, 'beforeDatasetDraw', [args]) === false) { + return; + } + clipArea(ctx, { + left: clip.left === false ? 0 : area.left - clip.left, + right: clip.right === false ? me.width : area.right + clip.right, + top: clip.top === false ? 0 : area.top - clip.top, + bottom: clip.bottom === false ? me.height : area.bottom + clip.bottom + }); + meta.controller.draw(); + unclipArea(ctx); + me._plugins.notify(me, 'afterDatasetDraw', [args]); + } + getElementAtEvent(e) { + return Interaction.modes.nearest(this, e, {intersect: true}); + } + getElementsAtEvent(e) { + return Interaction.modes.index(this, e, {intersect: true}); + } + getElementsAtXAxis(e) { + return Interaction.modes.index(this, e, {intersect: false}); + } + getElementsAtEventForMode(e, mode, options, useFinalPosition) { + const method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options, useFinalPosition); + } + return []; + } + getDatasetAtEvent(e) { + return Interaction.modes.dataset(this, e, {intersect: true}); + } + getDatasetMeta(datasetIndex) { + const me = this; + const dataset = me.data.datasets[datasetIndex]; + const metasets = me._metasets; + let meta = metasets.filter(x => x._dataset === dataset).pop(); + if (!meta) { + meta = metasets[datasetIndex] = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, + xAxisID: null, + yAxisID: null, + order: dataset.order || 0, + index: datasetIndex, + _dataset: dataset, + _parsed: [], + _sorted: false + }; + } + return meta; + } + getVisibleDatasetCount() { + return this.getSortedVisibleDatasetMetas().length; + } + isDatasetVisible(datasetIndex) { + const meta = this.getDatasetMeta(datasetIndex); + return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden; + } + setDatasetVisibility(datasetIndex, visible) { + const meta = this.getDatasetMeta(datasetIndex); + meta.hidden = !visible; + } + toggleDataVisibility(index) { + this._hiddenIndices[index] = !this._hiddenIndices[index]; + } + getDataVisibility(index) { + return !this._hiddenIndices[index]; + } + _updateDatasetVisibility(datasetIndex, visible) { + const me = this; + const mode = visible ? 'show' : 'hide'; + const meta = me.getDatasetMeta(datasetIndex); + const anims = meta.controller._resolveAnimations(undefined, mode); + me.setDatasetVisibility(datasetIndex, visible); + anims.update(meta, {visible}); + me.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined); + } + hide(datasetIndex) { + this._updateDatasetVisibility(datasetIndex, false); + } + show(datasetIndex) { + this._updateDatasetVisibility(datasetIndex, true); + } + _destroyDatasetMeta(datasetIndex) { + const me = this; + const meta = me._metasets && me._metasets[datasetIndex]; + if (meta) { + meta.controller._destroy(); + delete me._metasets[datasetIndex]; + } + } + destroy() { + const me = this; + const canvas = me.canvas; + let i, ilen; + me.stop(); + animator.remove(me); + for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me._destroyDatasetMeta(i); + } + if (canvas) { + me.unbindEvents(); + clear(me); + me.platform.releaseContext(me.ctx); + me.canvas = null; + me.ctx = null; + } + me._plugins.notify(me, 'destroy'); + delete Chart.instances[me.id]; + } + toBase64Image(...args) { + return this.canvas.toDataURL(...args); + } + bindEvents() { + const me = this; + const listeners = me._listeners; + const platform = me.platform; + const _add = (type, listener) => { + platform.addEventListener(me, type, listener); + listeners[type] = listener; + }; + const _remove = (type, listener) => { + if (listeners[type]) { + platform.removeEventListener(me, type, listener); + delete listeners[type]; + } + }; + let listener = function(e, x, y) { + e.offsetX = x; + e.offsetY = y; + me._eventHandler(e); + }; + each(me.options.events, (type) => _add(type, listener)); + if (me.options.responsive) { + listener = (width, height) => { + if (me.canvas) { + me.resize(false, width, height); + } + }; + let detached; + const attached = () => { + _remove('attach', attached); + me.attached = true; + me.resize(); + _add('resize', listener); + _add('detach', detached); + }; + detached = () => { + me.attached = false; + _remove('resize', listener); + _add('attach', attached); + }; + if (platform.isAttached(me.canvas)) { + attached(); + } else { + detached(); + } + } else { + me.attached = true; + } + } + unbindEvents() { + const me = this; + const listeners = me._listeners; + if (!listeners) { + return; + } + delete me._listeners; + each(listeners, (listener, type) => { + me.platform.removeEventListener(me, type, listener); + }); + } + updateHoverStyle(items, mode, enabled) { + const prefix = enabled ? 'set' : 'remove'; + let meta, item, i, ilen; + if (mode === 'dataset') { + meta = this.getDatasetMeta(items[0].datasetIndex); + meta.controller['_' + prefix + 'DatasetHoverStyle'](); + } + for (i = 0, ilen = items.length; i < ilen; ++i) { + item = items[i]; + if (item) { + this.getDatasetMeta(item.datasetIndex).controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); + } + } + } + _updateHoverStyles(active, lastActive) { + const me = this; + const options = me.options || {}; + const hoverOptions = options.hover; + if (lastActive.length) { + me.updateHoverStyle(lastActive, hoverOptions.mode, false); + } + if (active.length && hoverOptions.mode) { + me.updateHoverStyle(active, hoverOptions.mode, true); + } + } + _eventHandler(e, replay) { + const me = this; + if (me._plugins.notify(me, 'beforeEvent', [e, replay]) === false) { + return; + } + me._handleEvent(e, replay); + me._plugins.notify(me, 'afterEvent', [e, replay]); + me.render(); + return me; + } + _handleEvent(e, replay) { + const me = this; + const lastActive = me._active || []; + const options = me.options; + const hoverOptions = options.hover; + const useFinalPosition = replay; + let active = []; + let changed = false; + if (e.type === 'mouseout') { + me._lastEvent = null; + } else { + active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); + me._lastEvent = e.type === 'click' ? me._lastEvent : e; + } + callback(options.onHover || options.hover.onHover, [e, active, me], me); + if (e.type === 'mouseup' || e.type === 'click') { + if (_isPointInArea(e, me.chartArea)) { + callback(options.onClick, [e, active, me], me); + } + } + changed = !_elementsEqual(active, lastActive); + if (changed || replay) { + me._active = active; + me._updateHoverStyles(active, lastActive); + } + return changed; + } +} +Chart.defaults = defaults; +Chart.instances = {}; +Chart.registry = registry; +Chart.version = version; +const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate()); +Chart.register = (...items) => { + registry.add(...items); + invalidatePlugins(); +}; +Chart.unregister = (...items) => { + registry.remove(...items); + invalidatePlugins(); +}; + +const TAU = Math.PI * 2; +function clipArc(ctx, element) { + const {startAngle, endAngle, pixelMargin, x, y, outerRadius, innerRadius} = element; + let angleMargin = pixelMargin / outerRadius; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (innerRadius > pixelMargin) { + angleMargin = pixelMargin / innerRadius; + ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); + } else { + ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2); + } + ctx.closePath(); + ctx.clip(); +} +function pathArc(ctx, element) { + const {x, y, startAngle, endAngle, pixelMargin} = element; + const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); + const innerRadius = element.innerRadius + pixelMargin; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, endAngle); + ctx.arc(x, y, innerRadius, endAngle, startAngle, true); + ctx.closePath(); +} +function drawArc(ctx, element) { + if (element.fullCircles) { + element.endAngle = element.startAngle + TAU; + pathArc(ctx, element); + for (let i = 0; i < element.fullCircles; ++i) { + ctx.fill(); + } + element.endAngle = element.startAngle + element.circumference % TAU; + } + pathArc(ctx, element); + ctx.fill(); +} +function drawFullCircleBorders(ctx, element, inner) { + const {x, y, startAngle, endAngle, pixelMargin} = element; + const outerRadius = Math.max(element.outerRadius - pixelMargin, 0); + const innerRadius = element.innerRadius + pixelMargin; + let i; + if (inner) { + element.endAngle = element.startAngle + TAU; + clipArc(ctx, element); + element.endAngle = endAngle; + if (element.endAngle === element.startAngle) { + element.endAngle += TAU; + element.fullCircles--; + } + } + ctx.beginPath(); + ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true); + for (i = 0; i < element.fullCircles; ++i) { + ctx.stroke(); + } + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU); + for (i = 0; i < element.fullCircles; ++i) { + ctx.stroke(); + } +} +function drawBorder(ctx, element) { + const {x, y, startAngle, endAngle, pixelMargin, options} = element; + const outerRadius = element.outerRadius; + const innerRadius = element.innerRadius + pixelMargin; + const inner = options.borderAlign === 'inner'; + if (!options.borderWidth) { + return; + } + if (inner) { + ctx.lineWidth = options.borderWidth * 2; + ctx.lineJoin = 'round'; + } else { + ctx.lineWidth = options.borderWidth; + ctx.lineJoin = 'bevel'; + } + if (element.fullCircles) { + drawFullCircleBorders(ctx, element, inner); + } + if (inner) { + clipArc(ctx, element); + } + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, endAngle); + ctx.arc(x, y, innerRadius, endAngle, startAngle, true); + ctx.closePath(); + ctx.stroke(); +} +class Arc extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.circumference = undefined; + this.startAngle = undefined; + this.endAngle = undefined; + this.innerRadius = undefined; + this.outerRadius = undefined; + this.pixelMargin = 0; + this.fullCircles = 0; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(chartX, chartY, useFinalPosition) { + const point = this.getProps(['x', 'y'], useFinalPosition); + const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY}); + const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([ + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius', + 'circumference' + ], useFinalPosition); + const betweenAngles = circumference >= TAU || _angleBetween(angle, startAngle, endAngle); + const withinRadius = (distance >= innerRadius && distance <= outerRadius); + return (betweenAngles && withinRadius); + } + getCenterPoint(useFinalPosition) { + const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([ + 'x', + 'y', + 'startAngle', + 'endAngle', + 'innerRadius', + 'outerRadius' + ], useFinalPosition); + const halfAngle = (startAngle + endAngle) / 2; + const halfRadius = (innerRadius + outerRadius) / 2; + return { + x: x + Math.cos(halfAngle) * halfRadius, + y: y + Math.sin(halfAngle) * halfRadius + }; + } + tooltipPosition(useFinalPosition) { + return this.getCenterPoint(useFinalPosition); + } + draw(ctx) { + const me = this; + const options = me.options; + const offset = options.offset || 0; + me.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0; + me.fullCircles = Math.floor(me.circumference / TAU); + if (me.circumference === 0) { + return; + } + ctx.save(); + if (offset && me.circumference < TAU) { + const halfAngle = (me.startAngle + me.endAngle) / 2; + ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset); + } + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + drawArc(ctx, me); + drawBorder(ctx, me); + ctx.restore(); + } +} +Arc.id = 'arc'; +Arc.defaults = { + borderAlign: 'center', + borderColor: '#fff', + borderWidth: 2, + offset: 0 +}; +Arc.defaultRoutes = { + backgroundColor: 'color' +}; + +function setStyle(ctx, vm) { + ctx.lineCap = vm.borderCapStyle; + ctx.setLineDash(vm.borderDash); + ctx.lineDashOffset = vm.borderDashOffset; + ctx.lineJoin = vm.borderJoinStyle; + ctx.lineWidth = vm.borderWidth; + ctx.strokeStyle = vm.borderColor; +} +function lineTo(ctx, previous, target) { + ctx.lineTo(target.x, target.y); +} +function getLineMethod(options) { + if (options.stepped) { + return _steppedLineTo; + } + if (options.tension) { + return _bezierCurveTo; + } + return lineTo; +} +function pathVars(points, segment, params) { + params = params || {}; + const count = points.length; + const start = Math.max(params.start || 0, segment.start); + const end = Math.min(params.end || count - 1, segment.end); + return { + count, + start, + loop: segment.loop, + ilen: end < start ? count + end - start : end - start + }; +} +function pathSegment(ctx, line, segment, params) { + const {points, options} = line; + const {count, start, loop, ilen} = pathVars(points, segment, params); + const lineMethod = getLineMethod(options); + let {move = true, reverse} = params || {}; + let i, point, prev; + for (i = 0; i <= ilen; ++i) { + point = points[(start + (reverse ? ilen - i : i)) % count]; + if (point.skip) { + continue; + } else if (move) { + ctx.moveTo(point.x, point.y); + move = false; + } else { + lineMethod(ctx, prev, point, reverse, options.stepped); + } + prev = point; + } + if (loop) { + point = points[(start + (reverse ? ilen : 0)) % count]; + lineMethod(ctx, prev, point, reverse, options.stepped); + } + return !!loop; +} +function fastPathSegment(ctx, line, segment, params) { + const points = line.points; + const {count, start, ilen} = pathVars(points, segment, params); + const {move = true, reverse} = params || {}; + let avgX = 0; + let countX = 0; + let i, point, prevX, minY, maxY, lastY; + const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count; + const drawX = () => { + if (minY !== maxY) { + ctx.lineTo(avgX, maxY); + ctx.lineTo(avgX, minY); + ctx.lineTo(avgX, lastY); + } + }; + if (move) { + point = points[pointIndex(0)]; + ctx.moveTo(point.x, point.y); + } + for (i = 0; i <= ilen; ++i) { + point = points[pointIndex(i)]; + if (point.skip) { + continue; + } + const x = point.x; + const y = point.y; + const truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + avgX = (countX * avgX + x) / ++countX; + } else { + drawX(); + ctx.lineTo(x, y); + prevX = truncX; + countX = 0; + minY = maxY = y; + } + lastY = y; + } + drawX(); +} +function _getSegmentMethod(line) { + const opts = line.options; + const borderDash = opts.borderDash && opts.borderDash.length; + const useFastPath = !line._loop && !opts.tension && !opts.stepped && !borderDash; + return useFastPath ? fastPathSegment : pathSegment; +} +function _getInterpolationMethod(options) { + if (options.stepped) { + return _steppedInterpolation; + } + if (options.tension) { + return _bezierInterpolation; + } + return _pointInLine; +} +class Line extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this._loop = undefined; + this._fullLoop = undefined; + this._points = undefined; + this._segments = undefined; + this._pointsUpdated = false; + if (cfg) { + Object.assign(this, cfg); + } + } + updateControlPoints(chartArea) { + const me = this; + const options = me.options; + if (options.tension && !options.stepped && !me._pointsUpdated) { + const loop = options.spanGaps ? me._loop : me._fullLoop; + _updateBezierControlPoints(me._points, options, chartArea, loop); + me._pointsUpdated = true; + } + } + set points(points) { + this._points = points; + delete this._segments; + } + get points() { + return this._points; + } + get segments() { + return this._segments || (this._segments = _computeSegments(this)); + } + first() { + const segments = this.segments; + const points = this.points; + return segments.length && points[segments[0].start]; + } + last() { + const segments = this.segments; + const points = this.points; + const count = segments.length; + return count && points[segments[count - 1].end]; + } + interpolate(point, property) { + const me = this; + const options = me.options; + const value = point[property]; + const points = me.points; + const segments = _boundSegments(me, {property, start: value, end: value}); + if (!segments.length) { + return; + } + const result = []; + const _interpolate = _getInterpolationMethod(options); + let i, ilen; + for (i = 0, ilen = segments.length; i < ilen; ++i) { + const {start, end} = segments[i]; + const p1 = points[start]; + const p2 = points[end]; + if (p1 === p2) { + result.push(p1); + continue; + } + const t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); + const interpolated = _interpolate(p1, p2, t, options.stepped); + interpolated[property] = point[property]; + result.push(interpolated); + } + return result.length === 1 ? result[0] : result; + } + pathSegment(ctx, segment, params) { + const segmentMethod = _getSegmentMethod(this); + return segmentMethod(ctx, this, segment, params); + } + path(ctx, start, count) { + const me = this; + const segments = me.segments; + const ilen = segments.length; + const segmentMethod = _getSegmentMethod(me); + let loop = me._loop; + start = start || 0; + count = count || (me.points.length - start); + for (let i = 0; i < ilen; ++i) { + loop &= segmentMethod(ctx, me, segments[i], {start, end: start + count - 1}); + } + return !!loop; + } + draw(ctx, chartArea, start, count) { + const options = this.options || {}; + const points = this.points || []; + if (!points.length || !options.borderWidth) { + return; + } + ctx.save(); + setStyle(ctx, options); + ctx.beginPath(); + if (this.path(ctx, start, count)) { + ctx.closePath(); + } + ctx.stroke(); + ctx.restore(); + this._pointsUpdated = false; + } +} +Line.id = 'line'; +Line.defaults = { + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: 'miter', + borderWidth: 3, + capBezierPoints: true, + fill: true, + tension: 0 +}; +Line.defaultRoutes = { + backgroundColor: 'color', + borderColor: 'color' +}; + +class Point extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.skip = undefined; + this.stop = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + inRange(mouseX, mouseY, useFinalPosition) { + const options = this.options; + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2)); + } + inXRange(mouseX, useFinalPosition) { + const options = this.options; + const {x} = this.getProps(['x'], useFinalPosition); + return (Math.abs(mouseX - x) < options.radius + options.hitRadius); + } + inYRange(mouseY, useFinalPosition) { + const options = this.options; + const {y} = this.getProps(['x'], useFinalPosition); + return (Math.abs(mouseY - y) < options.radius + options.hitRadius); + } + getCenterPoint(useFinalPosition) { + const {x, y} = this.getProps(['x', 'y'], useFinalPosition); + return {x, y}; + } + size() { + const options = this.options || {}; + const radius = Math.max(options.radius, options.hoverRadius) || 0; + const borderWidth = radius && options.borderWidth || 0; + return (radius + borderWidth) * 2; + } + draw(ctx, chartArea) { + const me = this; + const options = me.options; + if (me.skip || options.radius <= 0) { + return; + } + if (chartArea === undefined || _isPointInArea(me, chartArea)) { + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.fillStyle = options.backgroundColor; + drawPoint(ctx, options, me.x, me.y); + } + } + getRange() { + const options = this.options || {}; + return options.radius + options.hitRadius; + } +} +Point.id = 'point'; +Point.defaults = { + borderWidth: 1, + hitRadius: 1, + hoverBorderWidth: 1, + hoverRadius: 4, + pointStyle: 'circle', + radius: 3 +}; +Point.defaultRoutes = { + backgroundColor: 'color', + borderColor: 'color' +}; + +function getBarBounds(bar, useFinalPosition) { + const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition); + let left, right, top, bottom, half; + if (bar.horizontal) { + half = height / 2; + left = Math.min(x, base); + right = Math.max(x, base); + top = y - half; + bottom = y + half; + } else { + half = width / 2; + left = x - half; + right = x + half; + top = Math.min(y, base); + bottom = Math.max(y, base); + } + return {left, top, right, bottom}; +} +function parseBorderSkipped(bar) { + let edge = bar.options.borderSkipped; + const res = {}; + if (!edge) { + return res; + } + edge = bar.horizontal + ? parseEdge(edge, 'left', 'right', bar.base > bar.x) + : parseEdge(edge, 'bottom', 'top', bar.base < bar.y); + res[edge] = true; + return res; +} +function parseEdge(edge, a, b, reverse) { + if (reverse) { + edge = swap(edge, a, b); + edge = startEnd(edge, b, a); + } else { + edge = startEnd(edge, a, b); + } + return edge; +} +function swap(orig, v1, v2) { + return orig === v1 ? v2 : orig === v2 ? v1 : orig; +} +function startEnd(v, start, end) { + return v === 'start' ? start : v === 'end' ? end : v; +} +function skipOrLimit(skip, value, min, max) { + return skip ? 0 : Math.max(Math.min(value, max), min); +} +function parseBorderWidth(bar, maxW, maxH) { + const value = bar.options.borderWidth; + const skip = parseBorderSkipped(bar); + const o = toTRBL(value); + return { + t: skipOrLimit(skip.top, o.top, 0, maxH), + r: skipOrLimit(skip.right, o.right, 0, maxW), + b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), + l: skipOrLimit(skip.left, o.left, 0, maxW) + }; +} +function boundingRects(bar) { + const bounds = getBarBounds(bar); + const width = bounds.right - bounds.left; + const height = bounds.bottom - bounds.top; + const border = parseBorderWidth(bar, width / 2, height / 2); + return { + outer: { + x: bounds.left, + y: bounds.top, + w: width, + h: height + }, + inner: { + x: bounds.left + border.l, + y: bounds.top + border.t, + w: width - border.l - border.r, + h: height - border.t - border.b + } + }; +} +function inRange(bar, x, y, useFinalPosition) { + const skipX = x === null; + const skipY = y === null; + const skipBoth = skipX && skipY; + const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); + return bounds + && (skipX || x >= bounds.left && x <= bounds.right) + && (skipY || y >= bounds.top && y <= bounds.bottom); +} +class Rectangle extends Element { + constructor(cfg) { + super(); + this.options = undefined; + this.horizontal = undefined; + this.base = undefined; + this.width = undefined; + this.height = undefined; + if (cfg) { + Object.assign(this, cfg); + } + } + draw(ctx) { + const options = this.options; + const {inner, outer} = boundingRects(this); + ctx.save(); + if (outer.w !== inner.w || outer.h !== inner.h) { + ctx.beginPath(); + ctx.rect(outer.x, outer.y, outer.w, outer.h); + ctx.clip(); + ctx.rect(inner.x, inner.y, inner.w, inner.h); + ctx.fillStyle = options.borderColor; + ctx.fill('evenodd'); + } + ctx.fillStyle = options.backgroundColor; + ctx.fillRect(inner.x, inner.y, inner.w, inner.h); + ctx.restore(); + } + inRange(mouseX, mouseY, useFinalPosition) { + return inRange(this, mouseX, mouseY, useFinalPosition); + } + inXRange(mouseX, useFinalPosition) { + return inRange(this, mouseX, null, useFinalPosition); + } + inYRange(mouseY, useFinalPosition) { + return inRange(this, null, mouseY, useFinalPosition); + } + getCenterPoint(useFinalPosition) { + const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition); + return { + x: horizontal ? (x + base) / 2 : x, + y: horizontal ? y : (y + base) / 2 + }; + } + getRange(axis) { + return axis === 'x' ? this.width / 2 : this.height / 2; + } +} +Rectangle.id = 'rectangle'; +Rectangle.defaults = { + borderSkipped: 'start', + borderWidth: 0 +}; +Rectangle.defaultRoutes = { + backgroundColor: 'color', + borderColor: 'color' +}; + +function getLineByIndex(chart, index) { + const meta = chart.getDatasetMeta(index); + const visible = meta && chart.isDatasetVisible(index); + return visible ? meta.dataset : null; +} +function parseFillOption(line) { + const options = line.options; + const fillOption = options.fill; + let fill = valueOrDefault(fillOption && fillOption.target, fillOption); + if (fill === undefined) { + fill = !!options.backgroundColor; + } + if (fill === false || fill === null) { + return false; + } + if (fill === true) { + return 'origin'; + } + return fill; +} +function decodeFill(line, index, count) { + const fill = parseFillOption(line); + let target = parseFloat(fill); + if (isNumberFinite(target) && Math.floor(target) === target) { + if (fill[0] === '-' || fill[0] === '+') { + target = index + target; + } + if (target === index || target < 0 || target >= count) { + return false; + } + return target; + } + return ['origin', 'start', 'end', 'stack'].indexOf(fill) >= 0 && fill; +} +function computeLinearBoundary(source) { + const {scale = {}, fill} = source; + let target = null; + let horizontal; + if (fill === 'start') { + target = scale.bottom; + } else if (fill === 'end') { + target = scale.top; + } else if (scale.getBasePixel) { + target = scale.getBasePixel(); + } + if (isNumberFinite(target)) { + horizontal = scale.isHorizontal(); + return { + x: horizontal ? target : null, + y: horizontal ? null : target + }; + } + return null; +} +class simpleArc { + constructor(opts) { + this.x = opts.x; + this.y = opts.y; + this.radius = opts.radius; + } + pathSegment(ctx, bounds, opts) { + const {x, y, radius} = this; + bounds = bounds || {start: 0, end: Math.PI * 2}; + if (opts.reverse) { + ctx.arc(x, y, radius, bounds.end, bounds.start, true); + } else { + ctx.arc(x, y, radius, bounds.start, bounds.end); + } + return !opts.bounds; + } + interpolate(point, property) { + const {x, y, radius} = this; + const angle = point.angle; + if (property === 'angle') { + return { + x: x + Math.cos(angle) * radius, + y: y + Math.sin(angle) * radius, + angle + }; + } + } +} +function computeCircularBoundary(source) { + const {scale, fill} = source; + const options = scale.options; + const length = scale.getLabels().length; + const target = []; + const start = options.reverse ? scale.max : scale.min; + const end = options.reverse ? scale.min : scale.max; + const value = fill === 'start' ? start : fill === 'end' ? end : scale.getBaseValue(); + let i, center; + if (options.gridLines.circular) { + center = scale.getPointPositionForValue(0, start); + return new simpleArc({ + x: center.x, + y: center.y, + radius: scale.getDistanceFromCenterForValue(value) + }); + } + for (i = 0; i < length; ++i) { + target.push(scale.getPointPositionForValue(i, value)); + } + return target; +} +function computeBoundary(source) { + const scale = source.scale || {}; + if (scale.getPointPositionForValue) { + return computeCircularBoundary(source); + } + return computeLinearBoundary(source); +} +function pointsFromSegments(boundary, line) { + const {x = null, y = null} = boundary || {}; + const linePoints = line.points; + const points = []; + line.segments.forEach((segment) => { + const first = linePoints[segment.start]; + const last = linePoints[segment.end]; + if (y !== null) { + points.push({x: first.x, y}); + points.push({x: last.x, y}); + } else if (x !== null) { + points.push({x, y: first.y}); + points.push({x, y: last.y}); + } + }); + return points; +} +function buildStackLine(source) { + const {chart, scale, index, line} = source; + const points = []; + const segments = line.segments; + const sourcePoints = line.points; + const linesBelow = getLinesBelow(chart, index); + linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line)); + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + for (let j = segment.start; j <= segment.end; j++) { + addPointsBelow(points, sourcePoints[j], linesBelow); + } + } + return new Line({points, options: {}}); +} +const isLineAndNotInHideAnimation = (meta) => meta.type === 'line' && !meta.hidden; +function getLinesBelow(chart, index) { + const below = []; + const metas = chart.getSortedVisibleDatasetMetas(); + for (let i = 0; i < metas.length; i++) { + const meta = metas[i]; + if (meta.index === index) { + break; + } + if (isLineAndNotInHideAnimation(meta)) { + below.unshift(meta.dataset); + } + } + return below; +} +function addPointsBelow(points, sourcePoint, linesBelow) { + const postponed = []; + for (let j = 0; j < linesBelow.length; j++) { + const line = linesBelow[j]; + const {first, last, point} = findPoint(line, sourcePoint, 'x'); + if (!point || (first && last)) { + continue; + } + if (first) { + postponed.unshift(point); + } else { + points.push(point); + if (!last) { + break; + } + } + } + points.push(...postponed); +} +function findPoint(line, sourcePoint, property) { + const point = line.interpolate(sourcePoint, property); + if (!point) { + return {}; + } + const pointValue = point[property]; + const segments = line.segments; + const linePoints = line.points; + let first = false; + let last = false; + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + const firstValue = linePoints[segment.start][property]; + const lastValue = linePoints[segment.end][property]; + if (pointValue >= firstValue && pointValue <= lastValue) { + first = pointValue === firstValue; + last = pointValue === lastValue; + break; + } + } + return {first, last, point}; +} +function getTarget(source) { + const {chart, fill, line} = source; + if (isNumberFinite(fill)) { + return getLineByIndex(chart, fill); + } + if (fill === 'stack') { + return buildStackLine(source); + } + const boundary = computeBoundary(source); + if (boundary instanceof simpleArc) { + return boundary; + } + return createBoundaryLine(boundary, line); +} +function createBoundaryLine(boundary, line) { + let points = []; + let _loop = false; + if (isArray(boundary)) { + _loop = true; + points = boundary; + } else { + points = pointsFromSegments(boundary, line); + } + return points.length ? new Line({ + points, + options: {tension: 0}, + _loop, + _fullLoop: _loop + }) : null; +} +function resolveTarget(sources, index, propagate) { + const source = sources[index]; + let fill = source.fill; + const visited = [index]; + let target; + if (!propagate) { + return fill; + } + while (fill !== false && visited.indexOf(fill) === -1) { + if (!isNumberFinite(fill)) { + return fill; + } + target = sources[fill]; + if (!target) { + return false; + } + if (target.visible) { + return fill; + } + visited.push(fill); + fill = target.fill; + } + return false; +} +function _clip(ctx, target, clipY) { + ctx.beginPath(); + target.path(ctx); + ctx.lineTo(target.last().x, clipY); + ctx.lineTo(target.first().x, clipY); + ctx.closePath(); + ctx.clip(); +} +function getBounds(property, first, last, loop) { + if (loop) { + return; + } + let start = first[property]; + let end = last[property]; + if (property === 'angle') { + start = _normalizeAngle(start); + end = _normalizeAngle(end); + } + return {property, start, end}; +} +function _getEdge(a, b, prop, fn) { + if (a && b) { + return fn(a[prop], b[prop]); + } + return a ? a[prop] : b ? b[prop] : 0; +} +function _segments(line, target, property) { + const segments = line.segments; + const points = line.points; + const tpoints = target.points; + const parts = []; + for (let i = 0; i < segments.length; i++) { + const segment = segments[i]; + const bounds = getBounds(property, points[segment.start], points[segment.end], segment.loop); + if (!target.segments) { + parts.push({ + source: segment, + target: bounds, + start: points[segment.start], + end: points[segment.end] + }); + continue; + } + const subs = _boundSegments(target, bounds); + for (let j = 0; j < subs.length; ++j) { + const sub = subs[j]; + const subBounds = getBounds(property, tpoints[sub.start], tpoints[sub.end], sub.loop); + const fillSources = _boundSegment(segment, points, subBounds); + for (let k = 0; k < fillSources.length; k++) { + parts.push({ + source: fillSources[k], + target: sub, + start: { + [property]: _getEdge(bounds, subBounds, 'start', Math.max) + }, + end: { + [property]: _getEdge(bounds, subBounds, 'end', Math.min) + } + }); + } + } + } + return parts; +} +function clipBounds(ctx, scale, bounds) { + const {top, bottom} = scale.chart.chartArea; + const {property, start, end} = bounds || {}; + if (property === 'x') { + ctx.beginPath(); + ctx.rect(start, top, end - start, bottom - top); + ctx.clip(); + } +} +function interpolatedLineTo(ctx, target, point, property) { + const interpolatedPoint = target.interpolate(point, property); + if (interpolatedPoint) { + ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); + } +} +function _fill(ctx, cfg) { + const {line, target, property, color, scale} = cfg; + const segments = _segments(line, target, property); + ctx.fillStyle = color; + for (let i = 0, ilen = segments.length; i < ilen; ++i) { + const {source: src, target: tgt, start, end} = segments[i]; + ctx.save(); + clipBounds(ctx, scale, getBounds(property, start, end)); + ctx.beginPath(); + const lineLoop = !!line.pathSegment(ctx, src); + if (lineLoop) { + ctx.closePath(); + } else { + interpolatedLineTo(ctx, target, end, property); + } + const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true}); + const loop = lineLoop && targetLoop; + if (!loop) { + interpolatedLineTo(ctx, target, start, property); + } + ctx.closePath(); + ctx.fill(loop ? 'evenodd' : 'nonzero'); + ctx.restore(); + } +} +function doFill(ctx, cfg) { + const {line, target, above, below, area, scale} = cfg; + const property = line._loop ? 'angle' : 'x'; + ctx.save(); + if (property === 'x' && below !== above) { + _clip(ctx, target, area.top); + _fill(ctx, {line, target, color: above, scale, property}); + ctx.restore(); + ctx.save(); + _clip(ctx, target, area.bottom); + } + _fill(ctx, {line, target, color: below, scale, property}); + ctx.restore(); +} +var plugin_filler = { + id: 'filler', + afterDatasetsUpdate(chart, options) { + const count = (chart.data.datasets || []).length; + const propagate = options.propagate; + const sources = []; + let meta, i, line, source; + for (i = 0; i < count; ++i) { + meta = chart.getDatasetMeta(i); + line = meta.dataset; + source = null; + if (line && line.options && line instanceof Line) { + source = { + visible: chart.isDatasetVisible(i), + index: i, + fill: decodeFill(line, i, count), + chart, + scale: meta.vScale, + line + }; + } + meta.$filler = source; + sources.push(source); + } + for (i = 0; i < count; ++i) { + source = sources[i]; + if (!source || source.fill === false) { + continue; + } + source.fill = resolveTarget(sources, i, propagate); + } + }, + beforeDatasetsDraw(chart) { + const metasets = chart.getSortedVisibleDatasetMetas(); + const area = chart.chartArea; + let i, meta; + for (i = metasets.length - 1; i >= 0; --i) { + meta = metasets[i].$filler; + if (meta) { + meta.line.updateControlPoints(area); + } + } + }, + beforeDatasetDraw(chart, args) { + const area = chart.chartArea; + const ctx = chart.ctx; + const source = args.meta.$filler; + if (!source || source.fill === false) { + return; + } + const target = getTarget(source); + const {line, scale} = source; + const lineOpts = line.options; + const fillOption = lineOpts.fill; + const color = lineOpts.backgroundColor; + const {above = color, below = color} = fillOption || {}; + if (target && line.points.length) { + clipArea(ctx, area); + doFill(ctx, {line, target, above, below, area, scale}); + unclipArea(ctx); + } + }, + defaults: { + propagate: true + } +}; + +function getBoxWidth(labelOpts, fontSize) { + const {boxWidth} = labelOpts; + return (labelOpts.usePointStyle && boxWidth > fontSize) || isNullOrUndef(boxWidth) ? + fontSize : + boxWidth; +} +function getBoxHeight(labelOpts, fontSize) { + const {boxHeight} = labelOpts; + return (labelOpts.usePointStyle && boxHeight > fontSize) || isNullOrUndef(boxHeight) ? + fontSize : + boxHeight; +} +class Legend extends Element { + constructor(config) { + super(); + Object.assign(this, config); + this.legendHitBoxes = []; + this._hoveredItem = null; + this.doughnutMode = false; + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this.legendItems = undefined; + this.columnWidths = undefined; + this.columnHeights = undefined; + this.lineWidths = undefined; + this._minSize = undefined; + this.maxHeight = undefined; + this.maxWidth = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.height = undefined; + this.width = undefined; + this._margins = undefined; + this.paddingTop = undefined; + this.paddingBottom = undefined; + this.paddingLeft = undefined; + this.paddingRight = undefined; + this.position = undefined; + this.weight = undefined; + this.fullWidth = undefined; + } + beforeUpdate() {} + update(maxWidth, maxHeight, margins) { + const me = this; + me.beforeUpdate(); + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me._margins = margins; + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + me.beforeBuildLabels(); + me.buildLabels(); + me.afterBuildLabels(); + me.beforeFit(); + me.fit(); + me.afterFit(); + me.afterUpdate(); + } + afterUpdate() {} + beforeSetDimensions() {} + setDimensions() { + const me = this; + if (me.isHorizontal()) { + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + me.top = 0; + me.bottom = me.height; + } + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + me._minSize = { + width: 0, + height: 0 + }; + } + afterSetDimensions() {} + beforeBuildLabels() {} + buildLabels() { + const me = this; + const labelOpts = me.options.labels || {}; + let legendItems = callback(labelOpts.generateLabels, [me.chart], me) || []; + if (labelOpts.filter) { + legendItems = legendItems.filter((item) => labelOpts.filter(item, me.chart.data)); + } + if (me.options.reverse) { + legendItems.reverse(); + } + me.legendItems = legendItems; + } + afterBuildLabels() {} + beforeFit() {} + fit() { + const me = this; + const opts = me.options; + const labelOpts = opts.labels; + const display = opts.display; + const ctx = me.ctx; + const labelFont = toFont(labelOpts.font, me.chart.options.font); + const fontSize = labelFont.size; + const boxWidth = getBoxWidth(labelOpts, fontSize); + const boxHeight = getBoxHeight(labelOpts, fontSize); + const itemHeight = Math.max(boxHeight, fontSize); + const hitboxes = me.legendHitBoxes = []; + const minSize = me._minSize; + const isHorizontal = me.isHorizontal(); + const titleHeight = me._computeTitleHeight(); + if (isHorizontal) { + minSize.width = me.maxWidth; + minSize.height = display ? 10 : 0; + } else { + minSize.width = display ? 10 : 0; + minSize.height = me.maxHeight; + } + if (!display) { + me.width = minSize.width = me.height = minSize.height = 0; + return; + } + ctx.font = labelFont.string; + if (isHorizontal) { + const lineWidths = me.lineWidths = [0]; + let totalHeight = titleHeight; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + me.legendItems.forEach((legendItem, i) => { + const width = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (i === 0 || lineWidths[lineWidths.length - 1] + width + 2 * labelOpts.padding > minSize.width) { + totalHeight += itemHeight + labelOpts.padding; + lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; + } + hitboxes[i] = { + left: 0, + top: 0, + width, + height: itemHeight + }; + lineWidths[lineWidths.length - 1] += width + labelOpts.padding; + }); + minSize.height += totalHeight; + } else { + const vPadding = labelOpts.padding; + const columnWidths = me.columnWidths = []; + const columnHeights = me.columnHeights = []; + let totalWidth = labelOpts.padding; + let currentColWidth = 0; + let currentColHeight = 0; + const heightLimit = minSize.height - titleHeight; + me.legendItems.forEach((legendItem, i) => { + const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width; + if (i > 0 && currentColHeight + fontSize + 2 * vPadding > heightLimit) { + totalWidth += currentColWidth + labelOpts.padding; + columnWidths.push(currentColWidth); + columnHeights.push(currentColHeight); + currentColWidth = 0; + currentColHeight = 0; + } + currentColWidth = Math.max(currentColWidth, itemWidth); + currentColHeight += fontSize + vPadding; + hitboxes[i] = { + left: 0, + top: 0, + width: itemWidth, + height: itemHeight, + }; + }); + totalWidth += currentColWidth; + columnWidths.push(currentColWidth); + columnHeights.push(currentColHeight); + minSize.width += totalWidth; + } + me.width = minSize.width; + me.height = minSize.height; + } + afterFit() {} + isHorizontal() { + return this.options.position === 'top' || this.options.position === 'bottom'; + } + draw() { + const me = this; + const opts = me.options; + const labelOpts = opts.labels; + const defaultColor = defaults.color; + const legendHeight = me.height; + const columnHeights = me.columnHeights; + const legendWidth = me.width; + const lineWidths = me.lineWidths; + if (!opts.display) { + return; + } + me.drawTitle(); + const rtlHelper = getRtlAdapter(opts.rtl, me.left, me._minSize.width); + const ctx = me.ctx; + const labelFont = toFont(labelOpts.font, me.chart.options.font); + const fontColor = labelFont.color; + const fontSize = labelFont.size; + let cursor; + ctx.textAlign = rtlHelper.textAlign('left'); + ctx.textBaseline = 'middle'; + ctx.lineWidth = 0.5; + ctx.strokeStyle = fontColor; + ctx.fillStyle = fontColor; + ctx.font = labelFont.string; + const boxWidth = getBoxWidth(labelOpts, fontSize); + const boxHeight = getBoxHeight(labelOpts, fontSize); + const height = Math.max(fontSize, boxHeight); + const hitboxes = me.legendHitBoxes; + const drawLegendBox = function(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { + return; + } + ctx.save(); + const lineWidth = valueOrDefault(legendItem.lineWidth, 1); + ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); + ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); + ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); + ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); + ctx.lineWidth = lineWidth; + ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); + if (ctx.setLineDash) { + ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); + } + if (labelOpts && labelOpts.usePointStyle) { + const drawOptions = { + radius: boxWidth * Math.SQRT2 / 2, + pointStyle: legendItem.pointStyle, + rotation: legendItem.rotation, + borderWidth: lineWidth + }; + const centerX = rtlHelper.xPlus(x, boxWidth / 2); + const centerY = y + fontSize / 2; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); + ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight); + if (lineWidth !== 0) { + ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight); + } + } + ctx.restore(); + }; + const fillText = function(x, y, legendItem, textWidth) { + const halfFontSize = fontSize / 2; + const xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize); + const yMiddle = y + (height / 2); + ctx.fillText(legendItem.text, xLeft, yMiddle); + if (legendItem.hidden) { + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.moveTo(xLeft, yMiddle); + ctx.lineTo(rtlHelper.xPlus(xLeft, textWidth), yMiddle); + ctx.stroke(); + } + }; + const alignmentOffset = function(dimension, blockSize) { + switch (opts.align) { + case 'start': + return labelOpts.padding; + case 'end': + return dimension - blockSize; + default: + return (dimension - blockSize + labelOpts.padding) / 2; + } + }; + const isHorizontal = me.isHorizontal(); + const titleHeight = this._computeTitleHeight(); + if (isHorizontal) { + cursor = { + x: me.left + alignmentOffset(legendWidth, lineWidths[0]), + y: me.top + labelOpts.padding + titleHeight, + line: 0 + }; + } else { + cursor = { + x: me.left + labelOpts.padding, + y: me.top + alignmentOffset(legendHeight, columnHeights[0]) + titleHeight, + line: 0 + }; + } + overrideTextDirection(me.ctx, opts.textDirection); + const itemHeight = height + labelOpts.padding; + me.legendItems.forEach((legendItem, i) => { + const textWidth = ctx.measureText(legendItem.text).width; + const width = boxWidth + (fontSize / 2) + textWidth; + let x = cursor.x; + let y = cursor.y; + rtlHelper.setWidth(me._minSize.width); + if (isHorizontal) { + if (i > 0 && x + width + labelOpts.padding > me.left + me._minSize.width) { + y = cursor.y += itemHeight; + cursor.line++; + x = cursor.x = me.left + alignmentOffset(legendWidth, lineWidths[cursor.line]); + } + } else if (i > 0 && y + itemHeight > me.top + me._minSize.height) { + x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding; + cursor.line++; + y = cursor.y = me.top + alignmentOffset(legendHeight, columnHeights[cursor.line]); + } + const realX = rtlHelper.x(x); + drawLegendBox(realX, y, legendItem); + hitboxes[i].left = rtlHelper.leftForLtr(realX, hitboxes[i].width); + hitboxes[i].top = y; + fillText(realX, y, legendItem, textWidth); + if (isHorizontal) { + cursor.x += width + labelOpts.padding; + } else { + cursor.y += itemHeight; + } + }); + restoreTextDirection(me.ctx, opts.textDirection); + } + drawTitle() { + const me = this; + const opts = me.options; + const titleOpts = opts.title; + const titleFont = toFont(titleOpts.font, me.chart.options.font); + const titlePadding = toPadding(titleOpts.padding); + if (!titleOpts.display) { + return; + } + const rtlHelper = getRtlAdapter(opts.rtl, me.left, me._minSize.width); + const ctx = me.ctx; + const position = titleOpts.position; + let x, textAlign; + const halfFontSize = titleFont.size / 2; + let y = me.top + titlePadding.top + halfFontSize; + let left = me.left; + let maxWidth = me.width; + if (this.isHorizontal()) { + maxWidth = Math.max(...me.lineWidths); + switch (opts.align) { + case 'start': + break; + case 'end': + left = me.right - maxWidth; + break; + default: + left = ((me.left + me.right) / 2) - (maxWidth / 2); + break; + } + } else { + const maxHeight = Math.max(...me.columnHeights); + switch (opts.align) { + case 'start': + break; + case 'end': + y += me.height - maxHeight; + break; + default: + y += (me.height - maxHeight) / 2; + break; + } + } + switch (position) { + case 'start': + x = left; + textAlign = 'left'; + break; + case 'end': + x = left + maxWidth; + textAlign = 'right'; + break; + default: + x = left + (maxWidth / 2); + textAlign = 'center'; + break; + } + ctx.textAlign = rtlHelper.textAlign(textAlign); + ctx.textBaseline = 'middle'; + ctx.strokeStyle = titleFont.color; + ctx.fillStyle = titleFont.color; + ctx.font = titleFont.string; + ctx.fillText(titleOpts.text, x, y); + } + _computeTitleHeight() { + const titleOpts = this.options.title; + const titleFont = toFont(titleOpts.font, this.chart.options.font); + const titlePadding = toPadding(titleOpts.padding); + return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; + } + _getLegendItemAt(x, y) { + const me = this; + let i, hitBox, lh; + if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) { + lh = me.legendHitBoxes; + for (i = 0; i < lh.length; ++i) { + hitBox = lh[i]; + if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) { + return me.legendItems[i]; + } + } + } + return null; + } + handleEvent(e) { + const me = this; + const opts = me.options; + const type = e.type === 'mouseup' ? 'click' : e.type; + if (type === 'mousemove') { + if (!opts.onHover && !opts.onLeave) { + return; + } + } else if (type === 'click') { + if (!opts.onClick) { + return; + } + } else { + return; + } + const hoveredItem = me._getLegendItemAt(e.x, e.y); + if (type === 'click') { + if (hoveredItem) { + callback(opts.onClick, [e, hoveredItem, me], me); + } + } else { + if (opts.onLeave && hoveredItem !== me._hoveredItem) { + if (me._hoveredItem) { + callback(opts.onLeave, [e, me._hoveredItem, me], me); + } + me._hoveredItem = hoveredItem; + } + if (hoveredItem) { + callback(opts.onHover, [e, hoveredItem, me], me); + } + } + } +} +function resolveOptions(options) { + return options !== false && merge({}, [defaults.plugins.legend, options]); +} +function createNewLegendAndAttach(chart, legendOpts) { + const legend = new Legend({ + ctx: chart.ctx, + options: legendOpts, + chart + }); + layouts.configure(chart, legend, legendOpts); + layouts.addBox(chart, legend); + chart.legend = legend; +} +var plugin_legend = { + id: 'legend', + _element: Legend, + beforeInit(chart) { + const legendOpts = resolveOptions(chart.options.legend); + if (legendOpts) { + createNewLegendAndAttach(chart, legendOpts); + } + }, + beforeUpdate(chart) { + const legendOpts = resolveOptions(chart.options.legend); + const legend = chart.legend; + if (legendOpts) { + if (legend) { + layouts.configure(chart, legend, legendOpts); + legend.options = legendOpts; + } else { + createNewLegendAndAttach(chart, legendOpts); + } + } else if (legend) { + layouts.removeBox(chart, legend); + delete chart.legend; + } + }, + afterUpdate(chart) { + if (chart.legend) { + chart.legend.buildLabels(); + } + }, + afterEvent(chart, e) { + const legend = chart.legend; + if (legend) { + legend.handleEvent(e); + } + }, + defaults: { + display: true, + position: 'top', + align: 'center', + fullWidth: true, + reverse: false, + weight: 1000, + onClick(e, legendItem, legend) { + const index = legendItem.datasetIndex; + const ci = legend.chart; + if (ci.isDatasetVisible(index)) { + ci.hide(index); + legendItem.hidden = true; + } else { + ci.show(index); + legendItem.hidden = false; + } + }, + onHover: null, + onLeave: null, + labels: { + boxWidth: 40, + padding: 10, + generateLabels(chart) { + const datasets = chart.data.datasets; + const options = chart.options.legend || {}; + const usePointStyle = options.labels && options.labels.usePointStyle; + return chart._getSortedDatasetMetas().map((meta) => { + const style = meta.controller.getStyle(usePointStyle ? 0 : undefined); + return { + text: datasets[meta.index].label, + fillStyle: style.backgroundColor, + hidden: !meta.visible, + lineCap: style.borderCapStyle, + lineDash: style.borderDash, + lineDashOffset: style.borderDashOffset, + lineJoin: style.borderJoinStyle, + lineWidth: style.borderWidth, + strokeStyle: style.borderColor, + pointStyle: style.pointStyle, + rotation: style.rotation, + datasetIndex: meta.index + }; + }, this); + } + }, + title: { + display: false, + position: 'center', + text: '', + } + } +}; + +class Title extends Element { + constructor(config) { + super(); + Object.assign(this, config); + this.chart = config.chart; + this.options = config.options; + this.ctx = config.ctx; + this._margins = undefined; + this._padding = undefined; + this.top = undefined; + this.bottom = undefined; + this.left = undefined; + this.right = undefined; + this.width = undefined; + this.height = undefined; + this.maxWidth = undefined; + this.maxHeight = undefined; + this.position = undefined; + this.weight = undefined; + this.fullWidth = undefined; + } + beforeUpdate() {} + update(maxWidth, maxHeight, margins) { + const me = this; + me.beforeUpdate(); + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me._margins = margins; + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + me.beforeBuildLabels(); + me.buildLabels(); + me.afterBuildLabels(); + me.beforeFit(); + me.fit(); + me.afterFit(); + me.afterUpdate(); + } + afterUpdate() {} + beforeSetDimensions() {} + setDimensions() { + const me = this; + if (me.isHorizontal()) { + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + me.top = 0; + me.bottom = me.height; + } + } + afterSetDimensions() {} + beforeBuildLabels() {} + buildLabels() {} + afterBuildLabels() {} + beforeFit() {} + fit() { + const me = this; + const opts = me.options; + const minSize = {}; + const isHorizontal = me.isHorizontal(); + if (!opts.display) { + me.width = minSize.width = me.height = minSize.height = 0; + return; + } + const lineCount = isArray(opts.text) ? opts.text.length : 1; + me._padding = toPadding(opts.padding); + const textSize = lineCount * toFont(opts.font, me.chart.options.font).lineHeight + me._padding.height; + me.width = minSize.width = isHorizontal ? me.maxWidth : textSize; + me.height = minSize.height = isHorizontal ? textSize : me.maxHeight; + } + afterFit() {} + isHorizontal() { + const pos = this.options.position; + return pos === 'top' || pos === 'bottom'; + } + draw() { + const me = this; + const ctx = me.ctx; + const opts = me.options; + if (!opts.display) { + return; + } + const fontOpts = toFont(opts.font, me.chart.options.font); + const lineHeight = fontOpts.lineHeight; + const offset = lineHeight / 2 + me._padding.top; + let rotation = 0; + const top = me.top; + const left = me.left; + const bottom = me.bottom; + const right = me.right; + let maxWidth, titleX, titleY; + let align; + if (me.isHorizontal()) { + switch (opts.align) { + case 'start': + titleX = left; + align = 'left'; + break; + case 'end': + titleX = right; + align = 'right'; + break; + default: + titleX = left + ((right - left) / 2); + align = 'center'; + break; + } + titleY = top + offset; + maxWidth = right - left; + } else { + titleX = opts.position === 'left' ? left + offset : right - offset; + switch (opts.align) { + case 'start': + titleY = opts.position === 'left' ? bottom : top; + align = 'left'; + break; + case 'end': + titleY = opts.position === 'left' ? top : bottom; + align = 'right'; + break; + default: + titleY = top + ((bottom - top) / 2); + align = 'center'; + break; + } + maxWidth = bottom - top; + rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5); + } + ctx.save(); + ctx.fillStyle = fontOpts.color; + ctx.font = fontOpts.string; + ctx.translate(titleX, titleY); + ctx.rotate(rotation); + ctx.textAlign = align; + ctx.textBaseline = 'middle'; + const text = opts.text; + if (isArray(text)) { + let y = 0; + for (let i = 0; i < text.length; ++i) { + ctx.fillText(text[i], 0, y, maxWidth); + y += lineHeight; + } + } else { + ctx.fillText(text, 0, 0, maxWidth); + } + ctx.restore(); + } +} +function createNewTitleBlockAndAttach(chart, titleOpts) { + const title = new Title({ + ctx: chart.ctx, + options: titleOpts, + chart + }); + layouts.configure(chart, title, titleOpts); + layouts.addBox(chart, title); + chart.titleBlock = title; +} +var plugin_title = { + id: 'title', + _element: Title, + beforeInit(chart) { + const titleOpts = chart.options.title; + if (titleOpts) { + createNewTitleBlockAndAttach(chart, titleOpts); + } + }, + beforeUpdate(chart) { + const titleOpts = chart.options.title; + const titleBlock = chart.titleBlock; + if (titleOpts) { + mergeIf(titleOpts, defaults.plugins.title); + if (titleBlock) { + layouts.configure(chart, titleBlock, titleOpts); + titleBlock.options = titleOpts; + } else { + createNewTitleBlockAndAttach(chart, titleOpts); + } + } else if (titleBlock) { + layouts.removeBox(chart, titleBlock); + delete chart.titleBlock; + } + }, + defaults: { + align: 'center', + display: false, + font: { + style: 'bold', + }, + fullWidth: true, + padding: 10, + position: 'top', + text: '', + weight: 2000 + } +}; + +const positioners = { + average(items) { + if (!items.length) { + return false; + } + let i, len; + let x = 0; + let y = 0; + let count = 0; + for (i = 0, len = items.length; i < len; ++i) { + const el = items[i].element; + if (el && el.hasValue()) { + const pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + return { + x: x / count, + y: y / count + }; + }, + nearest(items, eventPosition) { + let x = eventPosition.x; + let y = eventPosition.y; + let minDistance = Number.POSITIVE_INFINITY; + let i, len, nearestElement; + for (i = 0, len = items.length; i < len; ++i) { + const el = items[i].element; + if (el && el.hasValue()) { + const center = el.getCenterPoint(); + const d = distanceBetweenPoints(eventPosition, center); + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + if (nearestElement) { + const tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + return { + x, + y + }; + } +}; +function pushOrConcat(base, toPush) { + if (toPush) { + if (isArray(toPush)) { + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } + } + return base; +} +function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; +} +function createTooltipItem(chart, item) { + const {element, datasetIndex, index} = item; + const controller = chart.getDatasetMeta(datasetIndex).controller; + const {label, value} = controller.getLabelAndValue(index); + return { + chart, + label, + dataPoint: controller.getParsed(index), + formattedValue: value, + dataset: controller.getDataset(), + dataIndex: index, + datasetIndex, + element + }; +} +function resolveOptions$1(options, fallbackFont) { + options = merge({}, [defaults.plugins.tooltip, options]); + options.bodyFont = toFont(options.bodyFont, fallbackFont); + options.titleFont = toFont(options.titleFont, fallbackFont); + options.footerFont = toFont(options.footerFont, fallbackFont); + options.boxHeight = valueOrDefault(options.boxHeight, options.bodyFont.size); + options.boxWidth = valueOrDefault(options.boxWidth, options.bodyFont.size); + return options; +} +function getTooltipSize(tooltip) { + const ctx = tooltip._chart.ctx; + const {body, footer, options, title} = tooltip; + const {bodyFont, footerFont, titleFont, boxWidth, boxHeight} = options; + const titleLineCount = title.length; + const footerLineCount = footer.length; + const bodyLineItemCount = body.length; + let height = options.yPadding * 2; + let width = 0; + let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0); + combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; + if (titleLineCount) { + height += titleLineCount * titleFont.size + + (titleLineCount - 1) * options.titleSpacing + + options.titleMarginBottom; + } + if (combinedBodyLength) { + const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.size) : bodyFont.size; + height += bodyLineItemCount * bodyLineHeight + + (combinedBodyLength - bodyLineItemCount) * bodyFont.size + + (combinedBodyLength - 1) * options.bodySpacing; + } + if (footerLineCount) { + height += options.footerMarginTop + + footerLineCount * footerFont.size + + (footerLineCount - 1) * options.footerSpacing; + } + let widthPadding = 0; + const maxLineWidth = function(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + ctx.save(); + ctx.font = titleFont.string; + each(tooltip.title, maxLineWidth); + ctx.font = bodyFont.string; + each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); + widthPadding = options.displayColors ? (boxWidth + 2) : 0; + each(body, (bodyItem) => { + each(bodyItem.before, maxLineWidth); + each(bodyItem.lines, maxLineWidth); + each(bodyItem.after, maxLineWidth); + }); + widthPadding = 0; + ctx.font = footerFont.string; + each(tooltip.footer, maxLineWidth); + ctx.restore(); + width += 2 * options.xPadding; + return {width, height}; +} +function determineAlignment(chart, options, size) { + const {x, y, width, height} = size; + const chartArea = chart.chartArea; + let xAlign = 'center'; + let yAlign = 'center'; + if (y < height) { + yAlign = 'top'; + } else if (y > (chart.height - height)) { + yAlign = 'bottom'; + } + let lf, rf; + const midX = (chartArea.left + chartArea.right) / 2; + const midY = (chartArea.top + chartArea.bottom) / 2; + if (yAlign === 'center') { + lf = (value) => value <= midX; + rf = (value) => value > midX; + } else { + lf = (value) => value <= (width / 2); + rf = (value) => value >= (chart.width - (width / 2)); + } + const olf = (value) => value + width + options.caretSize + options.caretPadding > chart.width; + const orf = (value) => value - width - options.caretSize - options.caretPadding < 0; + const yf = (value) => value <= midY ? 'top' : 'bottom'; + if (lf(x)) { + xAlign = 'left'; + if (olf(x)) { + xAlign = 'center'; + yAlign = yf(y); + } + } else if (rf(x)) { + xAlign = 'right'; + if (orf(x)) { + xAlign = 'center'; + yAlign = yf(y); + } + } + return { + xAlign: options.xAlign ? options.xAlign : xAlign, + yAlign: options.yAlign ? options.yAlign : yAlign + }; +} +function alignX(size, xAlign, chartWidth) { + let {x, width} = size; + if (xAlign === 'right') { + x -= width; + } else if (xAlign === 'center') { + x -= (width / 2); + if (x + width > chartWidth) { + x = chartWidth - width; + } + if (x < 0) { + x = 0; + } + } + return x; +} +function alignY(size, yAlign, paddingAndSize) { + let {y, height} = size; + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= height + paddingAndSize; + } else { + y -= (height / 2); + } + return y; +} +function getBackgroundPoint(options, size, alignment, chart) { + const {caretSize, caretPadding, cornerRadius} = options; + const {xAlign, yAlign} = alignment; + const paddingAndSize = caretSize + caretPadding; + const radiusAndPadding = cornerRadius + caretPadding; + let x = alignX(size, xAlign, chart.width); + const y = alignY(size, yAlign, paddingAndSize); + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= radiusAndPadding; + } else if (xAlign === 'right') { + x += radiusAndPadding; + } + return {x, y}; +} +function getAlignedX(tooltip, align) { + const options = tooltip.options; + return align === 'center' + ? tooltip.x + tooltip.width / 2 + : align === 'right' + ? tooltip.x + tooltip.width - options.xPadding + : tooltip.x + options.xPadding; +} +function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); +} +class Tooltip extends Element { + constructor(config) { + super(); + this.opacity = 0; + this._active = []; + this._chart = config._chart; + this._eventPosition = undefined; + this._size = undefined; + this._cachedAnimations = undefined; + this.$animations = undefined; + this.options = undefined; + this.dataPoints = undefined; + this.title = undefined; + this.beforeBody = undefined; + this.body = undefined; + this.afterBody = undefined; + this.footer = undefined; + this.xAlign = undefined; + this.yAlign = undefined; + this.x = undefined; + this.y = undefined; + this.height = undefined; + this.width = undefined; + this.caretX = undefined; + this.caretY = undefined; + this.labelColors = undefined; + this.labelTextColors = undefined; + this.initialize(); + } + initialize() { + const me = this; + const chartOpts = me._chart.options; + me.options = resolveOptions$1(chartOpts.tooltips, chartOpts.font); + } + _resolveAnimations() { + const me = this; + const cached = me._cachedAnimations; + if (cached) { + return cached; + } + const chart = me._chart; + const options = me.options; + const opts = options.enabled && chart.options.animation && options.animation; + const animations = new Animations(me._chart, opts); + me._cachedAnimations = Object.freeze(animations); + return animations; + } + getTitle(context) { + const me = this; + const opts = me.options; + const callbacks = opts.callbacks; + const beforeTitle = callbacks.beforeTitle.apply(me, [context]); + const title = callbacks.title.apply(me, [context]); + const afterTitle = callbacks.afterTitle.apply(me, [context]); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); + return lines; + } + getBeforeBody(tooltipItems) { + return getBeforeAfterBodyLines(this.options.callbacks.beforeBody.apply(this, [tooltipItems])); + } + getBody(tooltipItems) { + const me = this; + const callbacks = me.options.callbacks; + const bodyItems = []; + each(tooltipItems, (context) => { + const bodyItem = { + before: [], + lines: [], + after: [] + }; + pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, context))); + pushOrConcat(bodyItem.lines, callbacks.label.call(me, context)); + pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, context))); + bodyItems.push(bodyItem); + }); + return bodyItems; + } + getAfterBody(tooltipItems) { + return getBeforeAfterBodyLines(this.options.callbacks.afterBody.apply(this, [tooltipItems])); + } + getFooter(tooltipItems) { + const me = this; + const callbacks = me.options.callbacks; + const beforeFooter = callbacks.beforeFooter.apply(me, [tooltipItems]); + const footer = callbacks.footer.apply(me, [tooltipItems]); + const afterFooter = callbacks.afterFooter.apply(me, [tooltipItems]); + let lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); + return lines; + } + _createItems() { + const me = this; + const active = me._active; + const options = me.options; + const data = me._chart.data; + const labelColors = []; + const labelTextColors = []; + let tooltipItems = []; + let i, len; + for (i = 0, len = active.length; i < len; ++i) { + tooltipItems.push(createTooltipItem(me._chart, active[i])); + } + if (options.filter) { + tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data)); + } + if (options.itemSort) { + tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data)); + } + each(tooltipItems, (context) => { + labelColors.push(options.callbacks.labelColor.call(me, context)); + labelTextColors.push(options.callbacks.labelTextColor.call(me, context)); + }); + me.labelColors = labelColors; + me.labelTextColors = labelTextColors; + me.dataPoints = tooltipItems; + return tooltipItems; + } + update(changed) { + const me = this; + const options = me.options; + const active = me._active; + let properties; + if (!active.length) { + if (me.opacity !== 0) { + properties = { + opacity: 0 + }; + } + } else { + const position = positioners[options.position].call(me, active, me._eventPosition); + const tooltipItems = me._createItems(); + me.title = me.getTitle(tooltipItems); + me.beforeBody = me.getBeforeBody(tooltipItems); + me.body = me.getBody(tooltipItems); + me.afterBody = me.getAfterBody(tooltipItems); + me.footer = me.getFooter(tooltipItems); + const size = me._size = getTooltipSize(me); + const positionAndSize = Object.assign({}, position, size); + const alignment = determineAlignment(me._chart, options, positionAndSize); + const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, me._chart); + me.xAlign = alignment.xAlign; + me.yAlign = alignment.yAlign; + properties = { + opacity: 1, + x: backgroundPoint.x, + y: backgroundPoint.y, + width: size.width, + height: size.height, + caretX: position.x, + caretY: position.y + }; + } + if (properties) { + me._resolveAnimations().update(me, properties); + } + if (changed && options.custom) { + options.custom.call(me, {chart: me._chart, tooltip: me}); + } + } + drawCaret(tooltipPoint, ctx, size) { + const caretPosition = this.getCaretPosition(tooltipPoint, size); + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + } + getCaretPosition(tooltipPoint, size) { + const {xAlign, yAlign, options} = this; + const {cornerRadius, caretSize} = options; + const {x: ptX, y: ptY} = tooltipPoint; + const {width, height} = size; + let x1, x2, x3, y1, y2, y3; + if (yAlign === 'center') { + y2 = ptY + (height / 2); + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + x3 = x1; + } else { + if (xAlign === 'left') { + x2 = ptX + cornerRadius + (caretSize); + } else if (xAlign === 'right') { + x2 = ptX + width - cornerRadius - caretSize; + } else { + x2 = this.caretX; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + x1 = x2 + caretSize; + x3 = x2 - caretSize; + } + y3 = y1; + } + return {x1, x2, x3, y1, y2, y3}; + } + drawTitle(pt, ctx) { + const me = this; + const options = me.options; + const title = me.title; + const length = title.length; + let titleFont, titleSpacing, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width); + pt.x = getAlignedX(me, options.titleAlign); + ctx.textAlign = rtlHelper.textAlign(options.titleAlign); + ctx.textBaseline = 'middle'; + titleFont = options.titleFont; + titleSpacing = options.titleSpacing; + ctx.fillStyle = options.titleFont.color; + ctx.font = titleFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.size / 2); + pt.y += titleFont.size + titleSpacing; + if (i + 1 === length) { + pt.y += options.titleMarginBottom - titleSpacing; + } + } + } + } + _drawColorBox(ctx, pt, i, rtlHelper) { + const me = this; + const options = me.options; + const labelColors = me.labelColors[i]; + const {boxHeight, boxWidth, bodyFont} = options; + const colorX = getAlignedX(me, 'left'); + const rtlColorX = rtlHelper.x(colorX); + const yOffSet = boxHeight < bodyFont.size ? (bodyFont.size - boxHeight) / 2 : 0; + const colorY = pt.y + yOffSet; + ctx.fillStyle = options.multiKeyBackground; + ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight); + ctx.lineWidth = 1; + ctx.strokeStyle = labelColors.borderColor; + ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight); + ctx.fillStyle = labelColors.backgroundColor; + ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2), colorY + 1, boxWidth - 2, boxHeight - 2); + ctx.fillStyle = me.labelTextColors[i]; + } + drawBody(pt, ctx) { + const me = this; + const {body, options} = me; + const {bodyFont, bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth} = options; + let bodyLineHeight = bodyFont.size; + let xLinePadding = 0; + const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width); + const fillLineOfText = function(line) { + ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); + pt.y += bodyLineHeight + bodySpacing; + }; + const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); + let bodyItem, textColor, lines, i, j, ilen, jlen; + ctx.textAlign = bodyAlign; + ctx.textBaseline = 'middle'; + ctx.font = bodyFont.string; + pt.x = getAlignedX(me, bodyAlignForCalculation); + ctx.fillStyle = bodyFont.color; + each(me.beforeBody, fillLineOfText); + xLinePadding = displayColors && bodyAlignForCalculation !== 'right' + ? bodyAlign === 'center' ? (boxWidth / 2 + 1) : (boxWidth + 2) + : 0; + for (i = 0, ilen = body.length; i < ilen; ++i) { + bodyItem = body[i]; + textColor = me.labelTextColors[i]; + ctx.fillStyle = textColor; + each(bodyItem.before, fillLineOfText); + lines = bodyItem.lines; + if (displayColors && lines.length) { + me._drawColorBox(ctx, pt, i, rtlHelper); + bodyLineHeight = Math.max(bodyFont.size, boxHeight); + } + for (j = 0, jlen = lines.length; j < jlen; ++j) { + fillLineOfText(lines[j]); + bodyLineHeight = bodyFont.size; + } + each(bodyItem.after, fillLineOfText); + } + xLinePadding = 0; + bodyLineHeight = bodyFont.size; + each(me.afterBody, fillLineOfText); + pt.y -= bodySpacing; + } + drawFooter(pt, ctx) { + const me = this; + const options = me.options; + const footer = me.footer; + const length = footer.length; + let footerFont, i; + if (length) { + const rtlHelper = getRtlAdapter(options.rtl, me.x, me.width); + pt.x = getAlignedX(me, options.footerAlign); + pt.y += options.footerMarginTop; + ctx.textAlign = rtlHelper.textAlign(options.footerAlign); + ctx.textBaseline = 'middle'; + footerFont = options.footerFont; + ctx.fillStyle = options.footerFont.color; + ctx.font = footerFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.size / 2); + pt.y += footerFont.size + options.footerSpacing; + } + } + } + drawBackground(pt, ctx, tooltipSize) { + const {xAlign, yAlign, options} = this; + const {x, y} = pt; + const {width, height} = tooltipSize; + const radius = options.cornerRadius; + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.beginPath(); + ctx.moveTo(x + radius, y); + if (yAlign === 'top') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } + } + _updateAnimationTarget() { + const me = this; + const chart = me._chart; + const options = me.options; + const anims = me.$animations; + const animX = anims && anims.x; + const animY = anims && anims.y; + if (animX || animY) { + const position = positioners[options.position].call(me, me._active, me._eventPosition); + if (!position) { + return; + } + const size = me._size = getTooltipSize(me); + const positionAndSize = Object.assign({}, position, me._size); + const alignment = determineAlignment(chart, options, positionAndSize); + const point = getBackgroundPoint(options, positionAndSize, alignment, chart); + if (animX._to !== point.x || animY._to !== point.y) { + me.xAlign = alignment.xAlign; + me.yAlign = alignment.yAlign; + me.width = size.width; + me.height = size.height; + me.caretX = position.x; + me.caretY = position.y; + me._resolveAnimations().update(me, point); + } + } + } + draw(ctx) { + const me = this; + const options = me.options; + let opacity = me.opacity; + if (!opacity) { + return; + } + me._updateAnimationTarget(); + const tooltipSize = { + width: me.width, + height: me.height + }; + const pt = { + x: me.x, + y: me.y + }; + opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; + const hasTooltipContent = me.title.length || me.beforeBody.length || me.body.length || me.afterBody.length || me.footer.length; + if (options.enabled && hasTooltipContent) { + ctx.save(); + ctx.globalAlpha = opacity; + me.drawBackground(pt, ctx, tooltipSize); + overrideTextDirection(ctx, options.textDirection); + pt.y += options.yPadding; + me.drawTitle(pt, ctx); + me.drawBody(pt, ctx); + me.drawFooter(pt, ctx); + restoreTextDirection(ctx, options.textDirection); + ctx.restore(); + } + } + handleEvent(e, replay) { + const me = this; + const options = me.options; + const lastActive = me._active || []; + let changed = false; + let active = []; + if (e.type !== 'mouseout') { + active = me._chart.getElementsAtEventForMode(e, options.mode, options, replay); + if (options.reverse) { + active.reverse(); + } + } + const position = positioners[options.position].call(me, active, e); + const positionChanged = this.caretX !== position.x || this.caretY !== position.y; + changed = replay || !_elementsEqual(active, lastActive) || positionChanged; + if (changed) { + me._active = active; + if (options.enabled || options.custom) { + me._eventPosition = { + x: e.x, + y: e.y + }; + me.update(true); + } + } + return changed; + } +} +Tooltip.positioners = positioners; +var plugin_tooltip = { + id: 'tooltip', + _element: Tooltip, + positioners, + afterInit(chart) { + const tooltipOpts = chart.options.tooltips; + if (tooltipOpts) { + chart.tooltip = new Tooltip({_chart: chart}); + } + }, + beforeUpdate(chart) { + if (chart.tooltip) { + chart.tooltip.initialize(); + } + }, + reset(chart) { + if (chart.tooltip) { + chart.tooltip.initialize(); + } + }, + afterDraw(chart) { + const tooltip = chart.tooltip; + const args = { + tooltip + }; + if (chart._plugins.notify(chart, 'beforeTooltipDraw', [args]) === false) { + return; + } + if (tooltip) { + tooltip.draw(chart.ctx); + } + chart._plugins.notify(chart, 'afterTooltipDraw', [args]); + }, + afterEvent(chart, e, replay) { + if (chart.tooltip) { + const useFinalPosition = replay; + chart.tooltip.handleEvent(e, useFinalPosition); + } + }, + defaults: { + enabled: true, + custom: null, + mode: 'nearest', + position: 'average', + intersect: true, + backgroundColor: 'rgba(0,0,0,0.8)', + titleFont: { + style: 'bold', + color: '#fff', + }, + titleSpacing: 2, + titleMarginBottom: 6, + titleAlign: 'left', + bodySpacing: 2, + bodyFont: { + color: '#fff', + }, + bodyAlign: 'left', + footerSpacing: 2, + footerMarginTop: 6, + footerFont: { + color: '#fff', + style: 'bold', + }, + footerAlign: 'left', + yPadding: 6, + xPadding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + multiKeyBackground: '#fff', + displayColors: true, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + animation: { + duration: 400, + easing: 'easeOutQuart', + numbers: { + type: 'number', + properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'], + }, + opacity: { + easing: 'linear', + duration: 200 + } + }, + callbacks: { + beforeTitle: noop, + title(tooltipItems) { + if (tooltipItems.length > 0) { + const item = tooltipItems[0]; + const labels = item.chart.data.labels; + const labelCount = labels ? labels.length : 0; + if (item.label) { + return item.label; + } else if (labelCount > 0 && item.dataIndex < labelCount) { + return labels[item.dataIndex]; + } + } + return ''; + }, + afterTitle: noop, + beforeBody: noop, + beforeLabel: noop, + label(tooltipItem) { + let label = tooltipItem.dataset.label || ''; + if (label) { + label += ': '; + } + const value = tooltipItem.formattedValue; + if (!isNullOrUndef(value)) { + label += value; + } + return label; + }, + labelColor(tooltipItem) { + const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + const options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + borderColor: options.borderColor, + backgroundColor: options.backgroundColor + }; + }, + labelTextColor() { + return this.options.bodyFont.color; + }, + afterLabel: noop, + afterBody: noop, + beforeFooter: noop, + footer: noop, + afterFooter: noop + } + }, +}; + +class CategoryScale extends Scale { + constructor(cfg) { + super(cfg); + this._startValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + const labels = this.getLabels(); + if (labels[index] === raw) { + return index; + } + const first = labels.indexOf(raw); + const last = labels.lastIndexOf(raw); + return first === -1 || first !== last ? index : first; + } + determineDataLimits() { + const me = this; + const max = me.getLabels().length - 1; + me.min = Math.max(me._userMin || 0, 0); + me.max = Math.min(me._userMax || max, max); + } + buildTicks() { + const me = this; + const min = me.min; + const max = me.max; + const offset = me.options.offset; + const ticks = []; + let labels = me.getLabels(); + labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1); + me._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); + me._startValue = me.min - (offset ? 0.5 : 0); + for (let value = min; value <= max; value++) { + ticks.push({value}); + } + return ticks; + } + getLabelForValue(value) { + const me = this; + const labels = me.getLabels(); + if (value >= 0 && value < labels.length) { + return labels[value]; + } + return value; + } + configure() { + const me = this; + super.configure(); + if (!me.isHorizontal()) { + me._reversePixels = !me._reversePixels; + } + } + getPixelForValue(value) { + const me = this; + if (typeof value !== 'number') { + value = me.parse(value); + } + return me.getPixelForDecimal((value - me._startValue) / me._valueRange); + } + getPixelForTick(index) { + const me = this; + const ticks = me.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return me.getPixelForValue(ticks[index].value); + } + getValueForPixel(pixel) { + const me = this; + const value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange); + return Math.min(Math.max(value, 0), me.ticks.length - 1); + } + getBasePixel() { + return this.bottom; + } +} +CategoryScale.id = 'category'; +CategoryScale.defaults = { + ticks: { + callback: CategoryScale.prototype.getLabelForValue + } +}; + +function niceNum(range) { + const exponent = Math.floor(log10(range)); + const fraction = range / Math.pow(10, exponent); + let niceFraction; + if (fraction <= 1.0) { + niceFraction = 1; + } else if (fraction <= 2) { + niceFraction = 2; + } else if (fraction <= 5) { + niceFraction = 5; + } else { + niceFraction = 10; + } + return niceFraction * Math.pow(10, exponent); +} +function generateTicks(generationOptions, dataRange) { + const ticks = []; + const MIN_SPACING = 1e-14; + const {stepSize, min, max, precision} = generationOptions; + const unit = stepSize || 1; + const maxNumSpaces = generationOptions.maxTicks - 1; + const {min: rmin, max: rmax} = dataRange; + let spacing = niceNum((rmax - rmin) / maxNumSpaces / unit) * unit; + let factor, niceMin, niceMax, numSpaces; + if (spacing < MIN_SPACING && isNullOrUndef(min) && isNullOrUndef(max)) { + return [{value: rmin}, {value: rmax}]; + } + numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); + if (numSpaces > maxNumSpaces) { + spacing = niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit; + } + if (stepSize || isNullOrUndef(precision)) { + factor = Math.pow(10, _decimalPlaces(spacing)); + } else { + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } + niceMin = Math.floor(rmin / spacing) * spacing; + niceMax = Math.ceil(rmax / spacing) * spacing; + if (stepSize && !isNullOrUndef(min) && !isNullOrUndef(max)) { + if (almostWhole((max - min) / stepSize, spacing / 1000)) { + niceMin = min; + niceMax = max; + } + } + numSpaces = (niceMax - niceMin) / spacing; + if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + niceMin = Math.round(niceMin * factor) / factor; + niceMax = Math.round(niceMax * factor) / factor; + ticks.push({value: isNullOrUndef(min) ? niceMin : min}); + for (let j = 1; j < numSpaces; ++j) { + ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor}); + } + ticks.push({value: isNullOrUndef(max) ? niceMax : max}); + return ticks; +} +class LinearScaleBase extends Scale { + constructor(cfg) { + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._endValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + if (isNullOrUndef(raw)) { + return NaN; + } + if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { + return NaN; + } + return +raw; + } + handleTickRangeOptions() { + const me = this; + const opts = me.options; + if (opts.beginAtZero) { + const minSign = sign(me.min); + const maxSign = sign(me.max); + if (minSign < 0 && maxSign < 0) { + me.max = 0; + } else if (minSign > 0 && maxSign > 0) { + me.min = 0; + } + } + const setMin = opts.min !== undefined || opts.suggestedMin !== undefined; + const setMax = opts.max !== undefined || opts.suggestedMax !== undefined; + if (opts.min !== undefined) { + me.min = opts.min; + } else if (opts.suggestedMin !== undefined) { + if (me.min === null) { + me.min = opts.suggestedMin; + } else { + me.min = Math.min(me.min, opts.suggestedMin); + } + } + if (opts.max !== undefined) { + me.max = opts.max; + } else if (opts.suggestedMax !== undefined) { + if (me.max === null) { + me.max = opts.suggestedMax; + } else { + me.max = Math.max(me.max, opts.suggestedMax); + } + } + if (setMin !== setMax) { + if (me.min >= me.max) { + if (setMin) { + me.max = me.min + 1; + } else { + me.min = me.max - 1; + } + } + } + if (me.min === me.max) { + me.max++; + if (!opts.beginAtZero) { + me.min--; + } + } + } + getTickLimit() { + const me = this; + const tickOpts = me.options.ticks; + let {maxTicksLimit, stepSize} = tickOpts; + let maxTicks; + if (stepSize) { + maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1; + } else { + maxTicks = me.computeTickLimit(); + maxTicksLimit = maxTicksLimit || 11; + } + if (maxTicksLimit) { + maxTicks = Math.min(maxTicksLimit, maxTicks); + } + return maxTicks; + } + computeTickLimit() { + return Number.POSITIVE_INFINITY; + } + buildTicks() { + const me = this; + const opts = me.options; + const tickOpts = opts.ticks; + let maxTicks = me.getTickLimit(); + maxTicks = Math.max(2, maxTicks); + const numericGeneratorOptions = { + maxTicks, + min: opts.min, + max: opts.max, + precision: tickOpts.precision, + stepSize: valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize) + }; + const ticks = generateTicks(numericGeneratorOptions, me); + _setMinAndMaxByKey(ticks, me, 'value'); + if (opts.reverse) { + ticks.reverse(); + me.start = me.max; + me.end = me.min; + } else { + me.start = me.min; + me.end = me.max; + } + return ticks; + } + configure() { + const me = this; + const ticks = me.ticks; + let start = me.min; + let end = me.max; + super.configure(); + if (me.options.offset && ticks.length) { + const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; + start -= offset; + end += offset; + } + me._startValue = start; + me._endValue = end; + me._valueRange = end - start; + } + getLabelForValue(value) { + return new Intl.NumberFormat(this.options.locale).format(value); + } +} + +class LinearScale extends LinearScaleBase { + determineDataLimits() { + const me = this; + const options = me.options; + const {min, max} = me.getMinMax(true); + me.min = isNumberFinite(min) ? min : valueOrDefault(options.suggestedMin, 0); + me.max = isNumberFinite(max) ? max : valueOrDefault(options.suggestedMax, 1); + if (options.stacked && min > 0) { + me.min = 0; + } + me.handleTickRangeOptions(); + } + computeTickLimit() { + const me = this; + if (me.isHorizontal()) { + return Math.ceil(me.width / 40); + } + const tickFont = me._resolveTickFontOptions(0); + return Math.ceil(me.height / tickFont.lineHeight); + } + getPixelForValue(value) { + const me = this; + return me.getPixelForDecimal((value - me._startValue) / me._valueRange); + } + getValueForPixel(pixel) { + return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; + } +} +LinearScale.id = 'linear'; +LinearScale.defaults = { + ticks: { + callback: Ticks.formatters.numeric + } +}; + +function isMajor(tickVal) { + const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal)))); + return remain === 1; +} +function finiteOrDefault(value, def) { + return isNumberFinite(value) ? value : def; +} +function generateTicks$1(generationOptions, dataRange) { + const endExp = Math.floor(log10(dataRange.max)); + const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); + const ticks = []; + let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); + let exp = Math.floor(log10(tickVal)); + let significand = Math.floor(tickVal / Math.pow(10, exp)); + let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; + do { + ticks.push({value: tickVal, major: isMajor(tickVal)}); + ++significand; + if (significand === 10) { + significand = 1; + ++exp; + precision = exp >= 0 ? 1 : precision; + } + tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; + } while (exp < endExp || (exp === endExp && significand < endSignificand)); + const lastTick = finiteOrDefault(generationOptions.max, tickVal); + ticks.push({value: lastTick, major: isMajor(tickVal)}); + return ticks; +} +class LogarithmicScale extends Scale { + constructor(cfg) { + super(cfg); + this.start = undefined; + this.end = undefined; + this._startValue = undefined; + this._valueRange = 0; + } + parse(raw, index) { + const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); + if (value === 0) { + return undefined; + } + return isNumberFinite(value) && value > 0 ? value : NaN; + } + determineDataLimits() { + const me = this; + const {min, max} = me.getMinMax(true); + me.min = isNumberFinite(min) ? Math.max(0, min) : null; + me.max = isNumberFinite(max) ? Math.max(0, max) : null; + me.handleTickRangeOptions(); + } + handleTickRangeOptions() { + const me = this; + const DEFAULT_MIN = 1; + const DEFAULT_MAX = 10; + let min = me.min; + let max = me.max; + if (min === max) { + if (min <= 0) { + min = DEFAULT_MIN; + max = DEFAULT_MAX; + } else { + min = Math.pow(10, Math.floor(log10(min)) - 1); + max = Math.pow(10, Math.floor(log10(max)) + 1); + } + } + if (min <= 0) { + min = Math.pow(10, Math.floor(log10(max)) - 1); + } + if (max <= 0) { + max = Math.pow(10, Math.floor(log10(min)) + 1); + } + me.min = min; + me.max = max; + } + buildTicks() { + const me = this; + const opts = me.options; + const generationOptions = { + min: me._userMin, + max: me._userMax + }; + const ticks = generateTicks$1(generationOptions, me); + let reverse = !me.isHorizontal(); + _setMinAndMaxByKey(ticks, me, 'value'); + if (opts.reverse) { + reverse = !reverse; + me.start = me.max; + me.end = me.min; + } else { + me.start = me.min; + me.end = me.max; + } + if (reverse) { + ticks.reverse(); + } + return ticks; + } + getLabelForValue(value) { + return value === undefined ? '0' : new Intl.NumberFormat(this.options.locale).format(value); + } + configure() { + const me = this; + const start = me.min; + super.configure(); + me._startValue = log10(start); + me._valueRange = log10(me.max) - log10(start); + } + getPixelForValue(value) { + const me = this; + if (value === undefined || value === 0) { + value = me.min; + } + return me.getPixelForDecimal(value === me.min + ? 0 + : (log10(value) - me._startValue) / me._valueRange); + } + getValueForPixel(pixel) { + const me = this; + const decimal = me.getDecimalForPixel(pixel); + return Math.pow(10, me._startValue + decimal * me._valueRange); + } +} +LogarithmicScale.id = 'logarithmic'; +LogarithmicScale.defaults = { + ticks: { + callback: Ticks.formatters.logarithmic, + major: { + enabled: true + } + } +}; + +function getTickBackdropHeight(opts) { + const tickOpts = opts.ticks; + if (tickOpts.display && opts.display) { + return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + tickOpts.backdropPaddingY * 2; + } + return 0; +} +function measureLabelSize(ctx, lineHeight, label) { + if (isArray(label)) { + return { + w: _longestText(ctx, ctx.font, label), + h: label.length * lineHeight + }; + } + return { + w: ctx.measureText(label).width, + h: lineHeight + }; +} +function determineLimits(angle, pos, size, min, max) { + if (angle === min || angle === max) { + return { + start: pos - (size / 2), + end: pos + (size / 2) + }; + } else if (angle < min || angle > max) { + return { + start: pos - size, + end: pos + }; + } + return { + start: pos, + end: pos + size + }; +} +function fitWithPointLabels(scale) { + const furthestLimits = { + l: 0, + r: scale.width, + t: 0, + b: scale.height - scale.paddingTop + }; + const furthestAngles = {}; + let i, textSize, pointPosition; + scale._pointLabelSizes = []; + const valueCount = scale.chart.data.labels.length; + for (i = 0; i < valueCount; i++) { + pointPosition = scale.getPointPosition(i, scale.drawingArea + 5); + const context = { + chart: scale.chart, + scale, + index: i, + label: scale.pointLabels[i] + }; + const plFont = toFont(resolve([scale.options.pointLabels.font], context, i), scale.chart.options.font); + scale.ctx.font = plFont.string; + textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]); + scale._pointLabelSizes[i] = textSize; + const angleRadians = scale.getIndexAngle(i); + const angle = toDegrees(angleRadians); + const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); + const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); + if (hLimits.start < furthestLimits.l) { + furthestLimits.l = hLimits.start; + furthestAngles.l = angleRadians; + } + if (hLimits.end > furthestLimits.r) { + furthestLimits.r = hLimits.end; + furthestAngles.r = angleRadians; + } + if (vLimits.start < furthestLimits.t) { + furthestLimits.t = vLimits.start; + furthestAngles.t = angleRadians; + } + if (vLimits.end > furthestLimits.b) { + furthestLimits.b = vLimits.end; + furthestAngles.b = angleRadians; + } + } + scale._setReductions(scale.drawingArea, furthestLimits, furthestAngles); +} +function getTextAlignForAngle(angle) { + if (angle === 0 || angle === 180) { + return 'center'; + } else if (angle < 180) { + return 'left'; + } + return 'right'; +} +function fillText(ctx, text, position, lineHeight) { + let y = position.y + lineHeight / 2; + let i, ilen; + if (isArray(text)) { + for (i = 0, ilen = text.length; i < ilen; ++i) { + ctx.fillText(text[i], position.x, y); + y += lineHeight; + } + } else { + ctx.fillText(text, position.x, y); + } +} +function adjustPointPositionForLabelHeight(angle, textSize, position) { + if (angle === 90 || angle === 270) { + position.y -= (textSize.h / 2); + } else if (angle > 270 || angle < 90) { + position.y -= textSize.h; + } +} +function drawPointLabels(scale) { + const ctx = scale.ctx; + const opts = scale.options; + const pointLabelOpts = opts.pointLabels; + const tickBackdropHeight = getTickBackdropHeight(opts); + const outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); + ctx.save(); + ctx.textBaseline = 'middle'; + for (let i = scale.chart.data.labels.length - 1; i >= 0; i--) { + const extra = (i === 0 ? tickBackdropHeight / 2 : 0); + const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5); + const context = { + chart: scale.chart, + scale, + index: i, + label: scale.pointLabels[i], + }; + const plFont = toFont(resolve([pointLabelOpts.font], context, i), scale.chart.options.font); + ctx.font = plFont.string; + ctx.fillStyle = plFont.color; + const angle = toDegrees(scale.getIndexAngle(i)); + ctx.textAlign = getTextAlignForAngle(angle); + adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition); + fillText(ctx, scale.pointLabels[i], pointLabelPosition, plFont.lineHeight); + } + ctx.restore(); +} +function drawRadiusLine(scale, gridLineOpts, radius, index) { + const ctx = scale.ctx; + const circular = gridLineOpts.circular; + const valueCount = scale.chart.data.labels.length; + const context = { + chart: scale.chart, + scale, + index, + tick: scale.ticks[index], + }; + const lineColor = resolve([gridLineOpts.color], context, index - 1); + const lineWidth = resolve([gridLineOpts.lineWidth], context, index - 1); + let pointPosition; + if ((!circular && !valueCount) || !lineColor || !lineWidth) { + return; + } + ctx.save(); + ctx.strokeStyle = lineColor; + ctx.lineWidth = lineWidth; + if (ctx.setLineDash) { + ctx.setLineDash(resolve([gridLineOpts.borderDash, []], context)); + ctx.lineDashOffset = resolve([gridLineOpts.borderDashOffset], context, index - 1); + } + ctx.beginPath(); + if (circular) { + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2); + } else { + pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + for (let i = 1; i < valueCount; i++) { + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } + } + ctx.closePath(); + ctx.stroke(); + ctx.restore(); +} +function numberOrZero(param) { + return isNumber(param) ? param : 0; +} +class RadialLinearScale extends LinearScaleBase { + constructor(cfg) { + super(cfg); + this.xCenter = undefined; + this.yCenter = undefined; + this.drawingArea = undefined; + this.pointLabels = []; + } + init(options) { + super.init(options); + this.axis = 'r'; + } + setDimensions() { + const me = this; + me.width = me.maxWidth; + me.height = me.maxHeight; + me.paddingTop = getTickBackdropHeight(me.options) / 2; + me.xCenter = Math.floor(me.width / 2); + me.yCenter = Math.floor((me.height - me.paddingTop) / 2); + me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2; + } + determineDataLimits() { + const me = this; + const {min, max} = me.getMinMax(false); + me.min = isNumberFinite(min) && !isNaN(min) ? min : 0; + me.max = isNumberFinite(max) && !isNaN(max) ? max : 0; + me.handleTickRangeOptions(); + } + computeTickLimit() { + return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); + } + generateTickLabels(ticks) { + const me = this; + LinearScaleBase.prototype.generateTickLabels.call(me, ticks); + me.pointLabels = me.chart.data.labels.map((value, index) => { + const label = callback(me.options.pointLabels.callback, [value, index], me); + return label || label === 0 ? label : ''; + }); + } + fit() { + const me = this; + const opts = me.options; + if (opts.display && opts.pointLabels.display) { + fitWithPointLabels(me); + } else { + me.setCenterPoint(0, 0, 0, 0); + } + } + _setReductions(largestPossibleRadius, furthestLimits, furthestAngles) { + const me = this; + let radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l); + let radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r); + let radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t); + let radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b); + radiusReductionLeft = numberOrZero(radiusReductionLeft); + radiusReductionRight = numberOrZero(radiusReductionRight); + radiusReductionTop = numberOrZero(radiusReductionTop); + radiusReductionBottom = numberOrZero(radiusReductionBottom); + me.drawingArea = Math.min( + Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2), + Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2)); + me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom); + } + setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { + const me = this; + const maxRight = me.width - rightMovement - me.drawingArea; + const maxLeft = leftMovement + me.drawingArea; + const maxTop = topMovement + me.drawingArea; + const maxBottom = (me.height - me.paddingTop) - bottomMovement - me.drawingArea; + me.xCenter = Math.floor(((maxLeft + maxRight) / 2) + me.left); + me.yCenter = Math.floor(((maxTop + maxBottom) / 2) + me.top + me.paddingTop); + } + getIndexAngle(index) { + const chart = this.chart; + const angleMultiplier = Math.PI * 2 / chart.data.labels.length; + const options = chart.options || {}; + const startAngle = options.startAngle || 0; + return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); + } + getDistanceFromCenterForValue(value) { + const me = this; + if (isNullOrUndef(value)) { + return NaN; + } + const scalingFactor = me.drawingArea / (me.max - me.min); + if (me.options.reverse) { + return (me.max - value) * scalingFactor; + } + return (value - me.min) * scalingFactor; + } + getValueForDistanceFromCenter(distance) { + if (isNullOrUndef(distance)) { + return NaN; + } + const me = this; + const scaledDistance = distance / (me.drawingArea / (me.max - me.min)); + return me.options.reverse ? me.max - scaledDistance : me.min + scaledDistance; + } + getPointPosition(index, distanceFromCenter) { + const me = this; + const angle = me.getIndexAngle(index) - (Math.PI / 2); + return { + x: Math.cos(angle) * distanceFromCenter + me.xCenter, + y: Math.sin(angle) * distanceFromCenter + me.yCenter, + angle + }; + } + getPointPositionForValue(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + } + getBasePosition(index) { + return this.getPointPositionForValue(index || 0, this.getBaseValue()); + } + drawGrid() { + const me = this; + const ctx = me.ctx; + const opts = me.options; + const gridLineOpts = opts.gridLines; + const angleLineOpts = opts.angleLines; + let i, offset, position; + if (opts.pointLabels.display) { + drawPointLabels(me); + } + if (gridLineOpts.display) { + me.ticks.forEach((tick, index) => { + if (index !== 0) { + offset = me.getDistanceFromCenterForValue(me.ticks[index].value); + drawRadiusLine(me, gridLineOpts, offset, index); + } + }); + } + if (angleLineOpts.display) { + ctx.save(); + for (i = me.chart.data.labels.length - 1; i >= 0; i--) { + const context = { + chart: me.chart, + scale: me, + index: i, + label: me.pointLabels[i], + }; + const lineWidth = resolve([angleLineOpts.lineWidth, gridLineOpts.lineWidth], context, i); + const color = resolve([angleLineOpts.color, gridLineOpts.color], context, i); + if (!lineWidth || !color) { + continue; + } + ctx.lineWidth = lineWidth; + ctx.strokeStyle = color; + if (ctx.setLineDash) { + ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []], context)); + ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0], context, i); + } + offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max); + position = me.getPointPosition(i, offset); + ctx.beginPath(); + ctx.moveTo(me.xCenter, me.yCenter); + ctx.lineTo(position.x, position.y); + ctx.stroke(); + } + ctx.restore(); + } + } + drawLabels() { + const me = this; + const ctx = me.ctx; + const opts = me.options; + const tickOpts = opts.ticks; + if (!tickOpts.display) { + return; + } + const startAngle = me.getIndexAngle(0); + let offset, width; + ctx.save(); + ctx.translate(me.xCenter, me.yCenter); + ctx.rotate(startAngle); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + me.ticks.forEach((tick, index) => { + const context = { + chart: me.chart, + scale: me, + index, + tick, + }; + if (index === 0 && !opts.reverse) { + return; + } + const tickFont = me._resolveTickFontOptions(index); + ctx.font = tickFont.string; + offset = me.getDistanceFromCenterForValue(me.ticks[index].value); + const showLabelBackdrop = resolve([tickOpts.showLabelBackdrop], context, index); + if (showLabelBackdrop) { + width = ctx.measureText(tick.label).width; + ctx.fillStyle = resolve([tickOpts.backdropColor], context, index); + ctx.fillRect( + -width / 2 - tickOpts.backdropPaddingX, + -offset - tickFont.size / 2 - tickOpts.backdropPaddingY, + width + tickOpts.backdropPaddingX * 2, + tickFont.size + tickOpts.backdropPaddingY * 2 + ); + } + ctx.fillStyle = tickFont.color; + ctx.fillText(tick.label, 0, -offset); + }); + ctx.restore(); + } + drawTitle() {} +} +RadialLinearScale.id = 'radialLinear'; +RadialLinearScale.defaults = { + display: true, + animate: true, + position: 'chartArea', + angleLines: { + display: true, + color: 'rgba(0,0,0,0.1)', + lineWidth: 1, + borderDash: [], + borderDashOffset: 0.0 + }, + gridLines: { + circular: false + }, + ticks: { + showLabelBackdrop: true, + backdropColor: 'rgba(255,255,255,0.75)', + backdropPaddingY: 2, + backdropPaddingX: 2, + callback: Ticks.formatters.numeric + }, + pointLabels: { + display: true, + font: { + size: 10 + }, + callback(label) { + return label; + } + } +}; + +const MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; +const INTERVALS = { + millisecond: {common: true, size: 1, steps: 1000}, + second: {common: true, size: 1000, steps: 60}, + minute: {common: true, size: 60000, steps: 60}, + hour: {common: true, size: 3600000, steps: 24}, + day: {common: true, size: 86400000, steps: 30}, + week: {common: false, size: 604800000, steps: 4}, + month: {common: true, size: 2.628e9, steps: 12}, + quarter: {common: false, size: 7.884e9, steps: 4}, + year: {common: true, size: 3.154e10} +}; +const UNITS = (Object.keys(INTERVALS)); +function sorter(a, b) { + return a - b; +} +function parse(scale, input) { + if (isNullOrUndef(input)) { + return null; + } + const adapter = scale._adapter; + const options = scale.options.time; + const {parser, round, isoWeekday} = options; + let value = input; + if (typeof parser === 'function') { + value = parser(value); + } + if (!isNumberFinite(value)) { + value = typeof parser === 'string' + ? adapter.parse(value, parser) + : adapter.parse(value); + } + if (value === null) { + return value; + } + if (round) { + value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) + ? scale._adapter.startOf(value, 'isoWeek', isoWeekday) + : scale._adapter.startOf(value, round); + } + return +value; +} +function determineUnitForAutoTicks(minUnit, min, max, capacity) { + const ilen = UNITS.length; + for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { + const interval = INTERVALS[UNITS[i]]; + const factor = interval.steps ? interval.steps : MAX_INTEGER; + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + return UNITS[ilen - 1]; +} +function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { + for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { + const unit = UNITS[i]; + if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { + return unit; + } + } + return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; +} +function determineMajorUnit(unit) { + for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { + if (INTERVALS[UNITS[i]].common) { + return UNITS[i]; + } + } +} +function addTick(ticks, time, timestamps) { + if (!timestamps) { + ticks[time] = true; + } else if (timestamps.length) { + const {lo, hi} = _lookup(timestamps, time); + const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; + ticks[timestamp] = true; + } +} +function setMajorTicks(scale, ticks, map, majorUnit) { + const adapter = scale._adapter; + const first = +adapter.startOf(ticks[0].value, majorUnit); + const last = ticks[ticks.length - 1].value; + let major, index; + for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { + index = map[major]; + if (index >= 0) { + ticks[index].major = true; + } + } + return ticks; +} +function ticksFromTimestamps(scale, values, majorUnit) { + const ticks = []; + const map = {}; + const ilen = values.length; + let i, value; + for (i = 0; i < ilen; ++i) { + value = values[i]; + map[value] = i; + ticks.push({ + value, + major: false + }); + } + return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit); +} +class TimeScale extends Scale { + constructor(props) { + super(props); + this._cache = { + data: [], + labels: [], + all: [] + }; + this._unit = 'day'; + this._majorUnit = undefined; + this._offsets = {}; + this._normalized = false; + } + init(scaleOpts, opts) { + const time = scaleOpts.time || (scaleOpts.time = {}); + const adapter = this._adapter = new adapters._date(scaleOpts.adapters.date); + mergeIf(time.displayFormats, adapter.formats()); + super.init(scaleOpts); + this._normalized = opts.normalized; + } + parse(raw, index) { + if (raw === undefined) { + return NaN; + } + return parse(this, raw); + } + invalidateCaches() { + this._cache = { + data: [], + labels: [], + all: [] + }; + } + determineDataLimits() { + const me = this; + const options = me.options; + const adapter = me._adapter; + const unit = options.time.unit || 'day'; + let {min, max, minDefined, maxDefined} = me.getUserBounds(); + function _applyBounds(bounds) { + if (!minDefined && !isNaN(bounds.min)) { + min = Math.min(min, bounds.min); + } + if (!maxDefined && !isNaN(bounds.max)) { + max = Math.max(max, bounds.max); + } + } + if (!minDefined || !maxDefined) { + _applyBounds(me._getLabelBounds()); + if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { + _applyBounds(me.getMinMax(false)); + } + } + min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; + me.min = Math.min(min, max); + me.max = Math.max(min + 1, max); + } + _getLabelBounds() { + const arr = this.getLabelTimestamps(); + let min = Number.POSITIVE_INFINITY; + let max = Number.NEGATIVE_INFINITY; + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return {min, max}; + } + buildTicks() { + const me = this; + const options = me.options; + const timeOpts = options.time; + const tickOpts = options.ticks; + const timestamps = tickOpts.source === 'labels' ? me.getLabelTimestamps() : me._generate(); + if (options.bounds === 'ticks' && timestamps.length) { + me.min = me._userMin || timestamps[0]; + me.max = me._userMax || timestamps[timestamps.length - 1]; + } + const min = me.min; + const max = me.max; + const ticks = _filterBetween(timestamps, min, max); + me._unit = timeOpts.unit || (tickOpts.autoSkip + ? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, me._getLabelCapacity(min)) + : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max)); + me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined + : determineMajorUnit(me._unit); + me.initOffsets(timestamps); + if (options.reverse) { + ticks.reverse(); + } + return ticksFromTimestamps(me, ticks, me._majorUnit); + } + initOffsets(timestamps) { + const me = this; + let start = 0; + let end = 0; + let first, last; + if (me.options.offset && timestamps.length) { + first = me.getDecimalForValue(timestamps[0]); + if (timestamps.length === 1) { + start = 1 - first; + } else { + start = (me.getDecimalForValue(timestamps[1]) - first) / 2; + } + last = me.getDecimalForValue(timestamps[timestamps.length - 1]); + if (timestamps.length === 1) { + end = last; + } else { + end = (last - me.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; + } + } + me._offsets = {start, end, factor: 1 / (start + 1 + end)}; + } + _generate() { + const me = this; + const adapter = me._adapter; + const min = me.min; + const max = me.max; + const options = me.options; + const timeOpts = options.time; + const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, me._getLabelCapacity(min)); + const stepSize = valueOrDefault(timeOpts.stepSize, 1); + const weekday = minor === 'week' ? timeOpts.isoWeekday : false; + const hasWeekday = isNumber(weekday) || weekday === true; + const ticks = {}; + let first = min; + let time; + if (hasWeekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + first = +adapter.startOf(first, hasWeekday ? 'day' : minor); + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + const timestamps = options.ticks.source === 'data' && me.getDataTimestamps(); + for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) { + addTick(ticks, time, timestamps); + } + if (time === max || options.bounds === 'ticks') { + addTick(ticks, time, timestamps); + } + return Object.keys(ticks).sort((a, b) => a - b).map(x => +x); + } + getLabelForValue(value) { + const me = this; + const adapter = me._adapter; + const timeOpts = me.options.time; + if (timeOpts.tooltipFormat) { + return adapter.format(value, timeOpts.tooltipFormat); + } + return adapter.format(value, timeOpts.displayFormats.datetime); + } + _tickFormatFunction(time, index, ticks, format) { + const me = this; + const options = me.options; + const formats = options.time.displayFormats; + const unit = me._unit; + const majorUnit = me._majorUnit; + const minorFormat = unit && formats[unit]; + const majorFormat = majorUnit && formats[majorUnit]; + const tick = ticks[index]; + const major = majorUnit && majorFormat && tick && tick.major; + const label = me._adapter.format(time, format || (major ? majorFormat : minorFormat)); + const formatter = options.ticks.callback; + return formatter ? formatter(label, index, ticks) : label; + } + generateTickLabels(ticks) { + let i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + tick.label = this._tickFormatFunction(tick.value, i, ticks); + } + } + getDecimalForValue(value) { + const me = this; + return (value - me.min) / (me.max - me.min); + } + getPixelForValue(value) { + const me = this; + const offsets = me._offsets; + const pos = me.getDecimalForValue(value); + return me.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + getValueForPixel(pixel) { + const me = this; + const offsets = me._offsets; + const pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return me.min + pos * (me.max - me.min); + } + _getLabelSize(label) { + const me = this; + const ticksOpts = me.options.ticks; + const tickLabelWidth = me.ctx.measureText(label).width; + const angle = toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); + const cosRotation = Math.cos(angle); + const sinRotation = Math.sin(angle); + const tickFontSize = me._resolveTickFontOptions(0).size; + return { + w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation), + h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation) + }; + } + _getLabelCapacity(exampleTime) { + const me = this; + const timeOpts = me.options.time; + const displayFormats = timeOpts.displayFormats; + const format = displayFormats[timeOpts.unit] || displayFormats.millisecond; + const exampleLabel = me._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format); + const size = me._getLabelSize(exampleLabel); + const capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h) - 1; + return capacity > 0 ? capacity : 1; + } + getDataTimestamps() { + const me = this; + let timestamps = me._cache.data || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const metas = me.getMatchingVisibleMetas(); + if (me._normalized && metas.length) { + return (me._cache.data = metas[0].controller.getAllParsedValues(me)); + } + for (i = 0, ilen = metas.length; i < ilen; ++i) { + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(me)); + } + return (me._cache.data = me.normalize(timestamps)); + } + getLabelTimestamps() { + const me = this; + const timestamps = me._cache.labels || []; + let i, ilen; + if (timestamps.length) { + return timestamps; + } + const labels = me.getLabels(); + for (i = 0, ilen = labels.length; i < ilen; ++i) { + timestamps.push(parse(me, labels[i])); + } + return (me._cache.labels = me._normalized ? timestamps : me.normalize(timestamps)); + } + normalize(values) { + return _arrayUnique(values.sort(sorter)); + } +} +TimeScale.id = 'time'; +TimeScale.defaults = { + bounds: 'data', + adapters: {}, + time: { + parser: false, + unit: false, + round: false, + isoWeekday: false, + minUnit: 'millisecond', + displayFormats: {} + }, + ticks: { + source: 'auto', + major: { + enabled: false + } + } +}; + +function interpolate(table, val, reverse) { + let prevSource, nextSource, prevTarget, nextTarget; + if (reverse) { + prevSource = Math.floor(val); + nextSource = Math.ceil(val); + prevTarget = table[prevSource]; + nextTarget = table[nextSource]; + } else { + const result = _lookup(table, val); + prevTarget = result.lo; + nextTarget = result.hi; + prevSource = table[prevTarget]; + nextSource = table[nextTarget]; + } + const span = nextSource - prevSource; + return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; +} +class TimeSeriesScale extends TimeScale { + constructor(props) { + super(props); + this._table = []; + this._maxIndex = undefined; + } + initOffsets() { + const me = this; + const timestamps = me._getTimestampsForTable(); + me._table = me.buildLookupTable(timestamps); + me._maxIndex = me._table.length - 1; + super.initOffsets(timestamps); + } + buildLookupTable(timestamps) { + const me = this; + const {min, max} = me; + if (!timestamps.length) { + return [ + {time: min, pos: 0}, + {time: max, pos: 1} + ]; + } + const items = [min]; + let i, ilen, curr; + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + curr = timestamps[i]; + if (curr > min && curr < max) { + items.push(curr); + } + } + items.push(max); + return items; + } + _getTimestampsForTable() { + const me = this; + let timestamps = me._cache.all || []; + if (timestamps.length) { + return timestamps; + } + const data = me.getDataTimestamps(); + const label = me.getLabelTimestamps(); + if (data.length && label.length) { + timestamps = me.normalize(data.concat(label)); + } else { + timestamps = data.length ? data : label; + } + timestamps = me._cache.all = timestamps; + return timestamps; + } + getPixelForValue(value, index) { + const me = this; + const offsets = me._offsets; + const pos = me._normalized && me._maxIndex > 0 && !isNullOrUndef(index) + ? index / me._maxIndex : me.getDecimalForValue(value); + return me.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + getDecimalForValue(value) { + return interpolate(this._table, value) / this._maxIndex; + } + getValueForPixel(pixel) { + const me = this; + const offsets = me._offsets; + const decimal = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return interpolate(me._table, decimal * this._maxIndex, true); + } +} +TimeSeriesScale.id = 'timeseries'; +TimeSeriesScale.defaults = TimeScale.defaults; + +export { Animation, Animations, Arc, BarController, BasePlatform, BasicPlatform, BubbleController, CategoryScale, Chart, DatasetController, DomPlatform, DoughnutController, Element, plugin_filler as Filler, Interaction, plugin_legend as Legend, Line, LineController, LinearScale, LogarithmicScale, PieController, Point, PolarAreaController, RadarController, RadialLinearScale, Rectangle, Scale, ScatterController, Ticks, TimeScale, TimeSeriesScale, plugin_title as Title, plugin_tooltip as Tooltip, adapters as _adapters, animator, layouts, PluginService as plugins, registry }; diff --git a/dist/chart.js b/dist/chart.js new file mode 100644 index 00000000000..dc2b56830c2 --- /dev/null +++ b/dist/chart.js @@ -0,0 +1,13156 @@ +/*! + * Chart.js v3.0.0-beta.2 + * https://www.chartjs.org + * (c) 2020 Chart.js Contributors + * Released under the MIT License + */ +(function (global, factory) { +typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : +typeof define === 'function' && define.amd ? define(factory) : +(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chart = factory()); +}(this, (function () { 'use strict'; + +function _defineProperties(target, props) { + for (var i = 0; i < props.length; i++) { + var descriptor = props[i]; + descriptor.enumerable = descriptor.enumerable || false; + descriptor.configurable = true; + if ("value" in descriptor) descriptor.writable = true; + Object.defineProperty(target, descriptor.key, descriptor); + } +} + +function _createClass(Constructor, protoProps, staticProps) { + if (protoProps) _defineProperties(Constructor.prototype, protoProps); + if (staticProps) _defineProperties(Constructor, staticProps); + return Constructor; +} + +function _extends() { + _extends = Object.assign || function (target) { + for (var i = 1; i < arguments.length; i++) { + var source = arguments[i]; + + for (var key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + target[key] = source[key]; + } + } + } + + return target; + }; + + return _extends.apply(this, arguments); +} + +function _inheritsLoose(subClass, superClass) { + subClass.prototype = Object.create(superClass.prototype); + subClass.prototype.constructor = subClass; + subClass.__proto__ = superClass; +} + +function _objectWithoutPropertiesLoose(source, excluded) { + if (source == null) return {}; + var target = {}; + var sourceKeys = Object.keys(source); + var key, i; + + for (i = 0; i < sourceKeys.length; i++) { + key = sourceKeys[i]; + if (excluded.indexOf(key) >= 0) continue; + target[key] = source[key]; + } + + return target; +} + +function _assertThisInitialized(self) { + if (self === void 0) { + throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); + } + + return self; +} + +function fontString(pixelSize, fontStyle, fontFamily) { + return fontStyle + ' ' + pixelSize + 'px ' + fontFamily; +} +var requestAnimFrame = function () { + if (typeof window === 'undefined') { + return function (callback) { + return callback(); + }; + } + return window.requestAnimationFrame; +}(); +function throttled(fn, thisArg, updateFn) { + var updateArgs = updateFn || function (args) { + return Array.prototype.slice.call(args); + }; + var ticking = false; + var args = []; + return function () { + for (var _len = arguments.length, rest = new Array(_len), _key = 0; _key < _len; _key++) { + rest[_key] = arguments[_key]; + } + args = updateArgs(rest); + if (!ticking) { + ticking = true; + requestAnimFrame.call(window, function () { + ticking = false; + fn.apply(thisArg, args); + }); + } + }; +} + +function drawFPS(chart, count, date, lastDate) { + var fps = 1000 / (date - lastDate) | 0; + var ctx = chart.ctx; + ctx.save(); + ctx.clearRect(0, 0, 50, 24); + ctx.fillStyle = 'black'; + ctx.textAlign = 'right'; + if (count) { + ctx.fillText(count, 50, 8); + ctx.fillText(fps + ' fps', 50, 18); + } + ctx.restore(); +} +var Animator = function () { + function Animator() { + this._request = null; + this._charts = new Map(); + this._running = false; + this._lastDate = undefined; + } + var _proto = Animator.prototype; + _proto._notify = function _notify(chart, anims, date, type) { + var callbacks = anims.listeners[type] || []; + var numSteps = anims.duration; + callbacks.forEach(function (fn) { + return fn({ + chart: chart, + numSteps: numSteps, + currentStep: Math.min(date - anims.start, numSteps) + }); + }); + } + ; + _proto._refresh = function _refresh() { + var me = this; + if (me._request) { + return; + } + me._running = true; + me._request = requestAnimFrame.call(window, function () { + me._update(); + me._request = null; + if (me._running) { + me._refresh(); + } + }); + } + ; + _proto._update = function _update() { + var me = this; + var date = Date.now(); + var remaining = 0; + me._charts.forEach(function (anims, chart) { + if (!anims.running || !anims.items.length) { + return; + } + var items = anims.items; + var i = items.length - 1; + var draw = false; + var item; + for (; i >= 0; --i) { + item = items[i]; + if (item._active) { + item.tick(date); + draw = true; + } else { + items[i] = items[items.length - 1]; + items.pop(); + } + } + if (draw) { + chart.draw(); + me._notify(chart, anims, date, 'progress'); + } + if (chart.options.animation.debug) { + drawFPS(chart, items.length, date, me._lastDate); + } + if (!items.length) { + anims.running = false; + me._notify(chart, anims, date, 'complete'); + } + remaining += items.length; + }); + me._lastDate = date; + if (remaining === 0) { + me._running = false; + } + } + ; + _proto._getAnims = function _getAnims(chart) { + var charts = this._charts; + var anims = charts.get(chart); + if (!anims) { + anims = { + running: false, + items: [], + listeners: { + complete: [], + progress: [] + } + }; + charts.set(chart, anims); + } + return anims; + } + ; + _proto.listen = function listen(chart, event, cb) { + this._getAnims(chart).listeners[event].push(cb); + } + ; + _proto.add = function add(chart, items) { + var _this$_getAnims$items; + if (!items || !items.length) { + return; + } + (_this$_getAnims$items = this._getAnims(chart).items).push.apply(_this$_getAnims$items, items); + } + ; + _proto.has = function has(chart) { + return this._getAnims(chart).items.length > 0; + } + ; + _proto.start = function start(chart) { + var anims = this._charts.get(chart); + if (!anims) { + return; + } + anims.running = true; + anims.start = Date.now(); + anims.duration = anims.items.reduce(function (acc, cur) { + return Math.max(acc, cur._duration); + }, 0); + this._refresh(); + }; + _proto.running = function running(chart) { + if (!this._running) { + return false; + } + var anims = this._charts.get(chart); + if (!anims || !anims.running || !anims.items.length) { + return false; + } + return true; + } + ; + _proto.stop = function stop(chart) { + var anims = this._charts.get(chart); + if (!anims || !anims.items.length) { + return; + } + var items = anims.items; + var i = items.length - 1; + for (; i >= 0; --i) { + items[i].cancel(); + } + anims.items = []; + this._notify(chart, anims, Date.now(), 'complete'); + } + ; + _proto.remove = function remove(chart) { + return this._charts["delete"](chart); + }; + return Animator; +}(); +var animator = new Animator(); + +function noop() {} +var uid = function () { + var id = 0; + return function () { + return id++; + }; +}(); +function isNullOrUndef(value) { + return value === null || typeof value === 'undefined'; +} +function isArray(value) { + if (Array.isArray && Array.isArray(value)) { + return true; + } + var type = Object.prototype.toString.call(value); + if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') { + return true; + } + return false; +} +function isObject(value) { + return value !== null && Object.prototype.toString.call(value) === '[object Object]'; +} +var isNumberFinite = function isNumberFinite(value) { + return (typeof value === 'number' || value instanceof Number) && isFinite(+value); +}; +function valueOrDefault(value, defaultValue) { + return typeof value === 'undefined' ? defaultValue : value; +} +function callback(fn, args, thisArg) { + if (fn && typeof fn.call === 'function') { + return fn.apply(thisArg, args); + } +} +function each(loopable, fn, thisArg, reverse) { + var i, len, keys; + if (isArray(loopable)) { + len = loopable.length; + if (reverse) { + for (i = len - 1; i >= 0; i--) { + fn.call(thisArg, loopable[i], i); + } + } else { + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[i], i); + } + } + } else if (isObject(loopable)) { + keys = Object.keys(loopable); + len = keys.length; + for (i = 0; i < len; i++) { + fn.call(thisArg, loopable[keys[i]], keys[i]); + } + } +} +function _elementsEqual(a0, a1) { + var i, ilen, v0, v1; + if (!a0 || !a1 || a0.length !== a1.length) { + return false; + } + for (i = 0, ilen = a0.length; i < ilen; ++i) { + v0 = a0[i]; + v1 = a1[i]; + if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) { + return false; + } + } + return true; +} +function clone(source) { + if (isArray(source)) { + return source.map(clone); + } + if (isObject(source)) { + var target = {}; + var keys = Object.keys(source); + var klen = keys.length; + var k = 0; + for (; k < klen; ++k) { + target[keys[k]] = clone(source[keys[k]]); + } + return target; + } + return source; +} +function _merger(key, target, source, options) { + var tval = target[key]; + var sval = source[key]; + if (isObject(tval) && isObject(sval)) { + merge(tval, sval, options); + } else { + target[key] = clone(sval); + } +} +function merge(target, source, options) { + var sources = isArray(source) ? source : [source]; + var ilen = sources.length; + if (!isObject(target)) { + return target; + } + options = options || {}; + var merger = options.merger || _merger; + for (var i = 0; i < ilen; ++i) { + source = sources[i]; + if (!isObject(source)) { + continue; + } + var keys = Object.keys(source); + for (var k = 0, klen = keys.length; k < klen; ++k) { + merger(keys[k], target, source, options); + } + } + return target; +} +function mergeIf(target, source) { + return merge(target, source, { + merger: _mergerIf + }); +} +function _mergerIf(key, target, source) { + var tval = target[key]; + var sval = source[key]; + if (isObject(tval) && isObject(sval)) { + mergeIf(tval, sval); + } else if (!Object.prototype.hasOwnProperty.call(target, key)) { + target[key] = clone(sval); + } +} +function _deprecated(scope, value, previous, current) { + if (value !== undefined) { + console.warn(scope + ': "' + previous + '" is deprecated. Please use "' + current + '" instead'); + } +} +function resolveObjectKey(obj, key) { + if (key.length < 3) { + return obj[key]; + } + var keys = key.split('.'); + for (var i = 0, n = keys.length; i < n; ++i) { + var k = keys[i]; + if (k in obj) { + obj = obj[k]; + } else { + return; + } + } + return obj; +} +function _capitalize(str) { + return str.charAt(0).toUpperCase() + str.slice(1); +} + +function getScope(node, key) { + if (!key) { + return node; + } + var keys = key.split('.'); + for (var i = 0, n = keys.length; i < n; ++i) { + var k = keys[i]; + node = node[k] || (node[k] = {}); + } + return node; +} +var Defaults = function () { + function Defaults() { + this.color = 'rgba(0,0,0,0.1)'; + this.elements = {}; + this.events = ['mousemove', 'mouseout', 'click', 'touchstart', 'touchmove']; + this.font = { + color: '#666', + family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif", + size: 12, + style: 'normal', + lineHeight: 1.2, + weight: null, + lineWidth: 0, + strokeStyle: undefined + }; + this.hover = { + onHover: null, + mode: 'nearest', + intersect: true + }; + this.maintainAspectRatio = true; + this.onClick = null; + this.responsive = true; + this.showLines = true; + this.plugins = {}; + this.scale = undefined; + this.doughnut = undefined; + this.scales = {}; + this.controllers = undefined; + } + var _proto = Defaults.prototype; + _proto.set = function set(scope, values) { + return merge(getScope(this, scope), values); + }; + _proto.get = function get(scope) { + return getScope(this, scope); + } + ; + _proto.route = function route(scope, name, targetScope, targetName) { + var _Object$definePropert; + var scopeObject = getScope(this, scope); + var targetScopeObject = getScope(this, targetScope); + var privateName = '_' + name; + Object.defineProperties(scopeObject, (_Object$definePropert = {}, _Object$definePropert[privateName] = { + writable: true + }, _Object$definePropert[name] = { + enumerable: true, + get: function get() { + return valueOrDefault(this[privateName], targetScopeObject[targetName]); + }, + set: function set(value) { + this[privateName] = value; + } + }, _Object$definePropert)); + }; + return Defaults; +}(); +var defaults = new Defaults(); + +var PI = Math.PI; +var RAD_PER_DEG = PI / 180; +var DOUBLE_PI = PI * 2; +var HALF_PI = PI / 2; +var QUARTER_PI = PI / 4; +var TWO_THIRDS_PI = PI * 2 / 3; +function toFontString(font) { + if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) { + return null; + } + return (font.style ? font.style + ' ' : '') + (font.weight ? font.weight + ' ' : '') + font.size + 'px ' + font.family; +} +function _measureText(ctx, data, gc, longest, string) { + var textWidth = data[string]; + if (!textWidth) { + textWidth = data[string] = ctx.measureText(string).width; + gc.push(string); + } + if (textWidth > longest) { + longest = textWidth; + } + return longest; +} +function _longestText(ctx, font, arrayOfThings, cache) { + cache = cache || {}; + var data = cache.data = cache.data || {}; + var gc = cache.garbageCollect = cache.garbageCollect || []; + if (cache.font !== font) { + data = cache.data = {}; + gc = cache.garbageCollect = []; + cache.font = font; + } + ctx.save(); + ctx.font = font; + var longest = 0; + var ilen = arrayOfThings.length; + var i, j, jlen, thing, nestedThing; + for (i = 0; i < ilen; i++) { + thing = arrayOfThings[i]; + if (thing !== undefined && thing !== null && isArray(thing) !== true) { + longest = _measureText(ctx, data, gc, longest, thing); + } else if (isArray(thing)) { + for (j = 0, jlen = thing.length; j < jlen; j++) { + nestedThing = thing[j]; + if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) { + longest = _measureText(ctx, data, gc, longest, nestedThing); + } + } + } + } + ctx.restore(); + var gcLen = gc.length / 2; + if (gcLen > arrayOfThings.length) { + for (i = 0; i < gcLen; i++) { + delete data[gc[i]]; + } + gc.splice(0, gcLen); + } + return longest; +} +function _alignPixel(chart, pixel, width) { + var devicePixelRatio = chart.currentDevicePixelRatio; + var halfWidth = width / 2; + return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth; +} +function clear(chart) { + chart.ctx.clearRect(0, 0, chart.width, chart.height); +} +function drawPoint(ctx, options, x, y) { + var type, xOffset, yOffset, size, cornerRadius; + var style = options.pointStyle; + var rotation = options.rotation; + var radius = options.radius; + var rad = (rotation || 0) * RAD_PER_DEG; + if (style && typeof style === 'object') { + type = style.toString(); + if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') { + ctx.save(); + ctx.translate(x, y); + ctx.rotate(rad); + ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height); + ctx.restore(); + return; + } + } + if (isNaN(radius) || radius <= 0) { + return; + } + ctx.beginPath(); + switch (style) { + default: + ctx.arc(x, y, radius, 0, DOUBLE_PI); + ctx.closePath(); + break; + case 'triangle': + ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + rad += TWO_THIRDS_PI; + ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius); + ctx.closePath(); + break; + case 'rectRounded': + cornerRadius = radius * 0.516; + size = radius - cornerRadius; + xOffset = Math.cos(rad + QUARTER_PI) * size; + yOffset = Math.sin(rad + QUARTER_PI) * size; + ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI); + ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad); + ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI); + ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI); + ctx.closePath(); + break; + case 'rect': + if (!rotation) { + size = Math.SQRT1_2 * radius; + ctx.rect(x - size, y - size, 2 * size, 2 * size); + break; + } + rad += QUARTER_PI; + case 'rectRot': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + yOffset, y - xOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.lineTo(x - yOffset, y + xOffset); + ctx.closePath(); + break; + case 'crossRot': + rad += QUARTER_PI; + case 'cross': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + break; + case 'star': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + rad += QUARTER_PI; + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + ctx.moveTo(x + yOffset, y - xOffset); + ctx.lineTo(x - yOffset, y + xOffset); + break; + case 'line': + xOffset = Math.cos(rad) * radius; + yOffset = Math.sin(rad) * radius; + ctx.moveTo(x - xOffset, y - yOffset); + ctx.lineTo(x + xOffset, y + yOffset); + break; + case 'dash': + ctx.moveTo(x, y); + ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius); + break; + } + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } +} +function _isPointInArea(point, area) { + var epsilon = 0.5; + return point.x > area.left - epsilon && point.x < area.right + epsilon && point.y > area.top - epsilon && point.y < area.bottom + epsilon; +} +function clipArea(ctx, area) { + ctx.save(); + ctx.beginPath(); + ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top); + ctx.clip(); +} +function unclipArea(ctx) { + ctx.restore(); +} +function _steppedLineTo(ctx, previous, target, flip, mode) { + if (!previous) { + return ctx.lineTo(target.x, target.y); + } + if (mode === 'middle') { + var midpoint = (previous.x + target.x) / 2.0; + ctx.lineTo(midpoint, previous.y); + ctx.lineTo(midpoint, target.y); + } else if (mode === 'after' !== !!flip) { + ctx.lineTo(previous.x, target.y); + } else { + ctx.lineTo(target.x, previous.y); + } + ctx.lineTo(target.x, target.y); +} +function _bezierCurveTo(ctx, previous, target, flip) { + if (!previous) { + return ctx.lineTo(target.x, target.y); + } + ctx.bezierCurveTo(flip ? previous.controlPointPreviousX : previous.controlPointNextX, flip ? previous.controlPointPreviousY : previous.controlPointNextY, flip ? target.controlPointNextX : target.controlPointPreviousX, flip ? target.controlPointNextY : target.controlPointPreviousY, target.x, target.y); +} + +function _lookup(table, value, cmp) { + cmp = cmp || function (index) { + return table[index] < value; + }; + var hi = table.length - 1; + var lo = 0; + var mid; + while (hi - lo > 1) { + mid = lo + hi >> 1; + if (cmp(mid)) { + lo = mid; + } else { + hi = mid; + } + } + return { + lo: lo, + hi: hi + }; +} +var _lookupByKey = function _lookupByKey(table, key, value) { + return _lookup(table, value, function (index) { + return table[index][key] < value; + }); +}; +var _rlookupByKey = function _rlookupByKey(table, key, value) { + return _lookup(table, value, function (index) { + return table[index][key] >= value; + }); +}; +function _filterBetween(values, min, max) { + var start = 0; + var end = values.length; + while (start < end && values[start] < min) { + start++; + } + while (end > start && values[end - 1] > max) { + end--; + } + return start > 0 || end < values.length ? values.slice(start, end) : values; +} +var arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift']; +function listenArrayEvents(array, listener) { + if (array._chartjs) { + array._chartjs.listeners.push(listener); + return; + } + Object.defineProperty(array, '_chartjs', { + configurable: true, + enumerable: false, + value: { + listeners: [listener] + } + }); + arrayEvents.forEach(function (key) { + var method = '_onData' + _capitalize(key); + var base = array[key]; + Object.defineProperty(array, key, { + configurable: true, + enumerable: false, + value: function value() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + var res = base.apply(this, args); + array._chartjs.listeners.forEach(function (object) { + if (typeof object[method] === 'function') { + object[method].apply(object, args); + } + }); + return res; + } + }); + }); +} +function unlistenArrayEvents(array, listener) { + var stub = array._chartjs; + if (!stub) { + return; + } + var listeners = stub.listeners; + var index = listeners.indexOf(listener); + if (index !== -1) { + listeners.splice(index, 1); + } + if (listeners.length > 0) { + return; + } + arrayEvents.forEach(function (key) { + delete array[key]; + }); + delete array._chartjs; +} +function _arrayUnique(items) { + var set = new Set(); + var i, ilen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + set.add(items[i]); + } + if (set.size === ilen) { + return items; + } + var result = []; + set.forEach(function (item) { + result.push(item); + }); + return result; +} + +function _getParentNode(domNode) { + var parent = domNode.parentNode; + if (parent && parent.toString() === '[object ShadowRoot]') { + parent = parent.host; + } + return parent; +} +function parseMaxStyle(styleValue, node, parentProperty) { + var valueInPixels; + if (typeof styleValue === 'string') { + valueInPixels = parseInt(styleValue, 10); + if (styleValue.indexOf('%') !== -1) { + valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty]; + } + } else { + valueInPixels = styleValue; + } + return valueInPixels; +} +var getComputedStyle = function getComputedStyle(element) { + return window.getComputedStyle(element, null); +}; +function getStyle(el, property) { + return el.currentStyle ? el.currentStyle[property] : getComputedStyle(el).getPropertyValue(property); +} +var positions = ['top', 'right', 'bottom', 'left']; +function getPositionedStyle(styles, style, suffix) { + var result = {}; + suffix = suffix ? '-' + suffix : ''; + for (var i = 0; i < 4; i++) { + var pos = positions[i]; + result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0; + } + result.width = result.left + result.right; + result.height = result.top + result.bottom; + return result; +} +function getCanvasPosition(evt, canvas) { + var e = evt.originalEvent || evt; + var touches = e.touches; + var source = touches && touches.length ? touches[0] : e; + var offsetX = source.offsetX, + offsetY = source.offsetY; + var box = false; + var x, y; + if (offsetX > 0 || offsetY > 0) { + x = offsetX; + y = offsetY; + } else { + var rect = canvas.getBoundingClientRect(); + x = source.clientX - rect.left; + y = source.clientY - rect.top; + box = true; + } + return { + x: x, + y: y, + box: box + }; +} +function getRelativePosition(evt, chart) { + var canvas = chart.canvas, + currentDevicePixelRatio = chart.currentDevicePixelRatio; + var style = getComputedStyle(canvas); + var borderBox = style.boxSizing === 'border-box'; + var paddings = getPositionedStyle(style, 'padding'); + var borders = getPositionedStyle(style, 'border', 'width'); + var _getCanvasPosition = getCanvasPosition(evt, canvas), + x = _getCanvasPosition.x, + y = _getCanvasPosition.y, + box = _getCanvasPosition.box; + var xOffset = paddings.left + (box && borders.left); + var yOffset = paddings.top + (box && borders.top); + var width = chart.width, + height = chart.height; + if (borderBox) { + width -= paddings.width + borders.width; + height -= paddings.height + borders.height; + } + return { + x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio), + y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio) + }; +} +var infinity = Number.POSITIVE_INFINITY; +function getContainerSize(canvas, width, height) { + var maxWidth, maxHeight; + if (width === undefined || height === undefined) { + var container = _getParentNode(canvas); + if (!container) { + width = canvas.clientWidth; + height = canvas.clientHeight; + } else { + var rect = container.getBoundingClientRect(); + var containerStyle = getComputedStyle(container); + var containerBorder = getPositionedStyle(containerStyle, 'border', 'width'); + var contarinerPadding = getPositionedStyle(containerStyle, 'padding'); + width = rect.width - contarinerPadding.width - containerBorder.width; + height = rect.height - contarinerPadding.height - containerBorder.height; + maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth'); + maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight'); + } + } + return { + width: width, + height: height, + maxWidth: maxWidth || infinity, + maxHeight: maxHeight || infinity + }; +} +function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) { + var style = getComputedStyle(canvas); + var margins = getPositionedStyle(style, 'margin'); + var maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || infinity; + var maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || infinity; + var containerSize = getContainerSize(canvas, bbWidth, bbHeight); + var width = containerSize.width, + height = containerSize.height; + if (style.boxSizing === 'content-box') { + var borders = getPositionedStyle(style, 'border', 'width'); + var paddings = getPositionedStyle(style, 'padding'); + width -= paddings.width + borders.width; + height -= paddings.height + borders.height; + } + width = Math.max(0, width - margins.width); + height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height); + return { + width: Math.min(width, maxWidth, containerSize.maxWidth), + height: Math.min(height, maxHeight, containerSize.maxHeight) + }; +} +function retinaScale(chart, forceRatio) { + var pixelRatio = chart.currentDevicePixelRatio = forceRatio || typeof window !== 'undefined' && window.devicePixelRatio || 1; + var canvas = chart.canvas, + width = chart.width, + height = chart.height; + canvas.height = height * pixelRatio; + canvas.width = width * pixelRatio; + chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0); + if (canvas.style && !canvas.style.height && !canvas.style.width) { + canvas.style.height = height + 'px'; + canvas.style.width = width + 'px'; + } +} +var supportsEventListenerOptions = function () { + var passiveSupported = false; + try { + var options = { + get passive() { + passiveSupported = true; + return false; + } + }; + window.addEventListener('test', null, options); + window.removeEventListener('test', null, options); + } catch (e) { + } + return passiveSupported; +}(); +function readUsedSize(element, property) { + var value = getStyle(element, property); + var matches = value && value.match(/^(\d+)(\.\d+)?px$/); + return matches ? +matches[1] : undefined; +} + +function getRelativePosition$1(e, chart) { + if ('native' in e) { + return { + x: e.x, + y: e.y + }; + } + return getRelativePosition(e, chart); +} +function evaluateAllVisibleItems(chart, handler) { + var metasets = chart.getSortedVisibleDatasetMetas(); + var index, data, element; + for (var i = 0, ilen = metasets.length; i < ilen; ++i) { + var _metasets$i = metasets[i]; + index = _metasets$i.index; + data = _metasets$i.data; + for (var j = 0, jlen = data.length; j < jlen; ++j) { + element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function binarySearch(metaset, axis, value, intersect) { + var controller = metaset.controller, + data = metaset.data, + _sorted = metaset._sorted; + var iScale = controller._cachedMeta.iScale; + if (iScale && axis === iScale.axis && _sorted && data.length) { + var lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey; + if (!intersect) { + return lookupMethod(data, axis, value); + } else if (controller._sharedOptions) { + var el = data[0]; + var range = typeof el.getRange === 'function' && el.getRange(axis); + if (range) { + var start = lookupMethod(data, axis, value - range); + var end = lookupMethod(data, axis, value + range); + return { + lo: start.lo, + hi: end.hi + }; + } + } + } + return { + lo: 0, + hi: data.length - 1 + }; +} +function optimizedEvaluateItems(chart, axis, position, handler, intersect) { + var metasets = chart.getSortedVisibleDatasetMetas(); + var value = position[axis]; + for (var i = 0, ilen = metasets.length; i < ilen; ++i) { + var _metasets$i2 = metasets[i], + index = _metasets$i2.index, + data = _metasets$i2.data; + var _binarySearch = binarySearch(metasets[i], axis, value, intersect), + lo = _binarySearch.lo, + hi = _binarySearch.hi; + for (var j = lo; j <= hi; ++j) { + var element = data[j]; + if (!element.skip) { + handler(element, index, j); + } + } + } +} +function getDistanceMetricForAxis(axis) { + var useX = axis.indexOf('x') !== -1; + var useY = axis.indexOf('y') !== -1; + return function (pt1, pt2) { + var deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0; + var deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0; + return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2)); + }; +} +function getIntersectItems(chart, position, axis, useFinalPosition) { + var items = []; + if (!_isPointInArea(position, chart.chartArea)) { + return items; + } + var evaluationFunc = function evaluationFunc(element, datasetIndex, index) { + if (element.inRange(position.x, position.y, useFinalPosition)) { + items.push({ + element: element, + datasetIndex: datasetIndex, + index: index + }); + } + }; + optimizedEvaluateItems(chart, axis, position, evaluationFunc, true); + return items; +} +function getNearestItems(chart, position, axis, intersect, useFinalPosition) { + var distanceMetric = getDistanceMetricForAxis(axis); + var minDistance = Number.POSITIVE_INFINITY; + var items = []; + if (!_isPointInArea(position, chart.chartArea)) { + return items; + } + var evaluationFunc = function evaluationFunc(element, datasetIndex, index) { + if (intersect && !element.inRange(position.x, position.y, useFinalPosition)) { + return; + } + var center = element.getCenterPoint(useFinalPosition); + var distance = distanceMetric(position, center); + if (distance < minDistance) { + items = [{ + element: element, + datasetIndex: datasetIndex, + index: index + }]; + minDistance = distance; + } else if (distance === minDistance) { + items.push({ + element: element, + datasetIndex: datasetIndex, + index: index + }); + } + }; + optimizedEvaluateItems(chart, axis, position, evaluationFunc); + return items; +} +function getAxisItems(chart, e, options, useFinalPosition) { + var position = getRelativePosition$1(e, chart); + var items = []; + var axis = options.axis; + var rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange'; + var intersectsItem = false; + evaluateAllVisibleItems(chart, function (element, datasetIndex, index) { + if (element[rangeMethod](position[axis], useFinalPosition)) { + items.push({ + element: element, + datasetIndex: datasetIndex, + index: index + }); + } + if (element.inRange(position.x, position.y, useFinalPosition)) { + intersectsItem = true; + } + }); + if (options.intersect && !intersectsItem) { + return []; + } + return items; +} +var Interaction = { + modes: { + index: function index(chart, e, options, useFinalPosition) { + var position = getRelativePosition$1(e, chart); + var axis = options.axis || 'x'; + var items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition) : getNearestItems(chart, position, axis, false, useFinalPosition); + var elements = []; + if (!items.length) { + return []; + } + chart.getSortedVisibleDatasetMetas().forEach(function (meta) { + var index = items[0].index; + var element = meta.data[index]; + if (element && !element.skip) { + elements.push({ + element: element, + datasetIndex: meta.index, + index: index + }); + } + }); + return elements; + }, + dataset: function dataset(chart, e, options, useFinalPosition) { + var position = getRelativePosition$1(e, chart); + var axis = options.axis || 'xy'; + var items = options.intersect ? getIntersectItems(chart, position, axis, useFinalPosition) : getNearestItems(chart, position, axis, false, useFinalPosition); + if (items.length > 0) { + var datasetIndex = items[0].datasetIndex; + var data = chart.getDatasetMeta(datasetIndex).data; + items = []; + for (var i = 0; i < data.length; ++i) { + items.push({ + element: data[i], + datasetIndex: datasetIndex, + index: i + }); + } + } + return items; + }, + point: function point(chart, e, options, useFinalPosition) { + var position = getRelativePosition$1(e, chart); + var axis = options.axis || 'xy'; + return getIntersectItems(chart, position, axis, useFinalPosition); + }, + nearest: function nearest(chart, e, options, useFinalPosition) { + var position = getRelativePosition$1(e, chart); + var axis = options.axis || 'xy'; + return getNearestItems(chart, position, axis, options.intersect, useFinalPosition); + }, + x: function x(chart, e, options, useFinalPosition) { + options.axis = 'x'; + return getAxisItems(chart, e, options, useFinalPosition); + }, + y: function y(chart, e, options, useFinalPosition) { + options.axis = 'y'; + return getAxisItems(chart, e, options, useFinalPosition); + } + } +}; + +function toLineHeight(value, size) { + var matches = ('' + value).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/); + if (!matches || matches[1] === 'normal') { + return size * 1.2; + } + value = +matches[2]; + switch (matches[3]) { + case 'px': + return value; + case '%': + value /= 100; + break; + } + return size * value; +} +var numberOrZero = function numberOrZero(v) { + return +v || 0; +}; +function toTRBL(value) { + var t, r, b, l; + if (isObject(value)) { + t = numberOrZero(value.top); + r = numberOrZero(value.right); + b = numberOrZero(value.bottom); + l = numberOrZero(value.left); + } else { + t = r = b = l = numberOrZero(value); + } + return { + top: t, + right: r, + bottom: b, + left: l + }; +} +function toPadding(value) { + var obj = toTRBL(value); + obj.width = obj.left + obj.right; + obj.height = obj.top + obj.bottom; + return obj; +} +function toFont(options, fallback) { + options = options || {}; + fallback = fallback || defaults.font; + var size = valueOrDefault(options.size, fallback.size); + if (typeof size === 'string') { + size = parseInt(size, 10); + } + var font = { + color: valueOrDefault(options.color, fallback.color), + family: valueOrDefault(options.family, fallback.family), + lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size), + lineWidth: valueOrDefault(options.lineWidth, fallback.lineWidth), + size: size, + style: valueOrDefault(options.style, fallback.style), + weight: valueOrDefault(options.weight, fallback.weight), + strokeStyle: valueOrDefault(options.strokeStyle, fallback.strokeStyle), + string: '' + }; + font.string = toFontString(font); + return font; +} +function resolve(inputs, context, index, info) { + var cacheable = true; + var i, ilen, value; + for (i = 0, ilen = inputs.length; i < ilen; ++i) { + value = inputs[i]; + if (value === undefined) { + continue; + } + if (context !== undefined && typeof value === 'function') { + value = value(context); + cacheable = false; + } + if (index !== undefined && isArray(value)) { + value = value[index % value.length]; + cacheable = false; + } + if (value !== undefined) { + if (info && !cacheable) { + info.cacheable = false; + } + return value; + } + } +} + +var STATIC_POSITIONS = ['left', 'top', 'right', 'bottom']; +function filterByPosition(array, position) { + return array.filter(function (v) { + return v.pos === position; + }); +} +function filterDynamicPositionByAxis(array, axis) { + return array.filter(function (v) { + return STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis; + }); +} +function sortByWeight(array, reverse) { + return array.sort(function (a, b) { + var v0 = reverse ? b : a; + var v1 = reverse ? a : b; + return v0.weight === v1.weight ? v0.index - v1.index : v0.weight - v1.weight; + }); +} +function wrapBoxes(boxes) { + var layoutBoxes = []; + var i, ilen, box; + for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) { + box = boxes[i]; + layoutBoxes.push({ + index: i, + box: box, + pos: box.position, + horizontal: box.isHorizontal(), + weight: box.weight + }); + } + return layoutBoxes; +} +function setLayoutDims(layouts, params) { + var i, ilen, layout; + for (i = 0, ilen = layouts.length; i < ilen; ++i) { + layout = layouts[i]; + layout.width = layout.horizontal ? layout.box.fullWidth && params.availableWidth : params.vBoxMaxWidth; + layout.height = layout.horizontal && params.hBoxMaxHeight; + } +} +function buildLayoutBoxes(boxes) { + var layoutBoxes = wrapBoxes(boxes); + var left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true); + var right = sortByWeight(filterByPosition(layoutBoxes, 'right')); + var top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true); + var bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom')); + var centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x'); + var centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y'); + return { + leftAndTop: left.concat(top), + rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal), + chartArea: filterByPosition(layoutBoxes, 'chartArea'), + vertical: left.concat(right).concat(centerVertical), + horizontal: top.concat(bottom).concat(centerHorizontal) + }; +} +function getCombinedMax(maxPadding, chartArea, a, b) { + return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]); +} +function updateDims(chartArea, params, layout) { + var box = layout.box; + var maxPadding = chartArea.maxPadding; + if (layout.size) { + chartArea[layout.pos] -= layout.size; + } + layout.size = layout.horizontal ? box.height : box.width; + chartArea[layout.pos] += layout.size; + if (box.getPadding) { + var boxPadding = box.getPadding(); + maxPadding.top = Math.max(maxPadding.top, boxPadding.top); + maxPadding.left = Math.max(maxPadding.left, boxPadding.left); + maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom); + maxPadding.right = Math.max(maxPadding.right, boxPadding.right); + } + var newWidth = params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'); + var newHeight = params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'); + if (newWidth !== chartArea.w || newHeight !== chartArea.h) { + chartArea.w = newWidth; + chartArea.h = newHeight; + return layout.horizontal ? newWidth !== chartArea.w : newHeight !== chartArea.h; + } +} +function handleMaxPadding(chartArea) { + var maxPadding = chartArea.maxPadding; + function updatePos(pos) { + var change = Math.max(maxPadding[pos] - chartArea[pos], 0); + chartArea[pos] += change; + return change; + } + chartArea.y += updatePos('top'); + chartArea.x += updatePos('left'); + updatePos('right'); + updatePos('bottom'); +} +function getMargins(horizontal, chartArea) { + var maxPadding = chartArea.maxPadding; + function marginForPositions(positions) { + var margin = { + left: 0, + top: 0, + right: 0, + bottom: 0 + }; + positions.forEach(function (pos) { + margin[pos] = Math.max(chartArea[pos], maxPadding[pos]); + }); + return margin; + } + return horizontal ? marginForPositions(['left', 'right']) : marginForPositions(['top', 'bottom']); +} +function fitBoxes(boxes, chartArea, params) { + var refitBoxes = []; + var i, ilen, layout, box, refit, changed; + for (i = 0, ilen = boxes.length; i < ilen; ++i) { + layout = boxes[i]; + box = layout.box; + box.update(layout.width || chartArea.w, layout.height || chartArea.h, getMargins(layout.horizontal, chartArea)); + if (updateDims(chartArea, params, layout)) { + changed = true; + if (refitBoxes.length) { + refit = true; + } + } + if (!box.fullWidth) { + refitBoxes.push(layout); + } + } + return refit ? fitBoxes(refitBoxes, chartArea, params) || changed : changed; +} +function placeBoxes(boxes, chartArea, params) { + var userPadding = params.padding; + var x = chartArea.x; + var y = chartArea.y; + var i, ilen, layout, box; + for (i = 0, ilen = boxes.length; i < ilen; ++i) { + layout = boxes[i]; + box = layout.box; + if (layout.horizontal) { + box.left = box.fullWidth ? userPadding.left : chartArea.left; + box.right = box.fullWidth ? params.outerWidth - userPadding.right : chartArea.left + chartArea.w; + box.top = y; + box.bottom = y + box.height; + box.width = box.right - box.left; + y = box.bottom; + } else { + box.left = x; + box.right = x + box.width; + box.top = chartArea.top; + box.bottom = chartArea.top + chartArea.h; + box.height = box.bottom - box.top; + x = box.right; + } + } + chartArea.x = x; + chartArea.y = y; +} +defaults.set('layout', { + padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + } +}); +var layouts = { + addBox: function addBox(chart, item) { + if (!chart.boxes) { + chart.boxes = []; + } + item.fullWidth = item.fullWidth || false; + item.position = item.position || 'top'; + item.weight = item.weight || 0; + item._layers = item._layers || function () { + return [{ + z: 0, + draw: function draw(chartArea) { + item.draw(chartArea); + } + }]; + }; + chart.boxes.push(item); + }, + removeBox: function removeBox(chart, layoutItem) { + var index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1; + if (index !== -1) { + chart.boxes.splice(index, 1); + } + }, + configure: function configure(chart, item, options) { + var props = ['fullWidth', 'position', 'weight']; + var ilen = props.length; + var i = 0; + var prop; + for (; i < ilen; ++i) { + prop = props[i]; + if (Object.prototype.hasOwnProperty.call(options, prop)) { + item[prop] = options[prop]; + } + } + }, + update: function update(chart, width, height) { + if (!chart) { + return; + } + var layoutOptions = chart.options.layout || {}; + var padding = toPadding(layoutOptions.padding); + var availableWidth = width - padding.width; + var availableHeight = height - padding.height; + var boxes = buildLayoutBoxes(chart.boxes); + var verticalBoxes = boxes.vertical; + var horizontalBoxes = boxes.horizontal; + var params = Object.freeze({ + outerWidth: width, + outerHeight: height, + padding: padding, + availableWidth: availableWidth, + vBoxMaxWidth: availableWidth / 2 / verticalBoxes.length, + hBoxMaxHeight: availableHeight / 2 + }); + var chartArea = _extends({ + maxPadding: _extends({}, padding), + w: availableWidth, + h: availableHeight, + x: padding.left, + y: padding.top + }, padding); + setLayoutDims(verticalBoxes.concat(horizontalBoxes), params); + fitBoxes(verticalBoxes, chartArea, params); + if (fitBoxes(horizontalBoxes, chartArea, params)) { + fitBoxes(verticalBoxes, chartArea, params); + } + handleMaxPadding(chartArea); + placeBoxes(boxes.leftAndTop, chartArea, params); + chartArea.x += chartArea.w; + chartArea.y += chartArea.h; + placeBoxes(boxes.rightAndBottom, chartArea, params); + chart.chartArea = { + left: chartArea.left, + top: chartArea.top, + right: chartArea.left + chartArea.w, + bottom: chartArea.top + chartArea.h, + height: chartArea.h, + width: chartArea.w + }; + each(boxes.chartArea, function (layout) { + var box = layout.box; + _extends(box, chart.chartArea); + box.update(chartArea.w, chartArea.h); + }); + } +}; + +var BasePlatform = function () { + function BasePlatform() {} + var _proto = BasePlatform.prototype; + _proto.acquireContext = function acquireContext(canvas, options) {} + ; + _proto.releaseContext = function releaseContext(context) { + return false; + } + ; + _proto.addEventListener = function addEventListener(chart, type, listener) {} + ; + _proto.removeEventListener = function removeEventListener(chart, type, listener) {} + ; + _proto.getDevicePixelRatio = function getDevicePixelRatio() { + return 1; + } + ; + _proto.getMaximumSize = function getMaximumSize(element, width, height, aspectRatio) { + width = Math.max(0, width || element.width); + height = height || element.height; + return { + width: width, + height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height) + }; + } + ; + _proto.isAttached = function isAttached(canvas) { + return true; + }; + return BasePlatform; +}(); + +var BasicPlatform = function (_BasePlatform) { + _inheritsLoose(BasicPlatform, _BasePlatform); + function BasicPlatform() { + return _BasePlatform.apply(this, arguments) || this; + } + var _proto = BasicPlatform.prototype; + _proto.acquireContext = function acquireContext(item) { + return item && item.getContext && item.getContext('2d') || null; + }; + return BasicPlatform; +}(BasePlatform); + +var MapShim = function () { + if (typeof Map !== 'undefined') { + return Map; + } + function getIndex(arr, key) { + var result = -1; + arr.some(function (entry, index) { + if (entry[0] === key) { + result = index; + return true; + } + return false; + }); + return result; + } + return ( + function () { + function class_1() { + this.__entries__ = []; + } + Object.defineProperty(class_1.prototype, "size", { + get: function get() { + return this.__entries__.length; + }, + enumerable: true, + configurable: true + }); + class_1.prototype.get = function (key) { + var index = getIndex(this.__entries__, key); + var entry = this.__entries__[index]; + return entry && entry[1]; + }; + class_1.prototype.set = function (key, value) { + var index = getIndex(this.__entries__, key); + if (~index) { + this.__entries__[index][1] = value; + } else { + this.__entries__.push([key, value]); + } + }; + class_1.prototype["delete"] = function (key) { + var entries = this.__entries__; + var index = getIndex(entries, key); + if (~index) { + entries.splice(index, 1); + } + }; + class_1.prototype.has = function (key) { + return !!~getIndex(this.__entries__, key); + }; + class_1.prototype.clear = function () { + this.__entries__.splice(0); + }; + class_1.prototype.forEach = function (callback, ctx) { + if (ctx === void 0) { + ctx = null; + } + for (var _i = 0, _a = this.__entries__; _i < _a.length; _i++) { + var entry = _a[_i]; + callback.call(ctx, entry[1], entry[0]); + } + }; + return class_1; + }() + ); +}(); +var isBrowser = typeof window !== 'undefined' && typeof document !== 'undefined' && window.document === document; +var global$1 = function () { + if (typeof global !== 'undefined' && global.Math === Math) { + return global; + } + if (typeof self !== 'undefined' && self.Math === Math) { + return self; + } + if (typeof window !== 'undefined' && window.Math === Math) { + return window; + } + return Function('return this')(); +}(); +var requestAnimationFrame$1 = function () { + if (typeof requestAnimationFrame === 'function') { + return requestAnimationFrame.bind(global$1); + } + return function (callback) { + return setTimeout(function () { + return callback(Date.now()); + }, 1000 / 60); + }; +}(); +var trailingTimeout = 2; +function throttle(callback, delay) { + var leadingCall = false, + trailingCall = false, + lastCallTime = 0; + function resolvePending() { + if (leadingCall) { + leadingCall = false; + callback(); + } + if (trailingCall) { + proxy(); + } + } + function timeoutCallback() { + requestAnimationFrame$1(resolvePending); + } + function proxy() { + var timeStamp = Date.now(); + if (leadingCall) { + if (timeStamp - lastCallTime < trailingTimeout) { + return; + } + trailingCall = true; + } else { + leadingCall = true; + trailingCall = false; + setTimeout(timeoutCallback, delay); + } + lastCallTime = timeStamp; + } + return proxy; +} +var REFRESH_DELAY = 20; +var transitionKeys = ['top', 'right', 'bottom', 'left', 'width', 'height', 'size', 'weight']; +var mutationObserverSupported = typeof MutationObserver !== 'undefined'; +var ResizeObserverController = +function () { + function ResizeObserverController() { + this.connected_ = false; + this.mutationEventsAdded_ = false; + this.mutationsObserver_ = null; + this.observers_ = []; + this.onTransitionEnd_ = this.onTransitionEnd_.bind(this); + this.refresh = throttle(this.refresh.bind(this), REFRESH_DELAY); + } + ResizeObserverController.prototype.addObserver = function (observer) { + if (!~this.observers_.indexOf(observer)) { + this.observers_.push(observer); + } + if (!this.connected_) { + this.connect_(); + } + }; + ResizeObserverController.prototype.removeObserver = function (observer) { + var observers = this.observers_; + var index = observers.indexOf(observer); + if (~index) { + observers.splice(index, 1); + } + if (!observers.length && this.connected_) { + this.disconnect_(); + } + }; + ResizeObserverController.prototype.refresh = function () { + var changesDetected = this.updateObservers_(); + if (changesDetected) { + this.refresh(); + } + }; + ResizeObserverController.prototype.updateObservers_ = function () { + var activeObservers = this.observers_.filter(function (observer) { + return observer.gatherActive(), observer.hasActive(); + }); + activeObservers.forEach(function (observer) { + return observer.broadcastActive(); + }); + return activeObservers.length > 0; + }; + ResizeObserverController.prototype.connect_ = function () { + if (!isBrowser || this.connected_) { + return; + } + document.addEventListener('transitionend', this.onTransitionEnd_); + window.addEventListener('resize', this.refresh); + if (mutationObserverSupported) { + this.mutationsObserver_ = new MutationObserver(this.refresh); + this.mutationsObserver_.observe(document, { + attributes: true, + childList: true, + characterData: true, + subtree: true + }); + } else { + document.addEventListener('DOMSubtreeModified', this.refresh); + this.mutationEventsAdded_ = true; + } + this.connected_ = true; + }; + ResizeObserverController.prototype.disconnect_ = function () { + if (!isBrowser || !this.connected_) { + return; + } + document.removeEventListener('transitionend', this.onTransitionEnd_); + window.removeEventListener('resize', this.refresh); + if (this.mutationsObserver_) { + this.mutationsObserver_.disconnect(); + } + if (this.mutationEventsAdded_) { + document.removeEventListener('DOMSubtreeModified', this.refresh); + } + this.mutationsObserver_ = null; + this.mutationEventsAdded_ = false; + this.connected_ = false; + }; + ResizeObserverController.prototype.onTransitionEnd_ = function (_a) { + var _b = _a.propertyName, + propertyName = _b === void 0 ? '' : _b; + var isReflowProperty = transitionKeys.some(function (key) { + return !!~propertyName.indexOf(key); + }); + if (isReflowProperty) { + this.refresh(); + } + }; + ResizeObserverController.getInstance = function () { + if (!this.instance_) { + this.instance_ = new ResizeObserverController(); + } + return this.instance_; + }; + ResizeObserverController.instance_ = null; + return ResizeObserverController; +}(); +var defineConfigurable = function defineConfigurable(target, props) { + for (var _i = 0, _a = Object.keys(props); _i < _a.length; _i++) { + var key = _a[_i]; + Object.defineProperty(target, key, { + value: props[key], + enumerable: false, + writable: false, + configurable: true + }); + } + return target; +}; +var getWindowOf = function getWindowOf(target) { + var ownerGlobal = target && target.ownerDocument && target.ownerDocument.defaultView; + return ownerGlobal || global$1; +}; +var emptyRect = createRectInit(0, 0, 0, 0); +function toFloat(value) { + return parseFloat(value) || 0; +} +function getBordersSize(styles) { + var positions = []; + for (var _i = 1; _i < arguments.length; _i++) { + positions[_i - 1] = arguments[_i]; + } + return positions.reduce(function (size, position) { + var value = styles['border-' + position + '-width']; + return size + toFloat(value); + }, 0); +} +function getPaddings(styles) { + var positions = ['top', 'right', 'bottom', 'left']; + var paddings = {}; + for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) { + var position = positions_1[_i]; + var value = styles['padding-' + position]; + paddings[position] = toFloat(value); + } + return paddings; +} +function getSVGContentRect(target) { + var bbox = target.getBBox(); + return createRectInit(0, 0, bbox.width, bbox.height); +} +function getHTMLElementContentRect(target) { + var clientWidth = target.clientWidth, + clientHeight = target.clientHeight; + if (!clientWidth && !clientHeight) { + return emptyRect; + } + var styles = getWindowOf(target).getComputedStyle(target); + var paddings = getPaddings(styles); + var horizPad = paddings.left + paddings.right; + var vertPad = paddings.top + paddings.bottom; + var width = toFloat(styles.width), + height = toFloat(styles.height); + if (styles.boxSizing === 'border-box') { + if (Math.round(width + horizPad) !== clientWidth) { + width -= getBordersSize(styles, 'left', 'right') + horizPad; + } + if (Math.round(height + vertPad) !== clientHeight) { + height -= getBordersSize(styles, 'top', 'bottom') + vertPad; + } + } + if (!isDocumentElement(target)) { + var vertScrollbar = Math.round(width + horizPad) - clientWidth; + var horizScrollbar = Math.round(height + vertPad) - clientHeight; + if (Math.abs(vertScrollbar) !== 1) { + width -= vertScrollbar; + } + if (Math.abs(horizScrollbar) !== 1) { + height -= horizScrollbar; + } + } + return createRectInit(paddings.left, paddings.top, width, height); +} +var isSVGGraphicsElement = function () { + if (typeof SVGGraphicsElement !== 'undefined') { + return function (target) { + return target instanceof getWindowOf(target).SVGGraphicsElement; + }; + } + return function (target) { + return target instanceof getWindowOf(target).SVGElement && typeof target.getBBox === 'function'; + }; +}(); +function isDocumentElement(target) { + return target === getWindowOf(target).document.documentElement; +} +function getContentRect(target) { + if (!isBrowser) { + return emptyRect; + } + if (isSVGGraphicsElement(target)) { + return getSVGContentRect(target); + } + return getHTMLElementContentRect(target); +} +function createReadOnlyRect(_a) { + var x = _a.x, + y = _a.y, + width = _a.width, + height = _a.height; + var Constr = typeof DOMRectReadOnly !== 'undefined' ? DOMRectReadOnly : Object; + var rect = Object.create(Constr.prototype); + defineConfigurable(rect, { + x: x, + y: y, + width: width, + height: height, + top: y, + right: x + width, + bottom: height + y, + left: x + }); + return rect; +} +function createRectInit(x, y, width, height) { + return { + x: x, + y: y, + width: width, + height: height + }; +} +var ResizeObservation = +function () { + function ResizeObservation(target) { + this.broadcastWidth = 0; + this.broadcastHeight = 0; + this.contentRect_ = createRectInit(0, 0, 0, 0); + this.target = target; + } + ResizeObservation.prototype.isActive = function () { + var rect = getContentRect(this.target); + this.contentRect_ = rect; + return rect.width !== this.broadcastWidth || rect.height !== this.broadcastHeight; + }; + ResizeObservation.prototype.broadcastRect = function () { + var rect = this.contentRect_; + this.broadcastWidth = rect.width; + this.broadcastHeight = rect.height; + return rect; + }; + return ResizeObservation; +}(); +var ResizeObserverEntry = +function () { + function ResizeObserverEntry(target, rectInit) { + var contentRect = createReadOnlyRect(rectInit); + defineConfigurable(this, { + target: target, + contentRect: contentRect + }); + } + return ResizeObserverEntry; +}(); +var ResizeObserverSPI = +function () { + function ResizeObserverSPI(callback, controller, callbackCtx) { + this.activeObservations_ = []; + this.observations_ = new MapShim(); + if (typeof callback !== 'function') { + throw new TypeError('The callback provided as parameter 1 is not a function.'); + } + this.callback_ = callback; + this.controller_ = controller; + this.callbackCtx_ = callbackCtx; + } + ResizeObserverSPI.prototype.observe = function (target) { + if (!arguments.length) { + throw new TypeError('1 argument required, but only 0 present.'); + } + if (typeof Element === 'undefined' || !(Element instanceof Object)) { + return; + } + if (!(target instanceof getWindowOf(target).Element)) { + throw new TypeError('parameter 1 is not of type "Element".'); + } + var observations = this.observations_; + if (observations.has(target)) { + return; + } + observations.set(target, new ResizeObservation(target)); + this.controller_.addObserver(this); + this.controller_.refresh(); + }; + ResizeObserverSPI.prototype.unobserve = function (target) { + if (!arguments.length) { + throw new TypeError('1 argument required, but only 0 present.'); + } + if (typeof Element === 'undefined' || !(Element instanceof Object)) { + return; + } + if (!(target instanceof getWindowOf(target).Element)) { + throw new TypeError('parameter 1 is not of type "Element".'); + } + var observations = this.observations_; + if (!observations.has(target)) { + return; + } + observations["delete"](target); + if (!observations.size) { + this.controller_.removeObserver(this); + } + }; + ResizeObserverSPI.prototype.disconnect = function () { + this.clearActive(); + this.observations_.clear(); + this.controller_.removeObserver(this); + }; + ResizeObserverSPI.prototype.gatherActive = function () { + var _this = this; + this.clearActive(); + this.observations_.forEach(function (observation) { + if (observation.isActive()) { + _this.activeObservations_.push(observation); + } + }); + }; + ResizeObserverSPI.prototype.broadcastActive = function () { + if (!this.hasActive()) { + return; + } + var ctx = this.callbackCtx_; + var entries = this.activeObservations_.map(function (observation) { + return new ResizeObserverEntry(observation.target, observation.broadcastRect()); + }); + this.callback_.call(ctx, entries, ctx); + this.clearActive(); + }; + ResizeObserverSPI.prototype.clearActive = function () { + this.activeObservations_.splice(0); + }; + ResizeObserverSPI.prototype.hasActive = function () { + return this.activeObservations_.length > 0; + }; + return ResizeObserverSPI; +}(); +var observers = typeof WeakMap !== 'undefined' ? new WeakMap() : new MapShim(); +var ResizeObserver = +function () { + function ResizeObserver(callback) { + if (!(this instanceof ResizeObserver)) { + throw new TypeError('Cannot call a class as a function.'); + } + if (!arguments.length) { + throw new TypeError('1 argument required, but only 0 present.'); + } + var controller = ResizeObserverController.getInstance(); + var observer = new ResizeObserverSPI(callback, controller, this); + observers.set(this, observer); + } + return ResizeObserver; +}(); +['observe', 'unobserve', 'disconnect'].forEach(function (method) { + ResizeObserver.prototype[method] = function () { + var _a; + return (_a = observers.get(this))[method].apply(_a, arguments); + }; +}); +var index = function () { + if (typeof global$1.ResizeObserver !== 'undefined') { + return global$1.ResizeObserver; + } + return ResizeObserver; +}(); + +var EXPANDO_KEY = '$chartjs'; +var EVENT_TYPES = { + touchstart: 'mousedown', + touchmove: 'mousemove', + touchend: 'mouseup', + pointerenter: 'mouseenter', + pointerdown: 'mousedown', + pointermove: 'mousemove', + pointerup: 'mouseup', + pointerleave: 'mouseout', + pointerout: 'mouseout' +}; +var isNullOrEmpty = function isNullOrEmpty(value) { + return value === null || value === ''; +}; +function initCanvas(canvas, config) { + var style = canvas.style; + var renderHeight = canvas.getAttribute('height'); + var renderWidth = canvas.getAttribute('width'); + canvas[EXPANDO_KEY] = { + initial: { + height: renderHeight, + width: renderWidth, + style: { + display: style.display, + height: style.height, + width: style.width + } + } + }; + style.display = style.display || 'block'; + style.boxSizing = style.boxSizing || 'border-box'; + if (isNullOrEmpty(renderWidth)) { + var displayWidth = readUsedSize(canvas, 'width'); + if (displayWidth !== undefined) { + canvas.width = displayWidth; + } + } + if (isNullOrEmpty(renderHeight)) { + if (canvas.style.height === '') { + canvas.height = canvas.width / (config.options.aspectRatio || 2); + } else { + var displayHeight = readUsedSize(canvas, 'height'); + if (displayHeight !== undefined) { + canvas.height = displayHeight; + } + } + } + return canvas; +} +var eventListenerOptions = supportsEventListenerOptions ? { + passive: true +} : false; +function addListener(node, type, listener) { + node.addEventListener(type, listener, eventListenerOptions); +} +function removeListener(chart, type, listener) { + chart.canvas.removeEventListener(type, listener, eventListenerOptions); +} +function fromNativeEvent(event, chart) { + var type = EVENT_TYPES[event.type] || event.type; + var _getRelativePosition = getRelativePosition(event, chart), + x = _getRelativePosition.x, + y = _getRelativePosition.y; + return { + type: type, + chart: chart, + "native": event, + x: x !== undefined ? x : null, + y: y !== undefined ? y : null + }; +} +function createAttachObserver(chart, type, listener) { + var canvas = chart.canvas; + var container = canvas && _getParentNode(canvas); + var element = container || canvas; + var observer = new MutationObserver(function (entries) { + var parent = _getParentNode(element); + entries.forEach(function (entry) { + for (var i = 0; i < entry.addedNodes.length; i++) { + var added = entry.addedNodes[i]; + if (added === element || added === parent) { + listener(entry.target); + } + } + }); + }); + observer.observe(document, { + childList: true, + subtree: true + }); + return observer; +} +function createDetachObserver(chart, type, listener) { + var canvas = chart.canvas; + var container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + var observer = new MutationObserver(function (entries) { + entries.forEach(function (entry) { + for (var i = 0; i < entry.removedNodes.length; i++) { + if (entry.removedNodes[i] === canvas) { + listener(); + break; + } + } + }); + }); + observer.observe(container, { + childList: true + }); + return observer; +} +var drpListeningCharts = new Map(); +var oldDevicePixelRatio = 0; +function onWindowResize() { + var dpr = window.devicePixelRatio; + if (dpr === oldDevicePixelRatio) { + return; + } + oldDevicePixelRatio = dpr; + drpListeningCharts.forEach(function (resize, chart) { + if (chart.currentDevicePixelRatio !== dpr) { + resize(); + } + }); +} +function listenDevicePixelRatioChanges(chart, resize) { + if (!drpListeningCharts.size) { + window.addEventListener('resize', onWindowResize); + } + drpListeningCharts.set(chart, resize); +} +function unlistenDevicePixelRatioChanges(chart) { + drpListeningCharts["delete"](chart); + if (!drpListeningCharts.size) { + window.removeEventListener('resize', onWindowResize); + } +} +function createResizeObserver(chart, type, listener) { + var canvas = chart.canvas; + var container = canvas && _getParentNode(canvas); + if (!container) { + return; + } + var resize = throttled(function (width, height) { + var w = container.clientWidth; + listener(width, height); + if (w < container.clientWidth) { + listener(); + } + }, window); + var observer = new index(function (entries) { + var entry = entries[0]; + var width = entry.contentRect.width; + var height = entry.contentRect.height; + if (width === 0 && height === 0) { + return; + } + resize(width, height); + }); + observer.observe(container); + listenDevicePixelRatioChanges(chart, resize); + return observer; +} +function releaseObserver(chart, type, observer) { + if (observer) { + observer.disconnect(); + } + if (type === 'resize') { + unlistenDevicePixelRatioChanges(chart); + } +} +function createProxyAndListen(chart, type, listener) { + var canvas = chart.canvas; + var proxy = throttled(function (event) { + if (chart.ctx !== null) { + listener(fromNativeEvent(event, chart)); + } + }, chart, function (args) { + var event = args[0]; + return [event, event.offsetX, event.offsetY]; + }); + addListener(canvas, type, proxy); + return proxy; +} +var DomPlatform = function (_BasePlatform) { + _inheritsLoose(DomPlatform, _BasePlatform); + function DomPlatform() { + return _BasePlatform.apply(this, arguments) || this; + } + var _proto = DomPlatform.prototype; + _proto.acquireContext = function acquireContext(canvas, config) { + var context = canvas && canvas.getContext && canvas.getContext('2d'); + if (context && context.canvas === canvas) { + initCanvas(canvas, config); + return context; + } + return null; + } + ; + _proto.releaseContext = function releaseContext(context) { + var canvas = context.canvas; + if (!canvas[EXPANDO_KEY]) { + return false; + } + var initial = canvas[EXPANDO_KEY].initial; + ['height', 'width'].forEach(function (prop) { + var value = initial[prop]; + if (isNullOrUndef(value)) { + canvas.removeAttribute(prop); + } else { + canvas.setAttribute(prop, value); + } + }); + var style = initial.style || {}; + Object.keys(style).forEach(function (key) { + canvas.style[key] = style[key]; + }); + canvas.width = canvas.width; + delete canvas[EXPANDO_KEY]; + return true; + } + ; + _proto.addEventListener = function addEventListener(chart, type, listener) { + this.removeEventListener(chart, type); + var proxies = chart.$proxies || (chart.$proxies = {}); + var handlers = { + attach: createAttachObserver, + detach: createDetachObserver, + resize: createResizeObserver + }; + var handler = handlers[type] || createProxyAndListen; + proxies[type] = handler(chart, type, listener); + } + ; + _proto.removeEventListener = function removeEventListener(chart, type) { + var proxies = chart.$proxies || (chart.$proxies = {}); + var proxy = proxies[type]; + if (!proxy) { + return; + } + var handlers = { + attach: releaseObserver, + detach: releaseObserver, + resize: releaseObserver + }; + var handler = handlers[type] || removeListener; + handler(chart, type, proxy); + proxies[type] = undefined; + }; + _proto.getDevicePixelRatio = function getDevicePixelRatio() { + return window.devicePixelRatio; + } + ; + _proto.getMaximumSize = function getMaximumSize$1(canvas, width, height, aspectRatio) { + return getMaximumSize(canvas, width, height, aspectRatio); + } + ; + _proto.isAttached = function isAttached(canvas) { + var container = _getParentNode(canvas); + return !!(container && _getParentNode(container)); + }; + return DomPlatform; +}(BasePlatform); + +var platforms = /*#__PURE__*/Object.freeze({ +__proto__: null, +BasePlatform: BasePlatform, +BasicPlatform: BasicPlatform, +DomPlatform: DomPlatform +}); + +function finallyConstructor(callback) { + var constructor = this.constructor; + return this.then(function (value) { + return constructor.resolve(callback()).then(function () { + return value; + }); + }, function (reason) { + return constructor.resolve(callback()).then(function () { + return constructor.reject(reason); + }); + }); +} + +var setTimeoutFunc = setTimeout; +function isArray$1(x) { + return Boolean(x && typeof x.length !== 'undefined'); +} +function noop$1() {} +function bind(fn, thisArg) { + return function () { + fn.apply(thisArg, arguments); + }; +} +function Promise(fn) { + if (!(this instanceof Promise)) throw new TypeError('Promises must be constructed via new'); + if (typeof fn !== 'function') throw new TypeError('not a function'); + this._state = 0; + this._handled = false; + this._value = undefined; + this._deferreds = []; + doResolve(fn, this); +} +function handle(self, deferred) { + while (self._state === 3) { + self = self._value; + } + if (self._state === 0) { + self._deferreds.push(deferred); + return; + } + self._handled = true; + Promise._immediateFn(function () { + var cb = self._state === 1 ? deferred.onFulfilled : deferred.onRejected; + if (cb === null) { + (self._state === 1 ? resolve$1 : reject)(deferred.promise, self._value); + return; + } + var ret; + try { + ret = cb(self._value); + } catch (e) { + reject(deferred.promise, e); + return; + } + resolve$1(deferred.promise, ret); + }); +} +function resolve$1(self, newValue) { + try { + if (newValue === self) throw new TypeError('A promise cannot be resolved with itself.'); + if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) { + var then = newValue.then; + if (newValue instanceof Promise) { + self._state = 3; + self._value = newValue; + finale(self); + return; + } else if (typeof then === 'function') { + doResolve(bind(then, newValue), self); + return; + } + } + self._state = 1; + self._value = newValue; + finale(self); + } catch (e) { + reject(self, e); + } +} +function reject(self, newValue) { + self._state = 2; + self._value = newValue; + finale(self); +} +function finale(self) { + if (self._state === 2 && self._deferreds.length === 0) { + Promise._immediateFn(function () { + if (!self._handled) { + Promise._unhandledRejectionFn(self._value); + } + }); + } + for (var i = 0, len = self._deferreds.length; i < len; i++) { + handle(self, self._deferreds[i]); + } + self._deferreds = null; +} +function Handler(onFulfilled, onRejected, promise) { + this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null; + this.onRejected = typeof onRejected === 'function' ? onRejected : null; + this.promise = promise; +} +function doResolve(fn, self) { + var done = false; + try { + fn(function (value) { + if (done) return; + done = true; + resolve$1(self, value); + }, function (reason) { + if (done) return; + done = true; + reject(self, reason); + }); + } catch (ex) { + if (done) return; + done = true; + reject(self, ex); + } +} +Promise.prototype['catch'] = function (onRejected) { + return this.then(null, onRejected); +}; +Promise.prototype.then = function (onFulfilled, onRejected) { + var prom = new this.constructor(noop$1); + handle(this, new Handler(onFulfilled, onRejected, prom)); + return prom; +}; +Promise.prototype['finally'] = finallyConstructor; +Promise.all = function (arr) { + return new Promise(function (resolve, reject) { + if (!isArray$1(arr)) { + return reject(new TypeError('Promise.all accepts an array')); + } + var args = Array.prototype.slice.call(arr); + if (args.length === 0) return resolve([]); + var remaining = args.length; + function res(i, val) { + try { + if (val && (typeof val === 'object' || typeof val === 'function')) { + var then = val.then; + if (typeof then === 'function') { + then.call(val, function (val) { + res(i, val); + }, reject); + return; + } + } + args[i] = val; + if (--remaining === 0) { + resolve(args); + } + } catch (ex) { + reject(ex); + } + } + for (var i = 0; i < args.length; i++) { + res(i, args[i]); + } + }); +}; +Promise.resolve = function (value) { + if (value && typeof value === 'object' && value.constructor === Promise) { + return value; + } + return new Promise(function (resolve) { + resolve(value); + }); +}; +Promise.reject = function (value) { + return new Promise(function (resolve, reject) { + reject(value); + }); +}; +Promise.race = function (arr) { + return new Promise(function (resolve, reject) { + if (!isArray$1(arr)) { + return reject(new TypeError('Promise.race accepts an array')); + } + for (var i = 0, len = arr.length; i < len; i++) { + Promise.resolve(arr[i]).then(resolve, reject); + } + }); +}; +Promise._immediateFn = +typeof setImmediate === 'function' && function (fn) { + setImmediate(fn); +} || function (fn) { + setTimeoutFunc(fn, 0); +}; +Promise._unhandledRejectionFn = function _unhandledRejectionFn(err) { + if (typeof console !== 'undefined' && console) { + console.warn('Possible Unhandled Promise Rejection:', err); + } +}; + +var effects = { + linear: function linear(t) { + return t; + }, + easeInQuad: function easeInQuad(t) { + return t * t; + }, + easeOutQuad: function easeOutQuad(t) { + return -t * (t - 2); + }, + easeInOutQuad: function easeInOutQuad(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t; + } + return -0.5 * (--t * (t - 2) - 1); + }, + easeInCubic: function easeInCubic(t) { + return t * t * t; + }, + easeOutCubic: function easeOutCubic(t) { + return (t -= 1) * t * t + 1; + }, + easeInOutCubic: function easeInOutCubic(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t * t; + } + return 0.5 * ((t -= 2) * t * t + 2); + }, + easeInQuart: function easeInQuart(t) { + return t * t * t * t; + }, + easeOutQuart: function easeOutQuart(t) { + return -((t -= 1) * t * t * t - 1); + }, + easeInOutQuart: function easeInOutQuart(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t * t * t; + } + return -0.5 * ((t -= 2) * t * t * t - 2); + }, + easeInQuint: function easeInQuint(t) { + return t * t * t * t * t; + }, + easeOutQuint: function easeOutQuint(t) { + return (t -= 1) * t * t * t * t + 1; + }, + easeInOutQuint: function easeInOutQuint(t) { + if ((t /= 0.5) < 1) { + return 0.5 * t * t * t * t * t; + } + return 0.5 * ((t -= 2) * t * t * t * t + 2); + }, + easeInSine: function easeInSine(t) { + return -Math.cos(t * (Math.PI / 2)) + 1; + }, + easeOutSine: function easeOutSine(t) { + return Math.sin(t * (Math.PI / 2)); + }, + easeInOutSine: function easeInOutSine(t) { + return -0.5 * (Math.cos(Math.PI * t) - 1); + }, + easeInExpo: function easeInExpo(t) { + return t === 0 ? 0 : Math.pow(2, 10 * (t - 1)); + }, + easeOutExpo: function easeOutExpo(t) { + return t === 1 ? 1 : -Math.pow(2, -10 * t) + 1; + }, + easeInOutExpo: function easeInOutExpo(t) { + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if ((t /= 0.5) < 1) { + return 0.5 * Math.pow(2, 10 * (t - 1)); + } + return 0.5 * (-Math.pow(2, -10 * --t) + 2); + }, + easeInCirc: function easeInCirc(t) { + if (t >= 1) { + return t; + } + return -(Math.sqrt(1 - t * t) - 1); + }, + easeOutCirc: function easeOutCirc(t) { + return Math.sqrt(1 - (t -= 1) * t); + }, + easeInOutCirc: function easeInOutCirc(t) { + if ((t /= 0.5) < 1) { + return -0.5 * (Math.sqrt(1 - t * t) - 1); + } + return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1); + }, + easeInElastic: function easeInElastic(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if (!p) { + p = 0.3; + } + { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); + }, + easeOutElastic: function easeOutElastic(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if (t === 1) { + return 1; + } + if (!p) { + p = 0.3; + } + { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + return a * Math.pow(2, -10 * t) * Math.sin((t - s) * (2 * Math.PI) / p) + 1; + }, + easeInOutElastic: function easeInOutElastic(t) { + var s = 1.70158; + var p = 0; + var a = 1; + if (t === 0) { + return 0; + } + if ((t /= 0.5) === 2) { + return 1; + } + if (!p) { + p = 0.45; + } + { + s = p / (2 * Math.PI) * Math.asin(1 / a); + } + if (t < 1) { + return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p)); + } + return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t - s) * (2 * Math.PI) / p) * 0.5 + 1; + }, + easeInBack: function easeInBack(t) { + var s = 1.70158; + return t * t * ((s + 1) * t - s); + }, + easeOutBack: function easeOutBack(t) { + var s = 1.70158; + return (t -= 1) * t * ((s + 1) * t + s) + 1; + }, + easeInOutBack: function easeInOutBack(t) { + var s = 1.70158; + if ((t /= 0.5) < 1) { + return 0.5 * (t * t * (((s *= 1.525) + 1) * t - s)); + } + return 0.5 * ((t -= 2) * t * (((s *= 1.525) + 1) * t + s) + 2); + }, + easeInBounce: function easeInBounce(t) { + return 1 - effects.easeOutBounce(1 - t); + }, + easeOutBounce: function easeOutBounce(t) { + if (t < 1 / 2.75) { + return 7.5625 * t * t; + } + if (t < 2 / 2.75) { + return 7.5625 * (t -= 1.5 / 2.75) * t + 0.75; + } + if (t < 2.5 / 2.75) { + return 7.5625 * (t -= 2.25 / 2.75) * t + 0.9375; + } + return 7.5625 * (t -= 2.625 / 2.75) * t + 0.984375; + }, + easeInOutBounce: function easeInOutBounce(t) { + if (t < 0.5) { + return effects.easeInBounce(t * 2) * 0.5; + } + return effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5; + } +}; + +/*! + * @kurkle/color v0.1.9 + * https://github.com/kurkle/color#readme + * (c) 2020 Jukka Kurkela + * Released under the MIT License + */ +var map = { + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9, + A: 10, + B: 11, + C: 12, + D: 13, + E: 14, + F: 15, + a: 10, + b: 11, + c: 12, + d: 13, + e: 14, + f: 15 +}; +var hex = '0123456789ABCDEF'; +var h1 = function h1(b) { + return hex[b & 0xF]; +}; +var h2 = function h2(b) { + return hex[(b & 0xF0) >> 4] + hex[b & 0xF]; +}; +var eq = function eq(b) { + return (b & 0xF0) >> 4 === (b & 0xF); +}; +function isShort(v) { + return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a); +} +function hexParse(str) { + var len = str.length; + var ret; + if (str[0] === '#') { + if (len === 4 || len === 5) { + ret = { + r: 255 & map[str[1]] * 17, + g: 255 & map[str[2]] * 17, + b: 255 & map[str[3]] * 17, + a: len === 5 ? map[str[4]] * 17 : 255 + }; + } else if (len === 7 || len === 9) { + ret = { + r: map[str[1]] << 4 | map[str[2]], + g: map[str[3]] << 4 | map[str[4]], + b: map[str[5]] << 4 | map[str[6]], + a: len === 9 ? map[str[7]] << 4 | map[str[8]] : 255 + }; + } + } + return ret; +} +function _hexString(v) { + var f = isShort(v) ? h1 : h2; + return v ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '') : v; +} +function round(v) { + return v + 0.5 | 0; +} +var lim = function lim(v, l, h) { + return Math.max(Math.min(v, h), l); +}; +function p2b(v) { + return lim(round(v * 2.55), 0, 255); +} +function n2b(v) { + return lim(round(v * 255), 0, 255); +} +function b2n(v) { + return lim(round(v / 2.55) / 100, 0, 1); +} +function n2p(v) { + return lim(round(v * 100), 0, 100); +} +var RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/; +function rgbParse(str) { + var m = RGB_RE.exec(str); + var a = 255; + var r, g, b; + if (!m) { + return; + } + if (m[7] !== r) { + var v = +m[7]; + a = 255 & (m[8] ? p2b(v) : v * 255); + } + r = +m[1]; + g = +m[3]; + b = +m[5]; + r = 255 & (m[2] ? p2b(r) : r); + g = 255 & (m[4] ? p2b(g) : g); + b = 255 & (m[6] ? p2b(b) : b); + return { + r: r, + g: g, + b: b, + a: a + }; +} +function _rgbString(v) { + return v && (v.a < 255 ? "rgba(" + v.r + ", " + v.g + ", " + v.b + ", " + b2n(v.a) + ")" : "rgb(" + v.r + ", " + v.g + ", " + v.b + ")"); +} +var HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/; +function hsl2rgbn(h, s, l) { + var a = s * Math.min(l, 1 - l); + var f = function f(n, k) { + if (k === void 0) { + k = (n + h / 30) % 12; + } + return l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1); + }; + return [f(0), f(8), f(4)]; +} +function hsv2rgbn(h, s, v) { + var f = function f(n, k) { + if (k === void 0) { + k = (n + h / 60) % 6; + } + return v - v * s * Math.max(Math.min(k, 4 - k, 1), 0); + }; + return [f(5), f(3), f(1)]; +} +function hwb2rgbn(h, w, b) { + var rgb = hsl2rgbn(h, 1, 0.5); + var i; + if (w + b > 1) { + i = 1 / (w + b); + w *= i; + b *= i; + } + for (i = 0; i < 3; i++) { + rgb[i] *= 1 - w - b; + rgb[i] += w; + } + return rgb; +} +function rgb2hsl(v) { + var range = 255; + var r = v.r / range; + var g = v.g / range; + var b = v.b / range; + var max = Math.max(r, g, b); + var min = Math.min(r, g, b); + var l = (max + min) / 2; + var h, s, d; + if (max !== min) { + d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4; + h = h * 60 + 0.5; + } + return [h | 0, s || 0, l]; +} +function calln(f, a, b, c) { + return (Array.isArray(a) ? f(a[0], a[1], a[2]) : f(a, b, c)).map(n2b); +} +function hsl2rgb(h, s, l) { + return calln(hsl2rgbn, h, s, l); +} +function hwb2rgb(h, w, b) { + return calln(hwb2rgbn, h, w, b); +} +function hsv2rgb(h, s, v) { + return calln(hsv2rgbn, h, s, v); +} +function hue(h) { + return (h % 360 + 360) % 360; +} +function hueParse(str) { + var m = HUE_RE.exec(str); + var a = 255; + var v; + if (!m) { + return; + } + if (m[5] !== v) { + a = m[6] ? p2b(+m[5]) : n2b(+m[5]); + } + var h = hue(+m[2]); + var p1 = +m[3] / 100; + var p2 = +m[4] / 100; + if (m[1] === 'hwb') { + v = hwb2rgb(h, p1, p2); + } else if (m[1] === 'hsv') { + v = hsv2rgb(h, p1, p2); + } else { + v = hsl2rgb(h, p1, p2); + } + return { + r: v[0], + g: v[1], + b: v[2], + a: a + }; +} +function _rotate(v, deg) { + var h = rgb2hsl(v); + h[0] = hue(h[0] + deg); + h = hsl2rgb(h); + v.r = h[0]; + v.g = h[1]; + v.b = h[2]; +} +function _hslString(v) { + if (!v) { + return; + } + var a = rgb2hsl(v); + var h = a[0]; + var s = n2p(a[1]); + var l = n2p(a[2]); + return v.a < 255 ? "hsla(" + h + ", " + s + "%, " + l + "%, " + b2n(v.a) + ")" : "hsl(" + h + ", " + s + "%, " + l + "%)"; +} +var map$1 = { + x: 'dark', + Z: 'light', + Y: 're', + X: 'blu', + W: 'gr', + V: 'medium', + U: 'slate', + A: 'ee', + T: 'ol', + S: 'or', + B: 'ra', + C: 'lateg', + D: 'ights', + R: 'in', + Q: 'turquois', + E: 'hi', + P: 'ro', + O: 'al', + N: 'le', + M: 'de', + L: 'yello', + F: 'en', + K: 'ch', + G: 'arks', + H: 'ea', + I: 'ightg', + J: 'wh' +}; +var names = { + OiceXe: 'f0f8ff', + antiquewEte: 'faebd7', + aqua: 'ffff', + aquamarRe: '7fffd4', + azuY: 'f0ffff', + beige: 'f5f5dc', + bisque: 'ffe4c4', + black: '0', + blanKedOmond: 'ffebcd', + Xe: 'ff', + XeviTet: '8a2be2', + bPwn: 'a52a2a', + burlywood: 'deb887', + caMtXe: '5f9ea0', + KartYuse: '7fff00', + KocTate: 'd2691e', + cSO: 'ff7f50', + cSnflowerXe: '6495ed', + cSnsilk: 'fff8dc', + crimson: 'dc143c', + cyan: 'ffff', + xXe: '8b', + xcyan: '8b8b', + xgTMnPd: 'b8860b', + xWay: 'a9a9a9', + xgYF: '6400', + xgYy: 'a9a9a9', + xkhaki: 'bdb76b', + xmagFta: '8b008b', + xTivegYF: '556b2f', + xSange: 'ff8c00', + xScEd: '9932cc', + xYd: '8b0000', + xsOmon: 'e9967a', + xsHgYF: '8fbc8f', + xUXe: '483d8b', + xUWay: '2f4f4f', + xUgYy: '2f4f4f', + xQe: 'ced1', + xviTet: '9400d3', + dAppRk: 'ff1493', + dApskyXe: 'bfff', + dimWay: '696969', + dimgYy: '696969', + dodgerXe: '1e90ff', + fiYbrick: 'b22222', + flSOwEte: 'fffaf0', + foYstWAn: '228b22', + fuKsia: 'ff00ff', + gaRsbSo: 'dcdcdc', + ghostwEte: 'f8f8ff', + gTd: 'ffd700', + gTMnPd: 'daa520', + Way: '808080', + gYF: '8000', + gYFLw: 'adff2f', + gYy: '808080', + honeyMw: 'f0fff0', + hotpRk: 'ff69b4', + RdianYd: 'cd5c5c', + Rdigo: '4b0082', + ivSy: 'fffff0', + khaki: 'f0e68c', + lavFMr: 'e6e6fa', + lavFMrXsh: 'fff0f5', + lawngYF: '7cfc00', + NmoncEffon: 'fffacd', + ZXe: 'add8e6', + ZcSO: 'f08080', + Zcyan: 'e0ffff', + ZgTMnPdLw: 'fafad2', + ZWay: 'd3d3d3', + ZgYF: '90ee90', + ZgYy: 'd3d3d3', + ZpRk: 'ffb6c1', + ZsOmon: 'ffa07a', + ZsHgYF: '20b2aa', + ZskyXe: '87cefa', + ZUWay: '778899', + ZUgYy: '778899', + ZstAlXe: 'b0c4de', + ZLw: 'ffffe0', + lime: 'ff00', + limegYF: '32cd32', + lRF: 'faf0e6', + magFta: 'ff00ff', + maPon: '800000', + VaquamarRe: '66cdaa', + VXe: 'cd', + VScEd: 'ba55d3', + VpurpN: '9370db', + VsHgYF: '3cb371', + VUXe: '7b68ee', + VsprRggYF: 'fa9a', + VQe: '48d1cc', + VviTetYd: 'c71585', + midnightXe: '191970', + mRtcYam: 'f5fffa', + mistyPse: 'ffe4e1', + moccasR: 'ffe4b5', + navajowEte: 'ffdead', + navy: '80', + Tdlace: 'fdf5e6', + Tive: '808000', + TivedBb: '6b8e23', + Sange: 'ffa500', + SangeYd: 'ff4500', + ScEd: 'da70d6', + pOegTMnPd: 'eee8aa', + pOegYF: '98fb98', + pOeQe: 'afeeee', + pOeviTetYd: 'db7093', + papayawEp: 'ffefd5', + pHKpuff: 'ffdab9', + peru: 'cd853f', + pRk: 'ffc0cb', + plum: 'dda0dd', + powMrXe: 'b0e0e6', + purpN: '800080', + YbeccapurpN: '663399', + Yd: 'ff0000', + Psybrown: 'bc8f8f', + PyOXe: '4169e1', + saddNbPwn: '8b4513', + sOmon: 'fa8072', + sandybPwn: 'f4a460', + sHgYF: '2e8b57', + sHshell: 'fff5ee', + siFna: 'a0522d', + silver: 'c0c0c0', + skyXe: '87ceeb', + UXe: '6a5acd', + UWay: '708090', + UgYy: '708090', + snow: 'fffafa', + sprRggYF: 'ff7f', + stAlXe: '4682b4', + tan: 'd2b48c', + teO: '8080', + tEstN: 'd8bfd8', + tomato: 'ff6347', + Qe: '40e0d0', + viTet: 'ee82ee', + JHt: 'f5deb3', + wEte: 'ffffff', + wEtesmoke: 'f5f5f5', + Lw: 'ffff00', + LwgYF: '9acd32' +}; +function unpack() { + var unpacked = {}; + var keys = Object.keys(names); + var tkeys = Object.keys(map$1); + var i, j, k, ok, nk; + for (i = 0; i < keys.length; i++) { + ok = nk = keys[i]; + for (j = 0; j < tkeys.length; j++) { + k = tkeys[j]; + nk = nk.replace(k, map$1[k]); + } + k = parseInt(names[ok], 16); + unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF]; + } + return unpacked; +} +var names$1; +function nameParse(str) { + if (!names$1) { + names$1 = unpack(); + names$1.transparent = [0, 0, 0, 0]; + } + var a = names$1[str.toLowerCase()]; + return a && { + r: a[0], + g: a[1], + b: a[2], + a: a.length === 4 ? a[3] : 255 + }; +} +function modHSL(v, i, ratio) { + if (v) { + var tmp = rgb2hsl(v); + tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1)); + tmp = hsl2rgb(tmp); + v.r = tmp[0]; + v.g = tmp[1]; + v.b = tmp[2]; + } +} +function clone$1(v, proto) { + return v ? _extends(proto || {}, v) : v; +} +function fromObject(input) { + var v = { + r: 0, + g: 0, + b: 0, + a: 255 + }; + if (Array.isArray(input)) { + if (input.length >= 3) { + v = { + r: input[0], + g: input[1], + b: input[2], + a: 255 + }; + if (input.length > 3) { + v.a = n2b(input[3]); + } + } + } else { + v = clone$1(input, { + r: 0, + g: 0, + b: 0, + a: 1 + }); + v.a = n2b(v.a); + } + return v; +} +function functionParse(str) { + if (str.charAt(0) === 'r') { + return rgbParse(str); + } + return hueParse(str); +} +var Color = function () { + function Color(input) { + if (input instanceof Color) { + return input; + } + var type = typeof input; + var v; + if (type === 'object') { + v = fromObject(input); + } else if (type === 'string') { + v = hexParse(input) || nameParse(input) || functionParse(input); + } + this._rgb = v; + this._valid = !!v; + } + var _proto = Color.prototype; + _proto.rgbString = function rgbString() { + return this._valid ? _rgbString(this._rgb) : this._rgb; + }; + _proto.hexString = function hexString() { + return this._valid ? _hexString(this._rgb) : this._rgb; + }; + _proto.hslString = function hslString() { + return this._valid ? _hslString(this._rgb) : this._rgb; + }; + _proto.mix = function mix(color, weight) { + var me = this; + if (color) { + var c1 = me.rgb; + var c2 = color.rgb; + var w2; + var p = weight === w2 ? 0.5 : weight; + var w = 2 * p - 1; + var a = c1.a - c2.a; + var w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0; + w2 = 1 - w1; + c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5; + c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5; + c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5; + c1.a = p * c1.a + (1 - p) * c2.a; + me.rgb = c1; + } + return me; + }; + _proto.clone = function clone() { + return new Color(this.rgb); + }; + _proto.alpha = function alpha(a) { + this._rgb.a = n2b(a); + return this; + }; + _proto.clearer = function clearer(ratio) { + var rgb = this._rgb; + rgb.a *= 1 - ratio; + return this; + }; + _proto.greyscale = function greyscale() { + var rgb = this._rgb; + var val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11); + rgb.r = rgb.g = rgb.b = val; + return this; + }; + _proto.opaquer = function opaquer(ratio) { + var rgb = this._rgb; + rgb.a *= 1 + ratio; + return this; + }; + _proto.negate = function negate() { + var v = this._rgb; + v.r = 255 - v.r; + v.g = 255 - v.g; + v.b = 255 - v.b; + return this; + }; + _proto.lighten = function lighten(ratio) { + modHSL(this._rgb, 2, ratio); + return this; + }; + _proto.darken = function darken(ratio) { + modHSL(this._rgb, 2, -ratio); + return this; + }; + _proto.saturate = function saturate(ratio) { + modHSL(this._rgb, 1, ratio); + return this; + }; + _proto.desaturate = function desaturate(ratio) { + modHSL(this._rgb, 1, -ratio); + return this; + }; + _proto.rotate = function rotate(deg) { + _rotate(this._rgb, deg); + return this; + }; + _createClass(Color, [{ + key: "valid", + get: function get() { + return this._valid; + } + }, { + key: "rgb", + get: function get() { + var v = clone$1(this._rgb); + if (v) { + v.a = b2n(v.a); + } + return v; + }, + set: function set(obj) { + this._rgb = fromObject(obj); + } + }]); + return Color; +}(); +function index_esm(input) { + return new Color(input); +} + +var isPatternOrGradient = function isPatternOrGradient(value) { + return value instanceof CanvasGradient || value instanceof CanvasPattern; +}; +function color(value) { + return isPatternOrGradient(value) ? value : index_esm(value); +} +function getHoverColor(value) { + return isPatternOrGradient(value) ? value : index_esm(value).saturate(0.5).darken(0.1).hexString(); +} + +var transparent = 'transparent'; +var interpolators = { + "boolean": function boolean(from, to, factor) { + return factor > 0.5 ? to : from; + }, + color: function color$1(from, to, factor) { + var c0 = color(from || transparent); + var c1 = c0.valid && color(to || transparent); + return c1 && c1.valid ? c1.mix(c0, factor).hexString() : to; + }, + number: function number(from, to, factor) { + return from + (to - from) * factor; + } +}; +var Animation = function () { + function Animation(cfg, target, prop, to) { + var currentValue = target[prop]; + to = resolve([cfg.to, to, currentValue, cfg.from]); + var from = resolve([cfg.from, currentValue, to]); + this._active = true; + this._fn = cfg.fn || interpolators[cfg.type || typeof from]; + this._easing = effects[cfg.easing || 'linear']; + this._start = Math.floor(Date.now() + (cfg.delay || 0)); + this._duration = Math.floor(cfg.duration); + this._loop = !!cfg.loop; + this._target = target; + this._prop = prop; + this._from = from; + this._to = to; + this._promises = undefined; + } + var _proto = Animation.prototype; + _proto.active = function active() { + return this._active; + }; + _proto.update = function update(cfg, to, date) { + var me = this; + if (me._active) { + var currentValue = me._target[me._prop]; + var elapsed = date - me._start; + var remain = me._duration - elapsed; + me._start = date; + me._duration = Math.floor(Math.max(remain, cfg.duration)); + me._loop = !!cfg.loop; + me._to = resolve([cfg.to, to, currentValue, cfg.from]); + me._from = resolve([cfg.from, currentValue, to]); + } + }; + _proto.cancel = function cancel() { + var me = this; + if (me._active) { + me.tick(Date.now()); + me._active = false; + me._notify(false); + } + }; + _proto.tick = function tick(date) { + var me = this; + var elapsed = date - me._start; + var duration = me._duration; + var prop = me._prop; + var from = me._from; + var loop = me._loop; + var to = me._to; + var factor; + me._active = from !== to && (loop || elapsed < duration); + if (!me._active) { + me._target[prop] = to; + me._notify(true); + return; + } + if (elapsed < 0) { + me._target[prop] = from; + return; + } + factor = elapsed / duration % 2; + factor = loop && factor > 1 ? 2 - factor : factor; + factor = me._easing(Math.min(1, Math.max(0, factor))); + me._target[prop] = me._fn(from, to, factor); + }; + _proto.wait = function wait() { + var promises = this._promises || (this._promises = []); + return new Promise(function (res, rej) { + promises.push({ + res: res, + rej: rej + }); + }); + }; + _proto._notify = function _notify(resolved) { + var method = resolved ? 'res' : 'rej'; + var promises = this._promises || []; + for (var i = 0; i < promises.length; i++) { + promises[i][method](); + } + }; + return Animation; +}(); + +var numbers = ['x', 'y', 'borderWidth', 'radius', 'tension']; +var colors = ['borderColor', 'backgroundColor']; +defaults.set('animation', { + duration: 1000, + easing: 'easeOutQuart', + onProgress: noop, + onComplete: noop, + colors: { + type: 'color', + properties: colors + }, + numbers: { + type: 'number', + properties: numbers + }, + active: { + duration: 400 + }, + resize: { + duration: 0 + }, + show: { + colors: { + type: 'color', + properties: colors, + from: 'transparent' + }, + visible: { + type: 'boolean', + duration: 0 + } + }, + hide: { + colors: { + type: 'color', + properties: colors, + to: 'transparent' + }, + visible: { + type: 'boolean', + easing: 'easeInExpo' + } + } +}); +function copyOptions(target, values) { + var oldOpts = target.options; + var newOpts = values.options; + if (!oldOpts || !newOpts) { + return; + } + if (oldOpts.$shared && !newOpts.$shared) { + target.options = _extends({}, oldOpts, newOpts, { + $shared: false + }); + } else { + _extends(oldOpts, newOpts); + } + delete values.options; +} +function extensibleConfig(animations) { + var result = {}; + Object.keys(animations).forEach(function (key) { + var value = animations[key]; + if (!isObject(value)) { + result[key] = value; + } + }); + return result; +} +var Animations = function () { + function Animations(chart, animations) { + this._chart = chart; + this._properties = new Map(); + this.configure(animations); + } + var _proto = Animations.prototype; + _proto.configure = function configure(animations) { + if (!isObject(animations)) { + return; + } + var animatedProps = this._properties; + var animDefaults = extensibleConfig(animations); + Object.keys(animations).forEach(function (key) { + var cfg = animations[key]; + if (!isObject(cfg)) { + return; + } + (cfg.properties || [key]).forEach(function (prop) { + if (!animatedProps.has(prop)) { + animatedProps.set(prop, _extends({}, animDefaults, cfg)); + } else if (prop === key) { + var _animatedProps$get = animatedProps.get(prop), + properties = _animatedProps$get.properties, + inherited = _objectWithoutPropertiesLoose(_animatedProps$get, ["properties"]); + animatedProps.set(prop, _extends({}, inherited, cfg)); + } + }); + }); + } + ; + _proto._animateOptions = function _animateOptions(target, values) { + var newOptions = values.options; + var options = resolveTargetOptions(target, newOptions); + if (!options) { + return []; + } + var animations = this._createAnimations(options, newOptions); + if (newOptions.$shared && !options.$shared) { + awaitAll(target.options.$animations, newOptions).then(function () { + target.options = newOptions; + }); + } + return animations; + } + ; + _proto._createAnimations = function _createAnimations(target, values) { + var animatedProps = this._properties; + var animations = []; + var running = target.$animations || (target.$animations = {}); + var props = Object.keys(values); + var date = Date.now(); + var i; + for (i = props.length - 1; i >= 0; --i) { + var prop = props[i]; + if (prop.charAt(0) === '$') { + continue; + } + if (prop === 'options') { + animations.push.apply(animations, this._animateOptions(target, values)); + continue; + } + var value = values[prop]; + var animation = running[prop]; + var cfg = animatedProps.get(prop); + if (animation) { + if (cfg && animation.active()) { + animation.update(cfg, value, date); + continue; + } else { + animation.cancel(); + } + } + if (!cfg || !cfg.duration) { + target[prop] = value; + continue; + } + running[prop] = animation = new Animation(cfg, target, prop, value); + animations.push(animation); + } + return animations; + } + ; + _proto.update = function update(target, values) { + if (this._properties.size === 0) { + copyOptions(target, values); + _extends(target, values); + return; + } + var animations = this._createAnimations(target, values); + if (animations.length) { + animator.add(this._chart, animations); + return true; + } + }; + return Animations; +}(); +function awaitAll(animations, properties) { + var running = []; + var keys = Object.keys(properties); + for (var i = 0; i < keys.length; i++) { + var anim = animations[keys[i]]; + if (anim && anim.active()) { + running.push(anim.wait()); + } + } + return Promise.all(running); +} +function resolveTargetOptions(target, newOptions) { + if (!newOptions) { + return; + } + var options = target.options; + if (!options) { + target.options = newOptions; + return; + } + if (options.$shared && !newOptions.$shared) { + target.options = options = _extends({}, options, { + $shared: false, + $animations: {} + }); + } + return options; +} + +var PI$1 = Math.PI; +var TAU = 2 * PI$1; +var PITAU = TAU + PI$1; +function _factorize(value) { + var result = []; + var sqrt = Math.sqrt(value); + var i; + for (i = 1; i < sqrt; i++) { + if (value % i === 0) { + result.push(i); + result.push(value / i); + } + } + if (sqrt === (sqrt | 0)) { + result.push(sqrt); + } + result.sort(function (a, b) { + return a - b; + }).pop(); + return result; +} +var log10 = Math.log10 || function (x) { + var exponent = Math.log(x) * Math.LOG10E; + var powerOf10 = Math.round(exponent); + var isPowerOf10 = x === Math.pow(10, powerOf10); + return isPowerOf10 ? powerOf10 : exponent; +}; +function isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); +} +function almostEquals(x, y, epsilon) { + return Math.abs(x - y) < epsilon; +} +function almostWhole(x, epsilon) { + var rounded = Math.round(x); + return rounded - epsilon <= x && rounded + epsilon >= x; +} +function _setMinAndMaxByKey(array, target, property) { + var i, ilen, value; + for (i = 0, ilen = array.length; i < ilen; i++) { + value = array[i][property]; + if (!isNaN(value)) { + target.min = Math.min(target.min, value); + target.max = Math.max(target.max, value); + } + } +} +var sign = Math.sign ? function (x) { + return Math.sign(x); +} : function (x) { + x = +x; + if (x === 0 || isNaN(x)) { + return x; + } + return x > 0 ? 1 : -1; +}; +function toRadians(degrees) { + return degrees * (PI$1 / 180); +} +function toDegrees(radians) { + return radians * (180 / PI$1); +} +function _decimalPlaces(x) { + if (!isNumberFinite(x)) { + return; + } + var e = 1; + var p = 0; + while (Math.round(x * e) / e !== x) { + e *= 10; + p++; + } + return p; +} +function getAngleFromPoint(centrePoint, anglePoint) { + var distanceFromXCenter = anglePoint.x - centrePoint.x; + var distanceFromYCenter = anglePoint.y - centrePoint.y; + var radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter); + var angle = Math.atan2(distanceFromYCenter, distanceFromXCenter); + if (angle < -0.5 * PI$1) { + angle += TAU; + } + return { + angle: angle, + distance: radialDistanceFromCenter + }; +} +function distanceBetweenPoints(pt1, pt2) { + return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2)); +} +function _angleDiff(a, b) { + return (a - b + PITAU) % TAU - PI$1; +} +function _normalizeAngle(a) { + return (a % TAU + TAU) % TAU; +} +function _angleBetween(angle, start, end) { + var a = _normalizeAngle(angle); + var s = _normalizeAngle(start); + var e = _normalizeAngle(end); + var angleToStart = _normalizeAngle(s - a); + var angleToEnd = _normalizeAngle(e - a); + var startToAngle = _normalizeAngle(a - s); + var endToAngle = _normalizeAngle(a - e); + return a === s || a === e || angleToStart > angleToEnd && startToAngle < endToAngle; +} +function _limitValue(value, min, max) { + return Math.max(min, Math.min(max, value)); +} +function _int32Range(value) { + return _limitValue(value, -2147483648, 2147483647); +} + +function scaleClip(scale, allowedOverflow) { + var opts = scale && scale.options || {}; + var reverse = opts.reverse; + var min = opts.min === undefined ? allowedOverflow : 0; + var max = opts.max === undefined ? allowedOverflow : 0; + return { + start: reverse ? max : min, + end: reverse ? min : max + }; +} +function defaultClip(xScale, yScale, allowedOverflow) { + if (allowedOverflow === false) { + return false; + } + var x = scaleClip(xScale, allowedOverflow); + var y = scaleClip(yScale, allowedOverflow); + return { + top: y.end, + right: x.end, + bottom: y.start, + left: x.start + }; +} +function toClip(value) { + var t, r, b, l; + if (isObject(value)) { + t = value.top; + r = value.right; + b = value.bottom; + l = value.left; + } else { + t = r = b = l = value; + } + return { + top: t, + right: r, + bottom: b, + left: l + }; +} +function getSortedDatasetIndices(chart, filterVisible) { + var keys = []; + var metasets = chart._getSortedDatasetMetas(filterVisible); + var i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + keys.push(metasets[i].index); + } + return keys; +} +function _applyStack(stack, value, dsIndex, allOther) { + var keys = stack.keys; + var i, ilen, datasetIndex, otherValue; + for (i = 0, ilen = keys.length; i < ilen; ++i) { + datasetIndex = +keys[i]; + if (datasetIndex === dsIndex) { + if (allOther) { + continue; + } + break; + } + otherValue = stack.values[datasetIndex]; + if (!isNaN(otherValue) && (value === 0 || sign(value) === sign(otherValue))) { + value += otherValue; + } + } + return value; +} +function convertObjectDataToArray(data) { + var keys = Object.keys(data); + var adata = new Array(keys.length); + var i, ilen, key; + for (i = 0, ilen = keys.length; i < ilen; ++i) { + key = keys[i]; + adata[i] = { + x: key, + y: data[key] + }; + } + return adata; +} +function isStacked(scale, meta) { + var stacked = scale && scale.options.stacked; + return stacked || stacked === undefined && meta.stack !== undefined; +} +function getStackKey(indexScale, valueScale, meta) { + return indexScale.id + '.' + valueScale.id + '.' + meta.stack + '.' + meta.type; +} +function getUserBounds(scale) { + var _scale$getUserBounds = scale.getUserBounds(), + min = _scale$getUserBounds.min, + max = _scale$getUserBounds.max, + minDefined = _scale$getUserBounds.minDefined, + maxDefined = _scale$getUserBounds.maxDefined; + return { + min: minDefined ? min : Number.NEGATIVE_INFINITY, + max: maxDefined ? max : Number.POSITIVE_INFINITY + }; +} +function getOrCreateStack(stacks, stackKey, indexValue) { + var subStack = stacks[stackKey] || (stacks[stackKey] = {}); + return subStack[indexValue] || (subStack[indexValue] = {}); +} +function updateStacks(controller, parsed) { + var chart = controller.chart, + meta = controller._cachedMeta; + var stacks = chart._stacks || (chart._stacks = {}); + var iScale = meta.iScale, + vScale = meta.vScale, + datasetIndex = meta.index; + var iAxis = iScale.axis; + var vAxis = vScale.axis; + var key = getStackKey(iScale, vScale, meta); + var ilen = parsed.length; + var stack; + for (var i = 0; i < ilen; ++i) { + var item = parsed[i]; + var index = item[iAxis], + value = item[vAxis]; + var itemStacks = item._stacks || (item._stacks = {}); + stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index); + stack[datasetIndex] = value; + } +} +function getFirstScaleId(chart, axis) { + var scales = chart.scales; + return Object.keys(scales).filter(function (key) { + return scales[key].axis === axis; + }).shift(); +} +function optionKeys(optionNames) { + return isArray(optionNames) ? optionNames : Object.keys(optionNames); +} +function optionKey(key, active) { + return active ? 'hover' + _capitalize(key) : key; +} +function isDirectUpdateMode(mode) { + return mode === 'reset' || mode === 'none'; +} +var DatasetController = function () { + function DatasetController(chart, datasetIndex) { + this.chart = chart; + this._ctx = chart.ctx; + this.index = datasetIndex; + this._cachedAnimations = {}; + this._cachedDataOpts = {}; + this._cachedMeta = this.getMeta(); + this._type = this._cachedMeta.type; + this._config = undefined; + this._parsing = false; + this._data = undefined; + this._objectData = undefined; + this._sharedOptions = undefined; + this._drawStart = undefined; + this._drawCount = undefined; + this.enableOptionSharing = false; + this.initialize(); + } + var _proto = DatasetController.prototype; + _proto.initialize = function initialize() { + var me = this; + var meta = me._cachedMeta; + me.configure(); + me.linkScales(); + meta._stacked = isStacked(meta.vScale, meta); + me.addElements(); + }; + _proto.updateIndex = function updateIndex(datasetIndex) { + this.index = datasetIndex; + }; + _proto.linkScales = function linkScales() { + var me = this; + var chart = me.chart; + var meta = me._cachedMeta; + var dataset = me.getDataset(); + var chooseId = function chooseId(axis, x, y, r) { + return axis === 'x' ? x : axis === 'r' ? r : y; + }; + var xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x')); + var yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y')); + var rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r')); + var indexAxis = meta.indexAxis; + var iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid); + var vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid); + meta.xScale = me.getScaleForId(xid); + meta.yScale = me.getScaleForId(yid); + meta.rScale = me.getScaleForId(rid); + meta.iScale = me.getScaleForId(iid); + meta.vScale = me.getScaleForId(vid); + }; + _proto.getDataset = function getDataset() { + return this.chart.data.datasets[this.index]; + }; + _proto.getMeta = function getMeta() { + return this.chart.getDatasetMeta(this.index); + } + ; + _proto.getScaleForId = function getScaleForId(scaleID) { + return this.chart.scales[scaleID]; + } + ; + _proto._getOtherScale = function _getOtherScale(scale) { + var meta = this._cachedMeta; + return scale === meta.iScale ? meta.vScale : meta.iScale; + }; + _proto.reset = function reset() { + this._update('reset'); + } + ; + _proto._destroy = function _destroy() { + if (this._data) { + unlistenArrayEvents(this._data, this); + } + } + ; + _proto._dataCheck = function _dataCheck() { + var me = this; + var dataset = me.getDataset(); + var data = dataset.data || (dataset.data = []); + if (isObject(data)) { + me._data = convertObjectDataToArray(data); + } else if (me._data !== data) { + if (me._data) { + unlistenArrayEvents(me._data, me); + } + if (data && Object.isExtensible(data)) { + listenArrayEvents(data, me); + } + me._data = data; + } + }; + _proto.addElements = function addElements() { + var me = this; + var meta = me._cachedMeta; + me._dataCheck(); + var data = me._data; + var metaData = meta.data = new Array(data.length); + for (var i = 0, ilen = data.length; i < ilen; ++i) { + metaData[i] = new me.dataElementType(); + } + if (me.datasetElementType) { + meta.dataset = new me.datasetElementType(); + } + }; + _proto.buildOrUpdateElements = function buildOrUpdateElements() { + var me = this; + var meta = me._cachedMeta; + var dataset = me.getDataset(); + var stackChanged = false; + me._dataCheck(); + meta._stacked = isStacked(meta.vScale, meta); + if (meta.stack !== dataset.stack) { + stackChanged = true; + meta._parsed.forEach(function (parsed) { + delete parsed._stacks[meta.vScale.id][meta.index]; + }); + meta.stack = dataset.stack; + } + me._resyncElements(); + if (stackChanged) { + updateStacks(me, meta._parsed); + } + } + ; + _proto.configure = function configure() { + var me = this; + me._config = merge({}, [me.chart.options[me._type].datasets, me.getDataset()], { + merger: function merger(key, target, source) { + if (key !== 'data') { + _merger(key, target, source); + } + } + }); + me._parsing = resolve([me._config.parsing, me.chart.options.parsing, true]); + } + ; + _proto.parse = function parse(start, count) { + var me = this; + var meta = me._cachedMeta, + data = me._data; + var iScale = meta.iScale, + vScale = meta.vScale, + _stacked = meta._stacked; + var iAxis = iScale.axis; + var sorted = true; + var i, parsed, cur, prev; + if (start > 0) { + sorted = meta._sorted; + prev = meta._parsed[start - 1]; + } + if (me._parsing === false) { + meta._parsed = data; + meta._sorted = true; + } else { + if (isArray(data[start])) { + parsed = me.parseArrayData(meta, data, start, count); + } else if (isObject(data[start])) { + parsed = me.parseObjectData(meta, data, start, count); + } else { + parsed = me.parsePrimitiveData(meta, data, start, count); + } + var isNotInOrderComparedToPrev = function isNotInOrderComparedToPrev() { + return isNaN(cur[iAxis]) || prev && cur[iAxis] < prev[iAxis]; + }; + for (i = 0; i < count; ++i) { + meta._parsed[i + start] = cur = parsed[i]; + if (sorted) { + if (isNotInOrderComparedToPrev()) { + sorted = false; + } + prev = cur; + } + } + meta._sorted = sorted; + } + if (_stacked) { + updateStacks(me, parsed); + } + iScale.invalidateCaches(); + vScale.invalidateCaches(); + } + ; + _proto.parsePrimitiveData = function parsePrimitiveData(meta, data, start, count) { + var iScale = meta.iScale, + vScale = meta.vScale; + var iAxis = iScale.axis; + var vAxis = vScale.axis; + var labels = iScale.getLabels(); + var singleScale = iScale === vScale; + var parsed = new Array(count); + var i, ilen, index; + for (i = 0, ilen = count; i < ilen; ++i) { + var _parsed$i; + index = i + start; + parsed[i] = (_parsed$i = {}, _parsed$i[iAxis] = singleScale || iScale.parse(labels[index], index), _parsed$i[vAxis] = vScale.parse(data[index], index), _parsed$i); + } + return parsed; + } + ; + _proto.parseArrayData = function parseArrayData(meta, data, start, count) { + var xScale = meta.xScale, + yScale = meta.yScale; + var parsed = new Array(count); + var i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(item[0], index), + y: yScale.parse(item[1], index) + }; + } + return parsed; + } + ; + _proto.parseObjectData = function parseObjectData(meta, data, start, count) { + var xScale = meta.xScale, + yScale = meta.yScale; + var _this$_parsing = this._parsing, + _this$_parsing$xAxisK = _this$_parsing.xAxisKey, + xAxisKey = _this$_parsing$xAxisK === void 0 ? 'x' : _this$_parsing$xAxisK, + _this$_parsing$yAxisK = _this$_parsing.yAxisKey, + yAxisKey = _this$_parsing$yAxisK === void 0 ? 'y' : _this$_parsing$yAxisK; + var parsed = new Array(count); + var i, ilen, index, item; + for (i = 0, ilen = count; i < ilen; ++i) { + index = i + start; + item = data[index]; + parsed[i] = { + x: xScale.parse(resolveObjectKey(item, xAxisKey), index), + y: yScale.parse(resolveObjectKey(item, yAxisKey), index) + }; + } + return parsed; + } + ; + _proto.getParsed = function getParsed(index) { + return this._cachedMeta._parsed[index]; + } + ; + _proto.applyStack = function applyStack(scale, parsed) { + var chart = this.chart; + var meta = this._cachedMeta; + var value = parsed[scale.axis]; + var stack = { + keys: getSortedDatasetIndices(chart, true), + values: parsed._stacks[scale.axis] + }; + return _applyStack(stack, value, meta.index); + } + ; + _proto.updateRangeFromParsed = function updateRangeFromParsed(range, scale, parsed, stack) { + var value = parsed[scale.axis]; + var values = stack && parsed._stacks[scale.axis]; + if (stack && values) { + stack.values = values; + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + value = _applyStack(stack, value, this._cachedMeta.index, true); + } + range.min = Math.min(range.min, value); + range.max = Math.max(range.max, value); + } + ; + _proto.getMinMax = function getMinMax(scale, canStack) { + var me = this; + var meta = me._cachedMeta; + var _parsed = meta._parsed; + var sorted = meta._sorted && scale === meta.iScale; + var ilen = _parsed.length; + var otherScale = me._getOtherScale(scale); + var stack = canStack && meta._stacked && { + keys: getSortedDatasetIndices(me.chart, true), + values: null + }; + var range = { + min: Number.POSITIVE_INFINITY, + max: Number.NEGATIVE_INFINITY + }; + var _getUserBounds = getUserBounds(otherScale), + otherMin = _getUserBounds.min, + otherMax = _getUserBounds.max; + var i, value, parsed, otherValue; + function _skip() { + parsed = _parsed[i]; + value = parsed[scale.axis]; + otherValue = parsed[otherScale.axis]; + return isNaN(value) || isNaN(otherValue) || otherMin > otherValue || otherMax < otherValue; + } + for (i = 0; i < ilen; ++i) { + if (_skip()) { + continue; + } + me.updateRangeFromParsed(range, scale, parsed, stack); + if (sorted) { + break; + } + } + if (sorted) { + for (i = ilen - 1; i >= 0; --i) { + if (_skip()) { + continue; + } + me.updateRangeFromParsed(range, scale, parsed, stack); + break; + } + } + return range; + }; + _proto.getAllParsedValues = function getAllParsedValues(scale) { + var parsed = this._cachedMeta._parsed; + var values = []; + var i, ilen, value; + for (i = 0, ilen = parsed.length; i < ilen; ++i) { + value = parsed[i][scale.axis]; + if (!isNaN(value)) { + values.push(value); + } + } + return values; + } + ; + _proto.getMaxOverflow = function getMaxOverflow() { + return false; + } + ; + _proto.getLabelAndValue = function getLabelAndValue(index) { + var me = this; + var meta = me._cachedMeta; + var iScale = meta.iScale; + var vScale = meta.vScale; + var parsed = me.getParsed(index); + return { + label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '', + value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : '' + }; + } + ; + _proto._update = function _update(mode) { + var me = this; + var meta = me._cachedMeta; + me.configure(); + me._cachedAnimations = {}; + me._cachedDataOpts = {}; + me.update(mode || 'default'); + meta._clip = toClip(valueOrDefault(me._config.clip, defaultClip(meta.xScale, meta.yScale, me.getMaxOverflow()))); + } + ; + _proto.update = function update(mode) {} + ; + _proto.draw = function draw() { + var me = this; + var ctx = me._ctx; + var chart = me.chart; + var meta = me._cachedMeta; + var elements = meta.data || []; + var area = chart.chartArea; + var active = []; + var start = me._drawStart || 0; + var count = me._drawCount || elements.length - start; + var i; + if (meta.dataset) { + meta.dataset.draw(ctx, area, start, count); + } + for (i = start; i < start + count; ++i) { + var element = elements[i]; + if (element.active) { + active.push(element); + } else { + element.draw(ctx, area); + } + } + for (i = 0; i < active.length; ++i) { + active[i].draw(ctx, area); + } + } + ; + _proto._addAutomaticHoverColors = function _addAutomaticHoverColors(index, options) { + var me = this; + var normalOptions = me.getStyle(index); + var missingColors = Object.keys(normalOptions).filter(function (key) { + return key.indexOf('Color') !== -1 && !(key in options); + }); + var i = missingColors.length - 1; + var color; + for (; i >= 0; i--) { + color = missingColors[i]; + options[color] = getHoverColor(normalOptions[color]); + } + } + ; + _proto.getStyle = function getStyle(index, active) { + var me = this; + var meta = me._cachedMeta; + var dataset = meta.dataset; + if (!me._config) { + me.configure(); + } + var options = dataset && index === undefined ? me.resolveDatasetElementOptions(active) : me.resolveDataElementOptions(index || 0, active && 'active'); + if (active) { + me._addAutomaticHoverColors(index, options); + } + return options; + } + ; + _proto._getContext = function _getContext(index, active) { + return { + chart: this.chart, + dataPoint: this.getParsed(index), + dataIndex: index, + dataset: this.getDataset(), + datasetIndex: this.index, + active: active + }; + } + ; + _proto.resolveDatasetElementOptions = function resolveDatasetElementOptions(active) { + return this._resolveOptions(this.datasetElementOptions, { + active: active, + type: this.datasetElementType.id + }); + } + ; + _proto.resolveDataElementOptions = function resolveDataElementOptions(index, mode) { + mode = mode || 'default'; + var me = this; + var active = mode === 'active'; + var cached = me._cachedDataOpts; + var sharing = me.enableOptionSharing; + if (cached[mode]) { + return cached[mode]; + } + var info = { + cacheable: !active + }; + var values = me._resolveOptions(me.dataElementOptions, { + index: index, + active: active, + info: info, + type: me.dataElementType.id + }); + if (info.cacheable) { + values.$shared = sharing; + cached[mode] = sharing ? Object.freeze(values) : values; + } + return values; + } + ; + _proto._resolveOptions = function _resolveOptions(optionNames, args) { + var me = this; + var index = args.index, + active = args.active, + type = args.type, + info = args.info; + var datasetOpts = me._config; + var options = me.chart.options.elements[type] || {}; + var values = {}; + var context = me._getContext(index, active); + var keys = optionKeys(optionNames); + for (var i = 0, ilen = keys.length; i < ilen; ++i) { + var key = keys[i]; + var readKey = optionKey(key, active); + var value = resolve([datasetOpts[optionNames[readKey]], datasetOpts[readKey], options[readKey]], context, index, info); + if (value !== undefined) { + values[key] = value; + } + } + return values; + } + ; + _proto._resolveAnimations = function _resolveAnimations(index, mode, active) { + var me = this; + var chart = me.chart; + var cached = me._cachedAnimations; + mode = mode || 'default'; + if (cached[mode]) { + return cached[mode]; + } + var info = { + cacheable: true + }; + var context = me._getContext(index, active); + var chartAnim = resolve([chart.options.animation], context, index, info); + var datasetAnim = resolve([me._config.animation], context, index, info); + var config = chartAnim && mergeIf({}, [datasetAnim, chartAnim]); + if (config[mode]) { + config = _extends({}, config, config[mode]); + } + var animations = new Animations(chart, config); + if (info.cacheable) { + cached[mode] = animations && Object.freeze(animations); + } + return animations; + } + ; + _proto.getSharedOptions = function getSharedOptions(options) { + if (!options.$shared) { + return; + } + return this._sharedOptions || (this._sharedOptions = _extends({}, options)); + } + ; + _proto.includeOptions = function includeOptions(mode, sharedOptions) { + return !sharedOptions || isDirectUpdateMode(mode); + } + ; + _proto.updateElement = function updateElement(element, index, properties, mode) { + if (isDirectUpdateMode(mode)) { + _extends(element, properties); + } else { + this._resolveAnimations(index, mode).update(element, properties); + } + } + ; + _proto.updateSharedOptions = function updateSharedOptions(sharedOptions, mode, newOptions) { + if (sharedOptions) { + this._resolveAnimations(undefined, mode).update({ + options: sharedOptions + }, { + options: newOptions + }); + } + } + ; + _proto._setStyle = function _setStyle(element, index, mode, active) { + element.active = active; + var options = this.getStyle(index, active); + this._resolveAnimations(index, mode, active).update(element, { + options: this.getSharedOptions(options) || options + }); + }; + _proto.removeHoverStyle = function removeHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', false); + }; + _proto.setHoverStyle = function setHoverStyle(element, datasetIndex, index) { + this._setStyle(element, index, 'active', true); + } + ; + _proto._removeDatasetHoverStyle = function _removeDatasetHoverStyle() { + var element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', false); + } + } + ; + _proto._setDatasetHoverStyle = function _setDatasetHoverStyle() { + var element = this._cachedMeta.dataset; + if (element) { + this._setStyle(element, undefined, 'active', true); + } + } + ; + _proto._resyncElements = function _resyncElements() { + var me = this; + var meta = me._cachedMeta; + var numMeta = meta.data.length; + var numData = me._data.length; + if (numData > numMeta) { + me._insertElements(numMeta, numData - numMeta); + } else if (numData < numMeta) { + meta.data.splice(numData, numMeta - numData); + meta._parsed.splice(numData, numMeta - numData); + } + me.parse(0, Math.min(numData, numMeta)); + } + ; + _proto._insertElements = function _insertElements(start, count) { + var me = this; + var elements = new Array(count); + var meta = me._cachedMeta; + var data = meta.data; + var i; + for (i = 0; i < count; ++i) { + elements[i] = new me.dataElementType(); + } + data.splice.apply(data, [start, 0].concat(elements)); + if (me._parsing) { + var _meta$_parsed; + (_meta$_parsed = meta._parsed).splice.apply(_meta$_parsed, [start, 0].concat(new Array(count))); + } + me.parse(start, count); + me.updateElements(data, start, count, 'reset'); + }; + _proto.updateElements = function updateElements(element, start, count, mode) {} + ; + _proto._removeElements = function _removeElements(start, count) { + var me = this; + if (me._parsing) { + me._cachedMeta._parsed.splice(start, count); + } + me._cachedMeta.data.splice(start, count); + } + ; + _proto._onDataPush = function _onDataPush() { + var count = arguments.length; + this._insertElements(this.getDataset().data.length - count, count); + } + ; + _proto._onDataPop = function _onDataPop() { + this._removeElements(this._cachedMeta.data.length - 1, 1); + } + ; + _proto._onDataShift = function _onDataShift() { + this._removeElements(0, 1); + } + ; + _proto._onDataSplice = function _onDataSplice(start, count) { + this._removeElements(start, count); + this._insertElements(start, arguments.length - 2); + } + ; + _proto._onDataUnshift = function _onDataUnshift() { + this._insertElements(0, arguments.length); + }; + return DatasetController; +}(); +DatasetController.defaults = {}; +DatasetController.prototype.datasetElementType = null; +DatasetController.prototype.dataElementType = null; +DatasetController.prototype.datasetElementOptions = ['backgroundColor', 'borderCapStyle', 'borderColor', 'borderDash', 'borderDashOffset', 'borderJoinStyle', 'borderWidth']; +DatasetController.prototype.dataElementOptions = ['backgroundColor', 'borderColor', 'borderWidth', 'pointStyle']; + +var Element$1 = function () { + function Element() { + this.x = undefined; + this.y = undefined; + this.active = false; + this.options = undefined; + this.$animations = undefined; + } + var _proto = Element.prototype; + _proto.tooltipPosition = function tooltipPosition(useFinalPosition) { + var _this$getProps = this.getProps(['x', 'y'], useFinalPosition), + x = _this$getProps.x, + y = _this$getProps.y; + return { + x: x, + y: y + }; + }; + _proto.hasValue = function hasValue() { + return isNumber(this.x) && isNumber(this.y); + } + ; + _proto.getProps = function getProps(props, _final) { + var me = this; + var anims = this.$animations; + if (!_final || !anims) { + return me; + } + var ret = {}; + props.forEach(function (prop) { + ret[prop] = anims[prop] && anims[prop].active ? anims[prop]._to : me[prop]; + }); + return ret; + }; + return Element; +}(); +Element$1.defaults = {}; +Element$1.defaultRoutes = undefined; + +var intlCache = new Map(); +var formatters = { + values: function values(value) { + return isArray(value) ? value : '' + value; + }, + numeric: function numeric(tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + var locale = this.chart.options.locale; + var maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value)); + var notation; + if (maxTick < 1e-4 || maxTick > 1e+15) { + notation = 'scientific'; + } + var delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value; + if (Math.abs(delta) > 1 && tickValue !== Math.floor(tickValue)) { + delta = tickValue - Math.floor(tickValue); + } + var logDelta = log10(Math.abs(delta)); + var numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0); + var options = { + notation: notation, + minimumFractionDigits: numDecimal, + maximumFractionDigits: numDecimal + }; + _extends(options, this.options.ticks.format); + var cacheKey = locale + JSON.stringify(options); + var formatter = intlCache.get(cacheKey); + if (!formatter) { + formatter = new Intl.NumberFormat(locale, options); + intlCache.set(cacheKey, formatter); + } + return formatter.format(tickValue); + } +}; +formatters.logarithmic = function (tickValue, index, ticks) { + if (tickValue === 0) { + return '0'; + } + var remain = tickValue / Math.pow(10, Math.floor(log10(tickValue))); + if (remain === 1 || remain === 2 || remain === 5) { + return formatters.numeric.call(this, tickValue, index, ticks); + } + return ''; +}; +var Ticks = { + formatters: formatters +}; + +defaults.set('scale', { + display: true, + offset: false, + reverse: false, + beginAtZero: false, + gridLines: { + display: true, + color: 'rgba(0,0,0,0.1)', + lineWidth: 1, + drawBorder: true, + drawOnChartArea: true, + drawTicks: true, + tickMarkLength: 10, + offsetGridLines: false, + borderDash: [], + borderDashOffset: 0.0 + }, + scaleLabel: { + display: false, + labelString: '', + padding: { + top: 4, + bottom: 4 + } + }, + ticks: { + minRotation: 0, + maxRotation: 50, + mirror: false, + lineWidth: 0, + strokeStyle: '', + padding: 0, + display: true, + autoSkip: true, + autoSkipPadding: 0, + labelOffset: 0, + callback: Ticks.formatters.values, + minor: {}, + major: {} + } +}); +function sample(arr, numItems) { + var result = []; + var increment = arr.length / numItems; + var len = arr.length; + var i = 0; + for (; i < len; i += increment) { + result.push(arr[Math.floor(i)]); + } + return result; +} +function getPixelForGridLine(scale, index, offsetGridLines) { + var length = scale.ticks.length; + var validIndex = Math.min(index, length - 1); + var start = scale._startPixel; + var end = scale._endPixel; + var epsilon = 1e-6; + var lineValue = scale.getPixelForTick(validIndex); + var offset; + if (offsetGridLines) { + if (length === 1) { + offset = Math.max(lineValue - start, end - lineValue); + } else if (index === 0) { + offset = (scale.getPixelForTick(1) - lineValue) / 2; + } else { + offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2; + } + lineValue += validIndex < index ? offset : -offset; + if (lineValue < start - epsilon || lineValue > end + epsilon) { + return; + } + } + return lineValue; +} +function garbageCollect(caches, length) { + each(caches, function (cache) { + var gc = cache.gc; + var gcLen = gc.length / 2; + var i; + if (gcLen > length) { + for (i = 0; i < gcLen; ++i) { + delete cache.data[gc[i]]; + } + gc.splice(0, gcLen); + } + }); +} +function getTickMarkLength(options) { + return options.drawTicks ? options.tickMarkLength : 0; +} +function getScaleLabelHeight(options, fallback) { + if (!options.display) { + return 0; + } + var font = toFont(options.font, fallback); + var padding = toPadding(options.padding); + return font.lineHeight + padding.height; +} +function getEvenSpacing(arr) { + var len = arr.length; + var i, diff; + if (len < 2) { + return false; + } + for (diff = arr[0], i = 1; i < len; ++i) { + if (arr[i] - arr[i - 1] !== diff) { + return false; + } + } + return diff; +} +function calculateSpacing(majorIndices, ticks, ticksLimit) { + var evenMajorSpacing = getEvenSpacing(majorIndices); + var spacing = ticks.length / ticksLimit; + if (!evenMajorSpacing) { + return Math.max(spacing, 1); + } + var factors = _factorize(evenMajorSpacing); + for (var i = 0, ilen = factors.length - 1; i < ilen; i++) { + var factor = factors[i]; + if (factor > spacing) { + return factor; + } + } + return Math.max(spacing, 1); +} +function getMajorIndices(ticks) { + var result = []; + var i, ilen; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + if (ticks[i].major) { + result.push(i); + } + } + return result; +} +function skipMajors(ticks, newTicks, majorIndices, spacing) { + var count = 0; + var next = majorIndices[0]; + var i; + spacing = Math.ceil(spacing); + for (i = 0; i < ticks.length; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = majorIndices[count * spacing]; + } + } +} +function skip(ticks, newTicks, spacing, majorStart, majorEnd) { + var start = valueOrDefault(majorStart, 0); + var end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length); + var count = 0; + var length, i, next; + spacing = Math.ceil(spacing); + if (majorEnd) { + length = majorEnd - majorStart; + spacing = length / Math.floor(length / spacing); + } + next = start; + while (next < 0) { + count++; + next = Math.round(start + count * spacing); + } + for (i = Math.max(start, 0); i < end; i++) { + if (i === next) { + newTicks.push(ticks[i]); + count++; + next = Math.round(start + count * spacing); + } + } +} +var Scale = function (_Element) { + _inheritsLoose(Scale, _Element); + function Scale(cfg) { + var _this; + _this = _Element.call(this) || this; + _this.id = cfg.id; + _this.type = cfg.type; + _this.options = undefined; + _this.ctx = cfg.ctx; + _this.chart = cfg.chart; + _this.top = undefined; + _this.bottom = undefined; + _this.left = undefined; + _this.right = undefined; + _this.width = undefined; + _this.height = undefined; + _this._margins = { + left: 0, + right: 0, + top: 0, + bottom: 0 + }; + _this.maxWidth = undefined; + _this.maxHeight = undefined; + _this.paddingTop = undefined; + _this.paddingBottom = undefined; + _this.paddingLeft = undefined; + _this.paddingRight = undefined; + _this.axis = undefined; + _this.labelRotation = undefined; + _this.min = undefined; + _this.max = undefined; + _this.ticks = []; + _this._gridLineItems = null; + _this._labelItems = null; + _this._labelSizes = null; + _this._length = 0; + _this._longestTextCache = {}; + _this._startPixel = undefined; + _this._endPixel = undefined; + _this._reversePixels = false; + _this._userMax = undefined; + _this._userMin = undefined; + _this._ticksLength = 0; + _this._borderValue = 0; + return _this; + } + var _proto = Scale.prototype; + _proto.init = function init(options) { + var me = this; + me.options = options; + me.axis = me.isHorizontal() ? 'x' : 'y'; + me._userMin = me.parse(options.min); + me._userMax = me.parse(options.max); + } + ; + _proto.parse = function parse(raw, index) { + return raw; + } + ; + _proto.getUserBounds = function getUserBounds() { + var min = this._userMin; + var max = this._userMax; + if (isNullOrUndef(min) || isNaN(min)) { + min = Number.POSITIVE_INFINITY; + } + if (isNullOrUndef(max) || isNaN(max)) { + max = Number.NEGATIVE_INFINITY; + } + return { + min: min, + max: max, + minDefined: isNumberFinite(min), + maxDefined: isNumberFinite(max) + }; + } + ; + _proto.getMinMax = function getMinMax(canStack) { + var me = this; + var _me$getUserBounds = me.getUserBounds(), + min = _me$getUserBounds.min, + max = _me$getUserBounds.max, + minDefined = _me$getUserBounds.minDefined, + maxDefined = _me$getUserBounds.maxDefined; + var range; + if (minDefined && maxDefined) { + return { + min: min, + max: max + }; + } + var metas = me.getMatchingVisibleMetas(); + for (var i = 0, ilen = metas.length; i < ilen; ++i) { + range = metas[i].controller.getMinMax(me, canStack); + if (!minDefined) { + min = Math.min(min, range.min); + } + if (!maxDefined) { + max = Math.max(max, range.max); + } + } + return { + min: min, + max: max + }; + }; + _proto.invalidateCaches = function invalidateCaches() {} + ; + _proto.getPadding = function getPadding() { + var me = this; + return { + left: me.paddingLeft || 0, + top: me.paddingTop || 0, + right: me.paddingRight || 0, + bottom: me.paddingBottom || 0 + }; + } + ; + _proto.getTicks = function getTicks() { + return this.ticks; + } + ; + _proto.getLabels = function getLabels() { + var data = this.chart.data; + return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || []; + } + ; + _proto.beforeUpdate = function beforeUpdate() { + callback(this.options.beforeUpdate, [this]); + } + ; + _proto.update = function update(maxWidth, maxHeight, margins) { + var me = this; + var tickOpts = me.options.ticks; + var sampleSize = tickOpts.sampleSize; + me.beforeUpdate(); + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me._margins = _extends({ + left: 0, + right: 0, + top: 0, + bottom: 0 + }, margins); + me.ticks = null; + me._labelSizes = null; + me._gridLineItems = null; + me._labelItems = null; + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + me.beforeDataLimits(); + me.determineDataLimits(); + me.afterDataLimits(); + me.beforeBuildTicks(); + me.ticks = me.buildTicks() || []; + me.afterBuildTicks(); + var samplingEnabled = sampleSize < me.ticks.length; + me._convertTicksToLabels(samplingEnabled ? sample(me.ticks, sampleSize) : me.ticks); + me.configure(); + me.beforeCalculateLabelRotation(); + me.calculateLabelRotation(); + me.afterCalculateLabelRotation(); + me.beforeFit(); + me.fit(); + me.afterFit(); + me.ticks = tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto') ? me._autoSkip(me.ticks) : me.ticks; + if (samplingEnabled) { + me._convertTicksToLabels(me.ticks); + } + me.afterUpdate(); + } + ; + _proto.configure = function configure() { + var me = this; + var reversePixels = me.options.reverse; + var startPixel, endPixel; + if (me.isHorizontal()) { + startPixel = me.left; + endPixel = me.right; + } else { + startPixel = me.top; + endPixel = me.bottom; + reversePixels = !reversePixels; + } + me._startPixel = startPixel; + me._endPixel = endPixel; + me._reversePixels = reversePixels; + me._length = endPixel - startPixel; + }; + _proto.afterUpdate = function afterUpdate() { + callback(this.options.afterUpdate, [this]); + } + ; + _proto.beforeSetDimensions = function beforeSetDimensions() { + callback(this.options.beforeSetDimensions, [this]); + }; + _proto.setDimensions = function setDimensions() { + var me = this; + if (me.isHorizontal()) { + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + me.top = 0; + me.bottom = me.height; + } + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + }; + _proto.afterSetDimensions = function afterSetDimensions() { + callback(this.options.afterSetDimensions, [this]); + } + ; + _proto.beforeDataLimits = function beforeDataLimits() { + callback(this.options.beforeDataLimits, [this]); + }; + _proto.determineDataLimits = function determineDataLimits() {}; + _proto.afterDataLimits = function afterDataLimits() { + callback(this.options.afterDataLimits, [this]); + } + ; + _proto.beforeBuildTicks = function beforeBuildTicks() { + callback(this.options.beforeBuildTicks, [this]); + } + ; + _proto.buildTicks = function buildTicks() { + return []; + }; + _proto.afterBuildTicks = function afterBuildTicks() { + callback(this.options.afterBuildTicks, [this]); + }; + _proto.beforeTickToLabelConversion = function beforeTickToLabelConversion() { + callback(this.options.beforeTickToLabelConversion, [this]); + } + ; + _proto.generateTickLabels = function generateTickLabels(ticks) { + var me = this; + var tickOpts = me.options.ticks; + var i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; i++) { + tick = ticks[i]; + tick.label = callback(tickOpts.callback, [tick.value, i, ticks], me); + } + }; + _proto.afterTickToLabelConversion = function afterTickToLabelConversion() { + callback(this.options.afterTickToLabelConversion, [this]); + } + ; + _proto.beforeCalculateLabelRotation = function beforeCalculateLabelRotation() { + callback(this.options.beforeCalculateLabelRotation, [this]); + }; + _proto.calculateLabelRotation = function calculateLabelRotation() { + var me = this; + var options = me.options; + var tickOpts = options.ticks; + var numTicks = me.ticks.length; + var minRotation = tickOpts.minRotation || 0; + var maxRotation = tickOpts.maxRotation; + var labelRotation = minRotation; + var tickWidth, maxHeight, maxLabelDiagonal; + if (!me._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !me.isHorizontal()) { + me.labelRotation = minRotation; + return; + } + var labelSizes = me._getLabelSizes(); + var maxLabelWidth = labelSizes.widest.width; + var maxLabelHeight = labelSizes.highest.height - labelSizes.highest.offset; + var maxWidth = Math.min(me.maxWidth, me.chart.width - maxLabelWidth); + tickWidth = options.offset ? me.maxWidth / numTicks : maxWidth / (numTicks - 1); + if (maxLabelWidth + 6 > tickWidth) { + tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1)); + maxHeight = me.maxHeight - getTickMarkLength(options.gridLines) - tickOpts.padding - getScaleLabelHeight(options.scaleLabel, me.chart.options.font); + maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight); + labelRotation = toDegrees(Math.min(Math.asin(Math.min((labelSizes.highest.height + 6) / tickWidth, 1)), Math.asin(Math.min(maxHeight / maxLabelDiagonal, 1)) - Math.asin(maxLabelHeight / maxLabelDiagonal))); + labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation)); + } + me.labelRotation = labelRotation; + }; + _proto.afterCalculateLabelRotation = function afterCalculateLabelRotation() { + callback(this.options.afterCalculateLabelRotation, [this]); + } + ; + _proto.beforeFit = function beforeFit() { + callback(this.options.beforeFit, [this]); + }; + _proto.fit = function fit() { + var me = this; + var minSize = { + width: 0, + height: 0 + }; + var chart = me.chart; + var opts = me.options; + var tickOpts = opts.ticks; + var scaleLabelOpts = opts.scaleLabel; + var gridLineOpts = opts.gridLines; + var display = me._isVisible(); + var labelsBelowTicks = opts.position !== 'top' && me.axis === 'x'; + var isHorizontal = me.isHorizontal(); + var scaleLabelHeight = display && getScaleLabelHeight(scaleLabelOpts, chart.options.font); + if (isHorizontal) { + minSize.width = me.maxWidth; + } else if (display) { + minSize.width = getTickMarkLength(gridLineOpts) + scaleLabelHeight; + } + if (!isHorizontal) { + minSize.height = me.maxHeight; + } else if (display) { + minSize.height = getTickMarkLength(gridLineOpts) + scaleLabelHeight; + } + if (tickOpts.display && display && me.ticks.length) { + var labelSizes = me._getLabelSizes(); + var firstLabelSize = labelSizes.first; + var lastLabelSize = labelSizes.last; + var widestLabelSize = labelSizes.widest; + var highestLabelSize = labelSizes.highest; + var lineSpace = highestLabelSize.offset * 0.8; + var tickPadding = tickOpts.padding; + if (isHorizontal) { + var isRotated = me.labelRotation !== 0; + var angleRadians = toRadians(me.labelRotation); + var cosRotation = Math.cos(angleRadians); + var sinRotation = Math.sin(angleRadians); + var labelHeight = sinRotation * widestLabelSize.width + cosRotation * (highestLabelSize.height - (isRotated ? highestLabelSize.offset : 0)) + (isRotated ? 0 : lineSpace); + minSize.height = Math.min(me.maxHeight, minSize.height + labelHeight + tickPadding); + var offsetLeft = me.getPixelForTick(0) - me.left; + var offsetRight = me.right - me.getPixelForTick(me.ticks.length - 1); + var paddingLeft, paddingRight; + if (isRotated) { + paddingLeft = labelsBelowTicks ? cosRotation * firstLabelSize.width + sinRotation * firstLabelSize.offset : sinRotation * (firstLabelSize.height - firstLabelSize.offset); + paddingRight = labelsBelowTicks ? sinRotation * (lastLabelSize.height - lastLabelSize.offset) : cosRotation * lastLabelSize.width + sinRotation * lastLabelSize.offset; + } else { + paddingLeft = firstLabelSize.width / 2; + paddingRight = lastLabelSize.width / 2; + } + me.paddingLeft = Math.max((paddingLeft - offsetLeft) * me.width / (me.width - offsetLeft), 0) + 3; + me.paddingRight = Math.max((paddingRight - offsetRight) * me.width / (me.width - offsetRight), 0) + 3; + } else { + var labelWidth = tickOpts.mirror ? 0 : + widestLabelSize.width + tickPadding + lineSpace; + minSize.width = Math.min(me.maxWidth, minSize.width + labelWidth); + me.paddingTop = lastLabelSize.height / 2; + me.paddingBottom = firstLabelSize.height / 2; + } + } + me._handleMargins(); + if (isHorizontal) { + me.width = me._length = chart.width - me._margins.left - me._margins.right; + me.height = minSize.height; + } else { + me.width = minSize.width; + me.height = me._length = chart.height - me._margins.top - me._margins.bottom; + } + } + ; + _proto._handleMargins = function _handleMargins() { + var me = this; + if (me._margins) { + me._margins.left = Math.max(me.paddingLeft, me._margins.left); + me._margins.top = Math.max(me.paddingTop, me._margins.top); + me._margins.right = Math.max(me.paddingRight, me._margins.right); + me._margins.bottom = Math.max(me.paddingBottom, me._margins.bottom); + } + }; + _proto.afterFit = function afterFit() { + callback(this.options.afterFit, [this]); + } + ; + _proto.isHorizontal = function isHorizontal() { + var _this$options = this.options, + axis = _this$options.axis, + position = _this$options.position; + return position === 'top' || position === 'bottom' || axis === 'x'; + } + ; + _proto.isFullWidth = function isFullWidth() { + return this.options.fullWidth; + } + ; + _proto._convertTicksToLabels = function _convertTicksToLabels(ticks) { + var me = this; + me.beforeTickToLabelConversion(); + me.generateTickLabels(ticks); + me.afterTickToLabelConversion(); + } + ; + _proto._getLabelSizes = function _getLabelSizes() { + var me = this; + var labelSizes = me._labelSizes; + if (!labelSizes) { + me._labelSizes = labelSizes = me._computeLabelSizes(); + } + return labelSizes; + } + ; + _proto._computeLabelSizes = function _computeLabelSizes() { + var me = this; + var ctx = me.ctx; + var caches = me._longestTextCache; + var sampleSize = me.options.ticks.sampleSize; + var widths = []; + var heights = []; + var offsets = []; + var ticks = me.ticks; + if (sampleSize < ticks.length) { + ticks = sample(ticks, sampleSize); + } + var length = ticks.length; + var i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel; + for (i = 0; i < length; ++i) { + label = ticks[i].label; + tickFont = me._resolveTickFontOptions(i); + ctx.font = fontString = tickFont.string; + cache = caches[fontString] = caches[fontString] || { + data: {}, + gc: [] + }; + lineHeight = tickFont.lineHeight; + width = height = 0; + if (!isNullOrUndef(label) && !isArray(label)) { + width = _measureText(ctx, cache.data, cache.gc, width, label); + height = lineHeight; + } else if (isArray(label)) { + for (j = 0, jlen = label.length; j < jlen; ++j) { + nestedLabel = label[j]; + if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) { + width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel); + height += lineHeight; + } + } + } + widths.push(width); + heights.push(height); + offsets.push(lineHeight / 2); + } + garbageCollect(caches, length); + var widest = widths.indexOf(Math.max.apply(null, widths)); + var highest = heights.indexOf(Math.max.apply(null, heights)); + function valueAt(idx) { + return { + width: widths[idx] || 0, + height: heights[idx] || 0, + offset: offsets[idx] || 0 + }; + } + return { + first: valueAt(0), + last: valueAt(length - 1), + widest: valueAt(widest), + highest: valueAt(highest) + }; + } + ; + _proto.getLabelForValue = function getLabelForValue(value) { + return value; + } + ; + _proto.getPixelForValue = function getPixelForValue(value, index) { + return NaN; + } + ; + _proto.getValueForPixel = function getValueForPixel(pixel) {} + ; + _proto.getPixelForTick = function getPixelForTick(index) { + var ticks = this.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return this.getPixelForValue(ticks[index].value); + } + ; + _proto.getPixelForDecimal = function getPixelForDecimal(decimal) { + var me = this; + if (me._reversePixels) { + decimal = 1 - decimal; + } + return _int32Range(me._startPixel + decimal * me._length); + } + ; + _proto.getDecimalForPixel = function getDecimalForPixel(pixel) { + var decimal = (pixel - this._startPixel) / this._length; + return this._reversePixels ? 1 - decimal : decimal; + } + ; + _proto.getBasePixel = function getBasePixel() { + return this.getPixelForValue(this.getBaseValue()); + } + ; + _proto.getBaseValue = function getBaseValue() { + var min = this.min, + max = this.max; + return min < 0 && max < 0 ? max : min > 0 && max > 0 ? min : 0; + } + ; + _proto._autoSkip = function _autoSkip(ticks) { + var me = this; + var tickOpts = me.options.ticks; + var ticksLimit = tickOpts.maxTicksLimit || me._length / me._tickSize(); + var majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : []; + var numMajorIndices = majorIndices.length; + var first = majorIndices[0]; + var last = majorIndices[numMajorIndices - 1]; + var newTicks = []; + if (numMajorIndices > ticksLimit) { + skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit); + return newTicks; + } + var spacing = calculateSpacing(majorIndices, ticks, ticksLimit); + if (numMajorIndices > 0) { + var i, ilen; + var avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null; + skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first); + for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) { + skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]); + } + skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing); + return newTicks; + } + skip(ticks, newTicks, spacing); + return newTicks; + } + ; + _proto._tickSize = function _tickSize() { + var me = this; + var optionTicks = me.options.ticks; + var rot = toRadians(me.labelRotation); + var cos = Math.abs(Math.cos(rot)); + var sin = Math.abs(Math.sin(rot)); + var labelSizes = me._getLabelSizes(); + var padding = optionTicks.autoSkipPadding || 0; + var w = labelSizes ? labelSizes.widest.width + padding : 0; + var h = labelSizes ? labelSizes.highest.height + padding : 0; + return me.isHorizontal() ? h * cos > w * sin ? w / cos : h / sin : h * sin < w * cos ? h / cos : w / sin; + } + ; + _proto._isVisible = function _isVisible() { + var display = this.options.display; + if (display !== 'auto') { + return !!display; + } + return this.getMatchingVisibleMetas().length > 0; + } + ; + _proto._computeGridLineItems = function _computeGridLineItems(chartArea) { + var me = this; + var axis = me.axis; + var chart = me.chart; + var options = me.options; + var gridLines = options.gridLines, + position = options.position; + var offsetGridLines = gridLines.offsetGridLines; + var isHorizontal = me.isHorizontal(); + var ticks = me.ticks; + var ticksLength = ticks.length + (offsetGridLines ? 1 : 0); + var tl = getTickMarkLength(gridLines); + var items = []; + var context = { + chart: chart, + scale: me, + tick: ticks[0], + index: 0 + }; + var axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0; + var axisHalfWidth = axisWidth / 2; + var alignBorderValue = function alignBorderValue(pixel) { + return _alignPixel(chart, pixel, axisWidth); + }; + var borderValue, i, lineValue, alignedLineValue; + var tx1, ty1, tx2, ty2, x1, y1, x2, y2; + if (position === 'top') { + borderValue = alignBorderValue(me.bottom); + ty1 = me.bottom - tl; + ty2 = borderValue - axisHalfWidth; + y1 = alignBorderValue(chartArea.top) + axisHalfWidth; + y2 = chartArea.bottom; + } else if (position === 'bottom') { + borderValue = alignBorderValue(me.top); + y1 = chartArea.top; + y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth; + ty1 = borderValue + axisHalfWidth; + ty2 = me.top + tl; + } else if (position === 'left') { + borderValue = alignBorderValue(me.right); + tx1 = me.right - tl; + tx2 = borderValue - axisHalfWidth; + x1 = alignBorderValue(chartArea.left) + axisHalfWidth; + x2 = chartArea.right; + } else if (position === 'right') { + borderValue = alignBorderValue(me.left); + x1 = chartArea.left; + x2 = alignBorderValue(chartArea.right) - axisHalfWidth; + tx1 = borderValue + axisHalfWidth; + tx2 = me.left + tl; + } else if (axis === 'x') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2); + } else if (isObject(position)) { + var positionAxisID = Object.keys(position)[0]; + var value = position[positionAxisID]; + borderValue = alignBorderValue(me.chart.scales[positionAxisID].getPixelForValue(value)); + } + y1 = chartArea.top; + y2 = chartArea.bottom; + ty1 = borderValue + axisHalfWidth; + ty2 = ty1 + tl; + } else if (axis === 'y') { + if (position === 'center') { + borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2); + } else if (isObject(position)) { + var _positionAxisID = Object.keys(position)[0]; + var _value = position[_positionAxisID]; + borderValue = alignBorderValue(me.chart.scales[_positionAxisID].getPixelForValue(_value)); + } + tx1 = borderValue - axisHalfWidth; + tx2 = tx1 - tl; + x1 = chartArea.left; + x2 = chartArea.right; + } + for (i = 0; i < ticksLength; ++i) { + var tick = ticks[i] || {}; + context = { + chart: chart, + scale: me, + tick: tick, + index: i + }; + var lineWidth = resolve([gridLines.lineWidth], context, i); + var lineColor = resolve([gridLines.color], context, i); + var borderDash = gridLines.borderDash || []; + var borderDashOffset = resolve([gridLines.borderDashOffset], context, i); + lineValue = getPixelForGridLine(me, i, offsetGridLines); + if (lineValue === undefined) { + continue; + } + alignedLineValue = _alignPixel(chart, lineValue, lineWidth); + if (isHorizontal) { + tx1 = tx2 = x1 = x2 = alignedLineValue; + } else { + ty1 = ty2 = y1 = y2 = alignedLineValue; + } + items.push({ + tx1: tx1, + ty1: ty1, + tx2: tx2, + ty2: ty2, + x1: x1, + y1: y1, + x2: x2, + y2: y2, + width: lineWidth, + color: lineColor, + borderDash: borderDash, + borderDashOffset: borderDashOffset + }); + } + me._ticksLength = ticksLength; + me._borderValue = borderValue; + return items; + } + ; + _proto._computeLabelItems = function _computeLabelItems(chartArea) { + var me = this; + var axis = me.axis; + var options = me.options; + var position = options.position, + optionTicks = options.ticks; + var isMirrored = optionTicks.mirror; + var isHorizontal = me.isHorizontal(); + var ticks = me.ticks; + var tickPadding = optionTicks.padding; + var tl = getTickMarkLength(options.gridLines); + var rotation = -toRadians(me.labelRotation); + var items = []; + var i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset; + if (position === 'top') { + y = me.bottom - tl - tickPadding; + textAlign = !rotation ? 'center' : 'left'; + } else if (position === 'bottom') { + y = me.top + tl + tickPadding; + textAlign = !rotation ? 'center' : 'right'; + } else if (position === 'left') { + x = me.right - (isMirrored ? 0 : tl) - tickPadding; + textAlign = isMirrored ? 'left' : 'right'; + } else if (position === 'right') { + x = me.left + (isMirrored ? 0 : tl) + tickPadding; + textAlign = isMirrored ? 'right' : 'left'; + } else if (axis === 'x') { + if (position === 'center') { + y = (chartArea.top + chartArea.bottom) / 2 + tl + tickPadding; + } else if (isObject(position)) { + var positionAxisID = Object.keys(position)[0]; + var value = position[positionAxisID]; + y = me.chart.scales[positionAxisID].getPixelForValue(value) + tl + tickPadding; + } + textAlign = !rotation ? 'center' : 'right'; + } else if (axis === 'y') { + if (position === 'center') { + x = (chartArea.left + chartArea.right) / 2 - tl - tickPadding; + } else if (isObject(position)) { + var _positionAxisID2 = Object.keys(position)[0]; + var _value2 = position[_positionAxisID2]; + x = me.chart.scales[_positionAxisID2].getPixelForValue(_value2); + } + textAlign = 'right'; + } + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + label = tick.label; + pixel = me.getPixelForTick(i) + optionTicks.labelOffset; + font = me._resolveTickFontOptions(i); + lineHeight = font.lineHeight; + lineCount = isArray(label) ? label.length : 1; + if (isHorizontal) { + x = pixel; + if (position === 'top') { + textOffset = (Math.sin(rotation) * (lineCount / 2) + 0.5) * lineHeight; + textOffset -= (rotation === 0 ? lineCount - 0.5 : Math.cos(rotation) * (lineCount / 2)) * lineHeight; + } else { + textOffset = Math.sin(rotation) * (lineCount / 2) * lineHeight; + textOffset += (rotation === 0 ? 0.5 : Math.cos(rotation) * (lineCount / 2)) * lineHeight; + } + } else { + y = pixel; + textOffset = (1 - lineCount) * lineHeight / 2; + } + items.push({ + x: x, + y: y, + rotation: rotation, + label: label, + font: font, + textOffset: textOffset, + textAlign: textAlign + }); + } + return items; + } + ; + _proto.drawGrid = function drawGrid(chartArea) { + var me = this; + var gridLines = me.options.gridLines; + var ctx = me.ctx; + var chart = me.chart; + var context = { + chart: chart, + scale: me, + tick: me.ticks[0], + index: 0 + }; + var axisWidth = gridLines.drawBorder ? resolve([gridLines.borderWidth, gridLines.lineWidth, 0], context, 0) : 0; + var items = me._gridLineItems || (me._gridLineItems = me._computeGridLineItems(chartArea)); + var i, ilen; + if (gridLines.display) { + for (i = 0, ilen = items.length; i < ilen; ++i) { + var item = items[i]; + var width = item.width; + var color = item.color; + if (width && color) { + ctx.save(); + ctx.lineWidth = width; + ctx.strokeStyle = color; + if (ctx.setLineDash) { + ctx.setLineDash(item.borderDash); + ctx.lineDashOffset = item.borderDashOffset; + } + ctx.beginPath(); + if (gridLines.drawTicks) { + ctx.moveTo(item.tx1, item.ty1); + ctx.lineTo(item.tx2, item.ty2); + } + if (gridLines.drawOnChartArea) { + ctx.moveTo(item.x1, item.y1); + ctx.lineTo(item.x2, item.y2); + } + ctx.stroke(); + ctx.restore(); + } + } + } + if (axisWidth) { + var firstLineWidth = axisWidth; + context = { + chart: chart, + scale: me, + tick: me.ticks[me._ticksLength - 1], + index: me._ticksLength - 1 + }; + var lastLineWidth = resolve([gridLines.lineWidth, 1], context, me._ticksLength - 1); + var borderValue = me._borderValue; + var x1, x2, y1, y2; + if (me.isHorizontal()) { + x1 = _alignPixel(chart, me.left, firstLineWidth) - firstLineWidth / 2; + x2 = _alignPixel(chart, me.right, lastLineWidth) + lastLineWidth / 2; + y1 = y2 = borderValue; + } else { + y1 = _alignPixel(chart, me.top, firstLineWidth) - firstLineWidth / 2; + y2 = _alignPixel(chart, me.bottom, lastLineWidth) + lastLineWidth / 2; + x1 = x2 = borderValue; + } + ctx.lineWidth = axisWidth; + ctx.strokeStyle = resolve([gridLines.borderColor, gridLines.color], context, 0); + ctx.beginPath(); + ctx.moveTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.stroke(); + } + } + ; + _proto.drawLabels = function drawLabels(chartArea) { + var me = this; + var optionTicks = me.options.ticks; + if (!optionTicks.display) { + return; + } + var ctx = me.ctx; + var items = me._labelItems || (me._labelItems = me._computeLabelItems(chartArea)); + var i, j, ilen, jlen; + for (i = 0, ilen = items.length; i < ilen; ++i) { + var item = items[i]; + var tickFont = item.font; + var useStroke = tickFont.lineWidth > 0 && tickFont.strokeStyle !== ''; + ctx.save(); + ctx.translate(item.x, item.y); + ctx.rotate(item.rotation); + ctx.font = tickFont.string; + ctx.fillStyle = tickFont.color; + ctx.textBaseline = 'middle'; + ctx.textAlign = item.textAlign; + if (useStroke) { + ctx.strokeStyle = tickFont.strokeStyle; + ctx.lineWidth = tickFont.lineWidth; + } + var label = item.label; + var y = item.textOffset; + if (isArray(label)) { + for (j = 0, jlen = label.length; j < jlen; ++j) { + if (useStroke) { + ctx.strokeText('' + label[j], 0, y); + } + ctx.fillText('' + label[j], 0, y); + y += tickFont.lineHeight; + } + } else { + if (useStroke) { + ctx.strokeText(label, 0, y); + } + ctx.fillText(label, 0, y); + } + ctx.restore(); + } + } + ; + _proto.drawTitle = function drawTitle(chartArea) { + var me = this; + var ctx = me.ctx; + var options = me.options; + var scaleLabel = options.scaleLabel; + if (!scaleLabel.display) { + return; + } + var scaleLabelFont = toFont(scaleLabel.font, me.chart.options.font); + var scaleLabelPadding = toPadding(scaleLabel.padding); + var halfLineHeight = scaleLabelFont.lineHeight / 2; + var scaleLabelAlign = scaleLabel.align; + var position = options.position; + var isReverse = me.options.reverse; + var rotation = 0; + var textAlign; + var scaleLabelX, scaleLabelY; + if (me.isHorizontal()) { + switch (scaleLabelAlign) { + case 'start': + scaleLabelX = me.left + (isReverse ? me.width : 0); + textAlign = isReverse ? 'right' : 'left'; + break; + case 'end': + scaleLabelX = me.left + (isReverse ? 0 : me.width); + textAlign = isReverse ? 'left' : 'right'; + break; + default: + scaleLabelX = me.left + me.width / 2; + textAlign = 'center'; + } + scaleLabelY = position === 'top' ? me.top + halfLineHeight + scaleLabelPadding.top : me.bottom - halfLineHeight - scaleLabelPadding.bottom; + } else { + var isLeft = position === 'left'; + scaleLabelX = isLeft ? me.left + halfLineHeight + scaleLabelPadding.top : me.right - halfLineHeight - scaleLabelPadding.top; + switch (scaleLabelAlign) { + case 'start': + scaleLabelY = me.top + (isReverse ? 0 : me.height); + textAlign = isReverse === isLeft ? 'right' : 'left'; + break; + case 'end': + scaleLabelY = me.top + (isReverse ? me.height : 0); + textAlign = isReverse === isLeft ? 'left' : 'right'; + break; + default: + scaleLabelY = me.top + me.height / 2; + textAlign = 'center'; + } + rotation = isLeft ? -0.5 * Math.PI : 0.5 * Math.PI; + } + ctx.save(); + ctx.translate(scaleLabelX, scaleLabelY); + ctx.rotate(rotation); + ctx.textAlign = textAlign; + ctx.textBaseline = 'middle'; + ctx.fillStyle = scaleLabelFont.color; + ctx.font = scaleLabelFont.string; + ctx.fillText(scaleLabel.labelString, 0, 0); + ctx.restore(); + }; + _proto.draw = function draw(chartArea) { + var me = this; + if (!me._isVisible()) { + return; + } + me.drawGrid(chartArea); + me.drawTitle(); + me.drawLabels(chartArea); + } + ; + _proto._layers = function _layers() { + var me = this; + var opts = me.options; + var tz = opts.ticks && opts.ticks.z || 0; + var gz = opts.gridLines && opts.gridLines.z || 0; + if (!me._isVisible() || tz === gz || me.draw !== me._draw) { + return [{ + z: tz, + draw: function draw(chartArea) { + me.draw(chartArea); + } + }]; + } + return [{ + z: gz, + draw: function draw(chartArea) { + me.drawGrid(chartArea); + me.drawTitle(); + } + }, { + z: tz, + draw: function draw(chartArea) { + me.drawLabels(chartArea); + } + }]; + } + ; + _proto.getMatchingVisibleMetas = function getMatchingVisibleMetas(type) { + var me = this; + var metas = me.chart.getSortedVisibleDatasetMetas(); + var axisID = me.axis + 'AxisID'; + var result = []; + var i, ilen; + for (i = 0, ilen = metas.length; i < ilen; ++i) { + var meta = metas[i]; + if (meta[axisID] === me.id && (!type || meta.type === type)) { + result.push(meta); + } + } + return result; + } + ; + _proto._resolveTickFontOptions = function _resolveTickFontOptions(index) { + var me = this; + var chart = me.chart; + var options = me.options.ticks; + var ticks = me.ticks || []; + var context = { + chart: chart, + scale: me, + tick: ticks[index], + index: index + }; + return toFont(resolve([options.font], context), chart.options.font); + }; + return Scale; +}(Element$1); +Scale.prototype._draw = Scale.prototype.draw; + +var TypedRegistry = function () { + function TypedRegistry(type, scope) { + this.type = type; + this.scope = scope; + this.items = Object.create(null); + } + var _proto = TypedRegistry.prototype; + _proto.isForType = function isForType(type) { + return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype); + } + ; + _proto.register = function register(item) { + var proto = Object.getPrototypeOf(item); + var parentScope; + if (isIChartComponent(proto)) { + parentScope = this.register(proto); + } + var items = this.items; + var id = item.id; + var baseScope = this.scope; + var scope = baseScope ? baseScope + '.' + id : id; + if (!id) { + throw new Error('class does not have id: ' + item); + } + if (id in items) { + return scope; + } + if (Object.keys(defaults.get(scope)).length) { + throw new Error('Can not register "' + id + '", because "defaults.' + scope + '" would collide with existing defaults'); + } + items[id] = item; + registerDefaults(item, scope, parentScope); + return scope; + } + ; + _proto.get = function get(id) { + return this.items[id]; + } + ; + _proto.unregister = function unregister(item) { + var items = this.items; + var id = item.id; + var scope = this.scope; + if (id in items) { + delete items[id]; + } + if (scope && id in defaults[scope]) { + delete defaults[scope][id]; + } else if (id in defaults) { + delete defaults[id]; + } + }; + return TypedRegistry; +}(); +function registerDefaults(item, scope, parentScope) { + var itemDefaults = parentScope ? _extends({}, defaults.get(parentScope), item.defaults) : item.defaults; + defaults.set(scope, itemDefaults); + if (item.defaultRoutes) { + routeDefaults(scope, item.defaultRoutes); + } +} +function routeDefaults(scope, routes) { + Object.keys(routes).forEach(function (property) { + var parts = routes[property].split('.'); + var targetName = parts.pop(); + var targetScope = parts.join('.'); + defaults.route(scope, property, targetScope, targetName); + }); +} +function isIChartComponent(proto) { + return 'id' in proto && 'defaults' in proto; +} + +var Registry = function () { + function Registry() { + this.controllers = new TypedRegistry(DatasetController, ''); + this.elements = new TypedRegistry(Element$1, 'elements'); + this.plugins = new TypedRegistry(Object, 'plugins'); + this.scales = new TypedRegistry(Scale, 'scales'); + this._typedRegistries = [this.controllers, this.scales, this.elements]; + } + var _proto = Registry.prototype; + _proto.add = function add() { + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + this._each('register', args); + }; + _proto.remove = function remove() { + for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) { + args[_key2] = arguments[_key2]; + } + this._each('unregister', args); + } + ; + _proto.addControllers = function addControllers() { + for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) { + args[_key3] = arguments[_key3]; + } + this._each('register', args, this.controllers); + } + ; + _proto.addElements = function addElements() { + for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) { + args[_key4] = arguments[_key4]; + } + this._each('register', args, this.elements); + } + ; + _proto.addPlugins = function addPlugins() { + for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) { + args[_key5] = arguments[_key5]; + } + this._each('register', args, this.plugins); + } + ; + _proto.addScales = function addScales() { + for (var _len6 = arguments.length, args = new Array(_len6), _key6 = 0; _key6 < _len6; _key6++) { + args[_key6] = arguments[_key6]; + } + this._each('register', args, this.scales); + } + ; + _proto.getController = function getController(id) { + return this._get(id, this.controllers, 'controller'); + } + ; + _proto.getElement = function getElement(id) { + return this._get(id, this.elements, 'element'); + } + ; + _proto.getPlugin = function getPlugin(id) { + return this._get(id, this.plugins, 'plugin'); + } + ; + _proto.getScale = function getScale(id) { + return this._get(id, this.scales, 'scale'); + } + ; + _proto.removeControllers = function removeControllers() { + for (var _len7 = arguments.length, args = new Array(_len7), _key7 = 0; _key7 < _len7; _key7++) { + args[_key7] = arguments[_key7]; + } + this._each('unregister', args, this.controllers); + } + ; + _proto.removeElements = function removeElements() { + for (var _len8 = arguments.length, args = new Array(_len8), _key8 = 0; _key8 < _len8; _key8++) { + args[_key8] = arguments[_key8]; + } + this._each('unregister', args, this.elements); + } + ; + _proto.removePlugins = function removePlugins() { + for (var _len9 = arguments.length, args = new Array(_len9), _key9 = 0; _key9 < _len9; _key9++) { + args[_key9] = arguments[_key9]; + } + this._each('unregister', args, this.plugins); + } + ; + _proto.removeScales = function removeScales() { + for (var _len10 = arguments.length, args = new Array(_len10), _key10 = 0; _key10 < _len10; _key10++) { + args[_key10] = arguments[_key10]; + } + this._each('unregister', args, this.scales); + } + ; + _proto._each = function _each(method, args, typedRegistry) { + var me = this; + [].concat(args).forEach(function (arg) { + var reg = typedRegistry || me._getRegistryForType(arg); + if (typedRegistry || reg.isForType(arg) || reg === me.plugins && arg.id) { + me._exec(method, reg, arg); + } else { + each(arg, function (item) { + var itemReg = typedRegistry || me._getRegistryForType(item); + me._exec(method, itemReg, item); + }); + } + }); + } + ; + _proto._exec = function _exec(method, registry, component) { + var camelMethod = _capitalize(method); + callback(component['before' + camelMethod], [], component); + registry[method](component); + callback(component['after' + camelMethod], [], component); + } + ; + _proto._getRegistryForType = function _getRegistryForType(type) { + for (var i = 0; i < this._typedRegistries.length; i++) { + var reg = this._typedRegistries[i]; + if (reg.isForType(type)) { + return reg; + } + } + return this.plugins; + } + ; + _proto._get = function _get(id, typedRegistry, type) { + var item = typedRegistry.get(id); + if (item === undefined) { + throw new Error('"' + id + '" is not a registered ' + type + '.'); + } + return item; + }; + return Registry; +}(); +var registry = new Registry(); + +var PluginService = function () { + function PluginService() {} + var _proto = PluginService.prototype; + _proto.notify = function notify(chart, hook, args) { + var descriptors = this._descriptors(chart); + for (var i = 0; i < descriptors.length; ++i) { + var descriptor = descriptors[i]; + var plugin = descriptor.plugin; + var method = plugin[hook]; + if (typeof method === 'function') { + var params = [chart].concat(args || []); + params.push(descriptor.options); + if (method.apply(plugin, params) === false) { + return false; + } + } + } + return true; + }; + _proto.invalidate = function invalidate() { + this._cache = undefined; + } + ; + _proto._descriptors = function _descriptors(chart) { + if (this._cache) { + return this._cache; + } + var config = chart && chart.config || {}; + var options = config.options && config.options.plugins || {}; + var plugins = allPlugins(config); + var descriptors = createDescriptors(plugins, options); + this._cache = descriptors; + return descriptors; + }; + return PluginService; +}(); +function allPlugins(config) { + var plugins = []; + var keys = Object.keys(registry.plugins.items); + for (var i = 0; i < keys.length; i++) { + plugins.push(registry.getPlugin(keys[i])); + } + var local = config.plugins || []; + for (var _i = 0; _i < local.length; _i++) { + var plugin = local[_i]; + if (plugins.indexOf(plugin) === -1) { + plugins.push(plugin); + } + } + return plugins; +} +function createDescriptors(plugins, options) { + var result = []; + for (var i = 0; i < plugins.length; i++) { + var plugin = plugins[i]; + var id = plugin.id; + var opts = options[id]; + if (opts === false) { + continue; + } + if (opts === true) { + opts = {}; + } + result.push({ + plugin: plugin, + options: mergeIf({}, [opts, defaults.plugins[id]]) + }); + } + return result; +} + +var version = "3.0.0-beta.2"; + +function getIndexAxis(type, options) { + var typeDefaults = defaults[type] || {}; + var datasetDefaults = typeDefaults.datasets || {}; + var typeOptions = options[type] || {}; + var datasetOptions = typeOptions.datasets || {}; + return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x'; +} +function getAxisFromDefaultScaleID(id, indexAxis) { + var axis = id; + if (id === '_index_') { + axis = indexAxis; + } else if (id === '_value_') { + axis = indexAxis === 'x' ? 'y' : 'x'; + } + return axis; +} +function getDefaultScaleIDFromAxis(axis, indexAxis) { + return axis === indexAxis ? '_index_' : '_value_'; +} +function mergeScaleConfig(config, options) { + options = options || {}; + var chartDefaults = defaults[config.type] || { + scales: {} + }; + var configScales = options.scales || {}; + var chartIndexAxis = getIndexAxis(config.type, options); + var firstIDs = {}; + var scales = {}; + Object.keys(configScales).forEach(function (id) { + var scaleConf = configScales[id]; + var axis = determineAxis(id, scaleConf); + var defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis); + firstIDs[axis] = firstIDs[axis] || id; + scales[id] = mergeIf({ + axis: axis + }, [scaleConf, chartDefaults.scales[axis], chartDefaults.scales[defaultId]]); + }); + if (options.scale) { + scales[options.scale.id || 'r'] = mergeIf({ + axis: 'r' + }, [options.scale, chartDefaults.scales.r]); + firstIDs.r = firstIDs.r || options.scale.id || 'r'; + } + config.data.datasets.forEach(function (dataset) { + var type = dataset.type || config.type; + var indexAxis = dataset.indexAxis || getIndexAxis(type, options); + var datasetDefaults = defaults[type] || {}; + var defaultScaleOptions = datasetDefaults.scales || {}; + Object.keys(defaultScaleOptions).forEach(function (defaultID) { + var axis = getAxisFromDefaultScaleID(defaultID, indexAxis); + var id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis; + scales[id] = scales[id] || {}; + mergeIf(scales[id], [{ + axis: axis + }, configScales[id], defaultScaleOptions[defaultID]]); + }); + }); + Object.keys(scales).forEach(function (key) { + var scale = scales[key]; + mergeIf(scale, [defaults.scales[scale.type], defaults.scale]); + }); + return scales; +} +function mergeConfig() +{ + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + return merge({}, args, { + merger: function merger(key, target, source, options) { + if (key !== 'scales' && key !== 'scale') { + _merger(key, target, source, options); + } + } + }); +} +function initConfig(config) { + config = config || {}; + var data = config.data = config.data || { + datasets: [], + labels: [] + }; + data.datasets = data.datasets || []; + data.labels = data.labels || []; + var scaleConfig = mergeScaleConfig(config, config.options); + var options = config.options = mergeConfig(defaults, defaults[config.type], config.options || {}); + options.scales = scaleConfig; + options.title = options.title !== false && merge({}, [defaults.plugins.title, options.title]); + options.tooltips = options.tooltips !== false && merge({}, [defaults.plugins.tooltip, options.tooltips]); + return config; +} +function isAnimationDisabled(config) { + return !config.animation; +} +function updateConfig(chart) { + var newOptions = chart.options; + each(chart.scales, function (scale) { + layouts.removeBox(chart, scale); + }); + var scaleConfig = mergeScaleConfig(chart.config, newOptions); + newOptions = mergeConfig(defaults, defaults[chart.config.type], newOptions); + chart.options = chart.config.options = newOptions; + chart.options.scales = scaleConfig; + chart._animationsDisabled = isAnimationDisabled(newOptions); +} +var KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea']; +function positionIsHorizontal(position, axis) { + return position === 'top' || position === 'bottom' || KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x'; +} +function axisFromPosition(position) { + if (position === 'top' || position === 'bottom') { + return 'x'; + } + if (position === 'left' || position === 'right') { + return 'y'; + } +} +function determineAxis(id, scaleOptions) { + if (id === 'x' || id === 'y' || id === 'r') { + return id; + } + return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase(); +} +function compare2Level(l1, l2) { + return function (a, b) { + return a[l1] === b[l1] ? a[l2] - b[l2] : a[l1] - b[l1]; + }; +} +function onAnimationsComplete(context) { + var chart = context.chart; + var animationOptions = chart.options.animation; + chart._plugins.notify(chart, 'afterRender'); + callback(animationOptions && animationOptions.onComplete, [context], chart); +} +function onAnimationProgress(context) { + var chart = context.chart; + var animationOptions = chart.options.animation; + callback(animationOptions && animationOptions.onProgress, [context], chart); +} +function isDomSupported() { + return typeof window !== 'undefined' && typeof document !== 'undefined'; +} +function getCanvas(item) { + if (isDomSupported() && typeof item === 'string') { + item = document.getElementById(item); + } else if (item && item.length) { + item = item[0]; + } + if (item && item.canvas) { + item = item.canvas; + } + return item; +} +var Chart = function () { + function Chart(item, config) { + var me = this; + config = initConfig(config); + var initialCanvas = getCanvas(item); + this.platform = me._initializePlatform(initialCanvas, config); + var context = me.platform.acquireContext(initialCanvas, config); + var canvas = context && context.canvas; + var height = canvas && canvas.height; + var width = canvas && canvas.width; + this.id = uid(); + this.ctx = context; + this.canvas = canvas; + this.config = config; + this.width = width; + this.height = height; + this.aspectRatio = height ? width / height : null; + this.options = config.options; + this._bufferedRender = false; + this._layers = []; + this._metasets = []; + this.boxes = []; + this.currentDevicePixelRatio = undefined; + this.chartArea = undefined; + this.data = undefined; + this._active = []; + this._lastEvent = undefined; + this._listeners = {}; + this._sortedMetasets = []; + this._updating = false; + this.scales = {}; + this.scale = undefined; + this._plugins = new PluginService(); + this.$proxies = {}; + this._hiddenIndices = {}; + this.attached = false; + Chart.instances[me.id] = me; + Object.defineProperty(me, 'data', { + get: function get() { + return me.config.data; + }, + set: function set(value) { + me.config.data = value; + } + }); + if (!context || !canvas) { + console.error("Failed to create chart: can't acquire context from the given item"); + return; + } + animator.listen(me, 'complete', onAnimationsComplete); + animator.listen(me, 'progress', onAnimationProgress); + me._initialize(); + if (me.attached) { + me.update(); + } + } + var _proto = Chart.prototype; + _proto._initialize = function _initialize() { + var me = this; + me._plugins.notify(me, 'beforeInit'); + if (me.options.responsive) { + me.resize(true); + } else { + retinaScale(me, me.options.devicePixelRatio); + } + me.bindEvents(); + me._plugins.notify(me, 'afterInit'); + return me; + } + ; + _proto._initializePlatform = function _initializePlatform(canvas, config) { + if (config.platform) { + return new config.platform(); + } else if (!isDomSupported() || typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas) { + return new BasicPlatform(); + } + return new DomPlatform(); + }; + _proto.clear = function clear$1() { + clear(this); + return this; + }; + _proto.stop = function stop() { + animator.stop(this); + return this; + }; + _proto.resize = function resize(silent, width, height) { + var me = this; + var options = me.options; + var canvas = me.canvas; + var aspectRatio = options.maintainAspectRatio && me.aspectRatio; + var newSize = me.platform.getMaximumSize(canvas, width, height, aspectRatio); + var oldRatio = me.currentDevicePixelRatio; + var newRatio = options.devicePixelRatio || me.platform.getDevicePixelRatio(); + if (me.width === newSize.width && me.height === newSize.height && oldRatio === newRatio) { + return; + } + canvas.width = me.width = newSize.width; + canvas.height = me.height = newSize.height; + if (canvas.style) { + canvas.style.width = newSize.width + 'px'; + canvas.style.height = newSize.height + 'px'; + } + retinaScale(me, newRatio); + if (!silent) { + me._plugins.notify(me, 'resize', [newSize]); + callback(options.onResize, [newSize], me); + if (me.attached) { + me.update('resize'); + } + } + }; + _proto.ensureScalesHaveIDs = function ensureScalesHaveIDs() { + var options = this.options; + var scalesOptions = options.scales || {}; + var scaleOptions = options.scale; + each(scalesOptions, function (axisOptions, axisID) { + axisOptions.id = axisID; + }); + if (scaleOptions) { + scaleOptions.id = scaleOptions.id || 'scale'; + } + } + ; + _proto.buildOrUpdateScales = function buildOrUpdateScales() { + var me = this; + var options = me.options; + var scaleOpts = options.scales; + var scales = me.scales || {}; + var updated = Object.keys(scales).reduce(function (obj, id) { + obj[id] = false; + return obj; + }, {}); + var items = []; + if (scaleOpts) { + items = items.concat(Object.keys(scaleOpts).map(function (id) { + var scaleOptions = scaleOpts[id]; + var axis = determineAxis(id, scaleOptions); + var isRadial = axis === 'r'; + var isHorizontal = axis === 'x'; + return { + options: scaleOptions, + dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left', + dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear' + }; + })); + } + each(items, function (item) { + var scaleOptions = item.options; + var id = scaleOptions.id; + var axis = determineAxis(id, scaleOptions); + var scaleType = valueOrDefault(scaleOptions.type, item.dtype); + if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) { + scaleOptions.position = item.dposition; + } + updated[id] = true; + var scale = null; + if (id in scales && scales[id].type === scaleType) { + scale = scales[id]; + } else { + var scaleClass = registry.getScale(scaleType); + scale = new scaleClass({ + id: id, + type: scaleType, + ctx: me.ctx, + chart: me + }); + scales[scale.id] = scale; + } + scale.init(scaleOptions, options); + if (item.isDefault) { + me.scale = scale; + } + }); + each(updated, function (hasUpdated, id) { + if (!hasUpdated) { + delete scales[id]; + } + }); + me.scales = scales; + each(scales, function (scale) { + scale.fullWidth = scale.options.fullWidth; + scale.position = scale.options.position; + scale.weight = scale.options.weight; + layouts.addBox(me, scale); + }); + } + ; + _proto._updateMetasetIndex = function _updateMetasetIndex(meta, index) { + var metasets = this._metasets; + var oldIndex = meta.index; + if (oldIndex !== index) { + metasets[oldIndex] = metasets[index]; + metasets[index] = meta; + meta.index = index; + } + } + ; + _proto._updateMetasets = function _updateMetasets() { + var me = this; + var metasets = me._metasets; + var numData = me.data.datasets.length; + var numMeta = metasets.length; + if (numMeta > numData) { + for (var i = numData; i < numMeta; ++i) { + me._destroyDatasetMeta(i); + } + metasets.splice(numData, numMeta - numData); + } + me._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index')); + }; + _proto.buildOrUpdateControllers = function buildOrUpdateControllers() { + var me = this; + var newControllers = []; + var datasets = me.data.datasets; + var i, ilen; + for (i = 0, ilen = datasets.length; i < ilen; i++) { + var dataset = datasets[i]; + var meta = me.getDatasetMeta(i); + var type = dataset.type || me.config.type; + if (meta.type && meta.type !== type) { + me._destroyDatasetMeta(i); + meta = me.getDatasetMeta(i); + } + meta.type = type; + meta.indexAxis = dataset.indexAxis || getIndexAxis(type, me.options); + meta.order = dataset.order || 0; + me._updateMetasetIndex(meta, i); + meta.label = '' + dataset.label; + meta.visible = me.isDatasetVisible(i); + if (meta.controller) { + meta.controller.updateIndex(i); + meta.controller.linkScales(); + } else { + var controllerDefaults = defaults[type]; + var ControllerClass = registry.getController(type); + _extends(ControllerClass.prototype, { + dataElementType: registry.getElement(controllerDefaults.dataElementType), + datasetElementType: controllerDefaults.datasetElementType && registry.getElement(controllerDefaults.datasetElementType), + dataElementOptions: controllerDefaults.dataElementOptions, + datasetElementOptions: controllerDefaults.datasetElementOptions + }); + meta.controller = new ControllerClass(me, i); + newControllers.push(meta.controller); + } + } + me._updateMetasets(); + return newControllers; + } + ; + _proto._resetElements = function _resetElements() { + var me = this; + each(me.data.datasets, function (dataset, datasetIndex) { + me.getDatasetMeta(datasetIndex).controller.reset(); + }, me); + } + ; + _proto.reset = function reset() { + this._resetElements(); + this._plugins.notify(this, 'reset'); + }; + _proto.update = function update(mode) { + var me = this; + var i, ilen; + me._updating = true; + updateConfig(me); + me.ensureScalesHaveIDs(); + me.buildOrUpdateScales(); + me._plugins.invalidate(); + if (me._plugins.notify(me, 'beforeUpdate') === false) { + return; + } + var newControllers = me.buildOrUpdateControllers(); + for (i = 0, ilen = me.data.datasets.length; i < ilen; i++) { + me.getDatasetMeta(i).controller.buildOrUpdateElements(); + } + me._updateLayout(); + each(newControllers, function (controller) { + controller.reset(); + }); + me._updateDatasets(mode); + me._plugins.notify(me, 'afterUpdate'); + me._layers.sort(compare2Level('z', '_idx')); + if (me._lastEvent) { + me._eventHandler(me._lastEvent, true); + } + me.render(); + me._updating = false; + } + ; + _proto._updateLayout = function _updateLayout() { + var me = this; + if (me._plugins.notify(me, 'beforeLayout') === false) { + return; + } + layouts.update(me, me.width, me.height); + me._layers = []; + each(me.boxes, function (box) { + var _me$_layers; + if (box.configure) { + box.configure(); + } + (_me$_layers = me._layers).push.apply(_me$_layers, box._layers()); + }, me); + me._layers.forEach(function (item, index) { + item._idx = index; + }); + me._plugins.notify(me, 'afterLayout'); + } + ; + _proto._updateDatasets = function _updateDatasets(mode) { + var me = this; + var isFunction = typeof mode === 'function'; + if (me._plugins.notify(me, 'beforeDatasetsUpdate') === false) { + return; + } + for (var i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me._updateDataset(i, isFunction ? mode({ + datasetIndex: i + }) : mode); + } + me._plugins.notify(me, 'afterDatasetsUpdate'); + } + ; + _proto._updateDataset = function _updateDataset(index, mode) { + var me = this; + var meta = me.getDatasetMeta(index); + var args = { + meta: meta, + index: index, + mode: mode + }; + if (me._plugins.notify(me, 'beforeDatasetUpdate', [args]) === false) { + return; + } + meta.controller._update(mode); + me._plugins.notify(me, 'afterDatasetUpdate', [args]); + }; + _proto.render = function render() { + var me = this; + if (me._plugins.notify(me, 'beforeRender') === false) { + return; + } + if (animator.has(me)) { + if (me.attached && !animator.running(me)) { + animator.start(me); + } + } else { + me.draw(); + onAnimationsComplete({ + chart: me + }); + } + }; + _proto.draw = function draw() { + var me = this; + var i; + me.clear(); + if (me.width <= 0 || me.height <= 0) { + return; + } + if (me._plugins.notify(me, 'beforeDraw') === false) { + return; + } + var layers = me._layers; + for (i = 0; i < layers.length && layers[i].z <= 0; ++i) { + layers[i].draw(me.chartArea); + } + me._drawDatasets(); + for (; i < layers.length; ++i) { + layers[i].draw(me.chartArea); + } + me._plugins.notify(me, 'afterDraw'); + } + ; + _proto._getSortedDatasetMetas = function _getSortedDatasetMetas(filterVisible) { + var me = this; + var metasets = me._sortedMetasets; + var result = []; + var i, ilen; + for (i = 0, ilen = metasets.length; i < ilen; ++i) { + var meta = metasets[i]; + if (!filterVisible || meta.visible) { + result.push(meta); + } + } + return result; + } + ; + _proto.getSortedVisibleDatasetMetas = function getSortedVisibleDatasetMetas() { + return this._getSortedDatasetMetas(true); + } + ; + _proto._drawDatasets = function _drawDatasets() { + var me = this; + if (me._plugins.notify(me, 'beforeDatasetsDraw') === false) { + return; + } + var metasets = me.getSortedVisibleDatasetMetas(); + for (var i = metasets.length - 1; i >= 0; --i) { + me._drawDataset(metasets[i]); + } + me._plugins.notify(me, 'afterDatasetsDraw'); + } + ; + _proto._drawDataset = function _drawDataset(meta) { + var me = this; + var ctx = me.ctx; + var clip = meta._clip; + var area = me.chartArea; + var args = { + meta: meta, + index: meta.index + }; + if (me._plugins.notify(me, 'beforeDatasetDraw', [args]) === false) { + return; + } + clipArea(ctx, { + left: clip.left === false ? 0 : area.left - clip.left, + right: clip.right === false ? me.width : area.right + clip.right, + top: clip.top === false ? 0 : area.top - clip.top, + bottom: clip.bottom === false ? me.height : area.bottom + clip.bottom + }); + meta.controller.draw(); + unclipArea(ctx); + me._plugins.notify(me, 'afterDatasetDraw', [args]); + } + ; + _proto.getElementAtEvent = function getElementAtEvent(e) { + return Interaction.modes.nearest(this, e, { + intersect: true + }); + }; + _proto.getElementsAtEvent = function getElementsAtEvent(e) { + return Interaction.modes.index(this, e, { + intersect: true + }); + }; + _proto.getElementsAtXAxis = function getElementsAtXAxis(e) { + return Interaction.modes.index(this, e, { + intersect: false + }); + }; + _proto.getElementsAtEventForMode = function getElementsAtEventForMode(e, mode, options, useFinalPosition) { + var method = Interaction.modes[mode]; + if (typeof method === 'function') { + return method(this, e, options, useFinalPosition); + } + return []; + }; + _proto.getDatasetAtEvent = function getDatasetAtEvent(e) { + return Interaction.modes.dataset(this, e, { + intersect: true + }); + }; + _proto.getDatasetMeta = function getDatasetMeta(datasetIndex) { + var me = this; + var dataset = me.data.datasets[datasetIndex]; + var metasets = me._metasets; + var meta = metasets.filter(function (x) { + return x._dataset === dataset; + }).pop(); + if (!meta) { + meta = metasets[datasetIndex] = { + type: null, + data: [], + dataset: null, + controller: null, + hidden: null, + xAxisID: null, + yAxisID: null, + order: dataset.order || 0, + index: datasetIndex, + _dataset: dataset, + _parsed: [], + _sorted: false + }; + } + return meta; + }; + _proto.getVisibleDatasetCount = function getVisibleDatasetCount() { + return this.getSortedVisibleDatasetMetas().length; + }; + _proto.isDatasetVisible = function isDatasetVisible(datasetIndex) { + var meta = this.getDatasetMeta(datasetIndex); + return typeof meta.hidden === 'boolean' ? !meta.hidden : !this.data.datasets[datasetIndex].hidden; + }; + _proto.setDatasetVisibility = function setDatasetVisibility(datasetIndex, visible) { + var meta = this.getDatasetMeta(datasetIndex); + meta.hidden = !visible; + }; + _proto.toggleDataVisibility = function toggleDataVisibility(index) { + this._hiddenIndices[index] = !this._hiddenIndices[index]; + }; + _proto.getDataVisibility = function getDataVisibility(index) { + return !this._hiddenIndices[index]; + } + ; + _proto._updateDatasetVisibility = function _updateDatasetVisibility(datasetIndex, visible) { + var me = this; + var mode = visible ? 'show' : 'hide'; + var meta = me.getDatasetMeta(datasetIndex); + var anims = meta.controller._resolveAnimations(undefined, mode); + me.setDatasetVisibility(datasetIndex, visible); + anims.update(meta, { + visible: visible + }); + me.update(function (ctx) { + return ctx.datasetIndex === datasetIndex ? mode : undefined; + }); + }; + _proto.hide = function hide(datasetIndex) { + this._updateDatasetVisibility(datasetIndex, false); + }; + _proto.show = function show(datasetIndex) { + this._updateDatasetVisibility(datasetIndex, true); + } + ; + _proto._destroyDatasetMeta = function _destroyDatasetMeta(datasetIndex) { + var me = this; + var meta = me._metasets && me._metasets[datasetIndex]; + if (meta) { + meta.controller._destroy(); + delete me._metasets[datasetIndex]; + } + }; + _proto.destroy = function destroy() { + var me = this; + var canvas = me.canvas; + var i, ilen; + me.stop(); + animator.remove(me); + for (i = 0, ilen = me.data.datasets.length; i < ilen; ++i) { + me._destroyDatasetMeta(i); + } + if (canvas) { + me.unbindEvents(); + clear(me); + me.platform.releaseContext(me.ctx); + me.canvas = null; + me.ctx = null; + } + me._plugins.notify(me, 'destroy'); + delete Chart.instances[me.id]; + }; + _proto.toBase64Image = function toBase64Image() { + var _this$canvas; + return (_this$canvas = this.canvas).toDataURL.apply(_this$canvas, arguments); + } + ; + _proto.bindEvents = function bindEvents() { + var me = this; + var listeners = me._listeners; + var platform = me.platform; + var _add = function _add(type, listener) { + platform.addEventListener(me, type, listener); + listeners[type] = listener; + }; + var _remove = function _remove(type, listener) { + if (listeners[type]) { + platform.removeEventListener(me, type, listener); + delete listeners[type]; + } + }; + var listener = function listener(e, x, y) { + e.offsetX = x; + e.offsetY = y; + me._eventHandler(e); + }; + each(me.options.events, function (type) { + return _add(type, listener); + }); + if (me.options.responsive) { + listener = function listener(width, height) { + if (me.canvas) { + me.resize(false, width, height); + } + }; + var detached; + var attached = function attached() { + _remove('attach', attached); + me.attached = true; + me.resize(); + _add('resize', listener); + _add('detach', detached); + }; + detached = function detached() { + me.attached = false; + _remove('resize', listener); + _add('attach', attached); + }; + if (platform.isAttached(me.canvas)) { + attached(); + } else { + detached(); + } + } else { + me.attached = true; + } + } + ; + _proto.unbindEvents = function unbindEvents() { + var me = this; + var listeners = me._listeners; + if (!listeners) { + return; + } + delete me._listeners; + each(listeners, function (listener, type) { + me.platform.removeEventListener(me, type, listener); + }); + }; + _proto.updateHoverStyle = function updateHoverStyle(items, mode, enabled) { + var prefix = enabled ? 'set' : 'remove'; + var meta, item, i, ilen; + if (mode === 'dataset') { + meta = this.getDatasetMeta(items[0].datasetIndex); + meta.controller['_' + prefix + 'DatasetHoverStyle'](); + } + for (i = 0, ilen = items.length; i < ilen; ++i) { + item = items[i]; + if (item) { + this.getDatasetMeta(item.datasetIndex).controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index); + } + } + } + ; + _proto._updateHoverStyles = function _updateHoverStyles(active, lastActive) { + var me = this; + var options = me.options || {}; + var hoverOptions = options.hover; + if (lastActive.length) { + me.updateHoverStyle(lastActive, hoverOptions.mode, false); + } + if (active.length && hoverOptions.mode) { + me.updateHoverStyle(active, hoverOptions.mode, true); + } + } + ; + _proto._eventHandler = function _eventHandler(e, replay) { + var me = this; + if (me._plugins.notify(me, 'beforeEvent', [e, replay]) === false) { + return; + } + me._handleEvent(e, replay); + me._plugins.notify(me, 'afterEvent', [e, replay]); + me.render(); + return me; + } + ; + _proto._handleEvent = function _handleEvent(e, replay) { + var me = this; + var lastActive = me._active || []; + var options = me.options; + var hoverOptions = options.hover; + var useFinalPosition = replay; + var active = []; + var changed = false; + if (e.type === 'mouseout') { + me._lastEvent = null; + } else { + active = me.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition); + me._lastEvent = e.type === 'click' ? me._lastEvent : e; + } + callback(options.onHover || options.hover.onHover, [e, active, me], me); + if (e.type === 'mouseup' || e.type === 'click') { + if (_isPointInArea(e, me.chartArea)) { + callback(options.onClick, [e, active, me], me); + } + } + changed = !_elementsEqual(active, lastActive); + if (changed || replay) { + me._active = active; + me._updateHoverStyles(active, lastActive); + } + return changed; + }; + return Chart; +}(); +Chart.defaults = defaults; +Chart.instances = {}; +Chart.registry = registry; +Chart.version = version; +var invalidatePlugins = function invalidatePlugins() { + return each(Chart.instances, function (chart) { + return chart._plugins.invalidate(); + }); +}; +Chart.register = function () { + registry.add.apply(registry, arguments); + invalidatePlugins(); +}; +Chart.unregister = function () { + registry.remove.apply(registry, arguments); + invalidatePlugins(); +}; + +var EPSILON = Number.EPSILON || 1e-14; +function splineCurve(firstPoint, middlePoint, afterPoint, t) { + var previous = firstPoint.skip ? middlePoint : firstPoint; + var current = middlePoint; + var next = afterPoint.skip ? middlePoint : afterPoint; + var d01 = Math.sqrt(Math.pow(current.x - previous.x, 2) + Math.pow(current.y - previous.y, 2)); + var d12 = Math.sqrt(Math.pow(next.x - current.x, 2) + Math.pow(next.y - current.y, 2)); + var s01 = d01 / (d01 + d12); + var s12 = d12 / (d01 + d12); + s01 = isNaN(s01) ? 0 : s01; + s12 = isNaN(s12) ? 0 : s12; + var fa = t * s01; + var fb = t * s12; + return { + previous: { + x: current.x - fa * (next.x - previous.x), + y: current.y - fa * (next.y - previous.y) + }, + next: { + x: current.x + fb * (next.x - previous.x), + y: current.y + fb * (next.y - previous.y) + } + }; +} +function splineCurveMonotone(points) { + var pointsWithTangents = (points || []).map(function (point) { + return { + model: point, + deltaK: 0, + mK: 0 + }; + }); + var pointsLen = pointsWithTangents.length; + var i, pointBefore, pointCurrent, pointAfter; + for (i = 0; i < pointsLen; ++i) { + pointCurrent = pointsWithTangents[i]; + if (pointCurrent.model.skip) { + continue; + } + pointBefore = i > 0 ? pointsWithTangents[i - 1] : null; + pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null; + if (pointAfter && !pointAfter.model.skip) { + var slopeDeltaX = pointAfter.model.x - pointCurrent.model.x; + pointCurrent.deltaK = slopeDeltaX !== 0 ? (pointAfter.model.y - pointCurrent.model.y) / slopeDeltaX : 0; + } + if (!pointBefore || pointBefore.model.skip) { + pointCurrent.mK = pointCurrent.deltaK; + } else if (!pointAfter || pointAfter.model.skip) { + pointCurrent.mK = pointBefore.deltaK; + } else if (sign(pointBefore.deltaK) !== sign(pointCurrent.deltaK)) { + pointCurrent.mK = 0; + } else { + pointCurrent.mK = (pointBefore.deltaK + pointCurrent.deltaK) / 2; + } + } + var alphaK, betaK, tauK, squaredMagnitude; + for (i = 0; i < pointsLen - 1; ++i) { + pointCurrent = pointsWithTangents[i]; + pointAfter = pointsWithTangents[i + 1]; + if (pointCurrent.model.skip || pointAfter.model.skip) { + continue; + } + if (almostEquals(pointCurrent.deltaK, 0, EPSILON)) { + pointCurrent.mK = pointAfter.mK = 0; + continue; + } + alphaK = pointCurrent.mK / pointCurrent.deltaK; + betaK = pointAfter.mK / pointCurrent.deltaK; + squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2); + if (squaredMagnitude <= 9) { + continue; + } + tauK = 3 / Math.sqrt(squaredMagnitude); + pointCurrent.mK = alphaK * tauK * pointCurrent.deltaK; + pointAfter.mK = betaK * tauK * pointCurrent.deltaK; + } + var deltaX; + for (i = 0; i < pointsLen; ++i) { + pointCurrent = pointsWithTangents[i]; + if (pointCurrent.model.skip) { + continue; + } + pointBefore = i > 0 ? pointsWithTangents[i - 1] : null; + pointAfter = i < pointsLen - 1 ? pointsWithTangents[i + 1] : null; + if (pointBefore && !pointBefore.model.skip) { + deltaX = (pointCurrent.model.x - pointBefore.model.x) / 3; + pointCurrent.model.controlPointPreviousX = pointCurrent.model.x - deltaX; + pointCurrent.model.controlPointPreviousY = pointCurrent.model.y - deltaX * pointCurrent.mK; + } + if (pointAfter && !pointAfter.model.skip) { + deltaX = (pointAfter.model.x - pointCurrent.model.x) / 3; + pointCurrent.model.controlPointNextX = pointCurrent.model.x + deltaX; + pointCurrent.model.controlPointNextY = pointCurrent.model.y + deltaX * pointCurrent.mK; + } + } +} +function capControlPoint(pt, min, max) { + return Math.max(Math.min(pt, max), min); +} +function capBezierPoints(points, area) { + var i, ilen, point; + for (i = 0, ilen = points.length; i < ilen; ++i) { + point = points[i]; + if (!_isPointInArea(point, area)) { + continue; + } + if (i > 0 && _isPointInArea(points[i - 1], area)) { + point.controlPointPreviousX = capControlPoint(point.controlPointPreviousX, area.left, area.right); + point.controlPointPreviousY = capControlPoint(point.controlPointPreviousY, area.top, area.bottom); + } + if (i < points.length - 1 && _isPointInArea(points[i + 1], area)) { + point.controlPointNextX = capControlPoint(point.controlPointNextX, area.left, area.right); + point.controlPointNextY = capControlPoint(point.controlPointNextY, area.top, area.bottom); + } + } +} +function _updateBezierControlPoints(points, options, area, loop) { + var i, ilen, point, controlPoints; + if (options.spanGaps) { + points = points.filter(function (pt) { + return !pt.skip; + }); + } + if (options.cubicInterpolationMode === 'monotone') { + splineCurveMonotone(points); + } else { + var prev = loop ? points[points.length - 1] : points[0]; + for (i = 0, ilen = points.length; i < ilen; ++i) { + point = points[i]; + controlPoints = splineCurve(prev, point, points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen], options.tension); + point.controlPointPreviousX = controlPoints.previous.x; + point.controlPointPreviousY = controlPoints.previous.y; + point.controlPointNextX = controlPoints.next.x; + point.controlPointNextY = controlPoints.next.y; + prev = point; + } + } + if (options.capBezierPoints) { + capBezierPoints(points, area); + } +} + +function _pointInLine(p1, p2, t, mode) { + return { + x: p1.x + t * (p2.x - p1.x), + y: p1.y + t * (p2.y - p1.y) + }; +} +function _steppedInterpolation(p1, p2, t, mode) { + return { + x: p1.x + t * (p2.x - p1.x), + y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y : mode === 'after' ? t < 1 ? p1.y : p2.y : t > 0 ? p2.y : p1.y + }; +} +function _bezierInterpolation(p1, p2, t, mode) { + var cp1 = { + x: p1.controlPointNextX, + y: p1.controlPointNextY + }; + var cp2 = { + x: p2.controlPointPreviousX, + y: p2.controlPointPreviousY + }; + var a = _pointInLine(p1, cp1, t); + var b = _pointInLine(cp1, cp2, t); + var c = _pointInLine(cp2, p2, t); + var d = _pointInLine(a, b, t); + var e = _pointInLine(b, c, t); + return _pointInLine(d, e, t); +} + +var getRightToLeftAdapter = function getRightToLeftAdapter(rectX, width) { + return { + x: function x(_x) { + return rectX + rectX + width - _x; + }, + setWidth: function setWidth(w) { + width = w; + }, + textAlign: function textAlign(align) { + if (align === 'center') { + return align; + } + return align === 'right' ? 'left' : 'right'; + }, + xPlus: function xPlus(x, value) { + return x - value; + }, + leftForLtr: function leftForLtr(x, itemWidth) { + return x - itemWidth; + } + }; +}; +var getLeftToRightAdapter = function getLeftToRightAdapter() { + return { + x: function x(_x2) { + return _x2; + }, + setWidth: function setWidth(w) { + }, + textAlign: function textAlign(align) { + return align; + }, + xPlus: function xPlus(x, value) { + return x + value; + }, + leftForLtr: function leftForLtr(x, _itemWidth) { + return x; + } + }; +}; +function getRtlAdapter(rtl, rectX, width) { + return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter(); +} +function overrideTextDirection(ctx, direction) { + var style, original; + if (direction === 'ltr' || direction === 'rtl') { + style = ctx.canvas.style; + original = [style.getPropertyValue('direction'), style.getPropertyPriority('direction')]; + style.setProperty('direction', direction, 'important'); + ctx.prevTextDirection = original; + } +} +function restoreTextDirection(ctx, original) { + if (original !== undefined) { + delete ctx.prevTextDirection; + ctx.canvas.style.setProperty('direction', original[0], original[1]); + } +} + +function propertyFn(property) { + if (property === 'angle') { + return { + between: _angleBetween, + compare: _angleDiff, + normalize: _normalizeAngle + }; + } + return { + between: function between(n, s, e) { + return n >= s && n <= e; + }, + compare: function compare(a, b) { + return a - b; + }, + normalize: function normalize(x) { + return x; + } + }; +} +function makeSubSegment(start, end, loop, count) { + return { + start: start % count, + end: end % count, + loop: loop && (end - start + 1) % count === 0 + }; +} +function getSegment(segment, points, bounds) { + var property = bounds.property, + startBound = bounds.start, + endBound = bounds.end; + var _propertyFn = propertyFn(property), + between = _propertyFn.between, + normalize = _propertyFn.normalize; + var count = points.length; + var start = segment.start, + end = segment.end, + loop = segment.loop; + var i, ilen; + if (loop) { + start += count; + end += count; + for (i = 0, ilen = count; i < ilen; ++i) { + if (!between(normalize(points[start % count][property]), startBound, endBound)) { + break; + } + start--; + end--; + } + start %= count; + end %= count; + } + if (end < start) { + end += count; + } + return { + start: start, + end: end, + loop: loop + }; +} +function _boundSegment(segment, points, bounds) { + if (!bounds) { + return [segment]; + } + var property = bounds.property, + startBound = bounds.start, + endBound = bounds.end; + var count = points.length; + var _propertyFn2 = propertyFn(property), + compare = _propertyFn2.compare, + between = _propertyFn2.between, + normalize = _propertyFn2.normalize; + var _getSegment = getSegment(segment, points, bounds), + start = _getSegment.start, + end = _getSegment.end, + loop = _getSegment.loop; + var result = []; + var inside = false; + var subStart = null; + var value, point, prevValue; + var startIsBefore = function startIsBefore() { + return between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0; + }; + var endIsBefore = function endIsBefore() { + return compare(endBound, value) === 0 || between(endBound, prevValue, value); + }; + var shouldStart = function shouldStart() { + return inside || startIsBefore(); + }; + var shouldStop = function shouldStop() { + return !inside || endIsBefore(); + }; + for (var i = start, prev = start; i <= end; ++i) { + point = points[i % count]; + if (point.skip) { + continue; + } + value = normalize(point[property]); + inside = between(value, startBound, endBound); + if (subStart === null && shouldStart()) { + subStart = compare(value, startBound) === 0 ? i : prev; + } + if (subStart !== null && shouldStop()) { + result.push(makeSubSegment(subStart, i, loop, count)); + subStart = null; + } + prev = i; + prevValue = value; + } + if (subStart !== null) { + result.push(makeSubSegment(subStart, end, loop, count)); + } + return result; +} +function _boundSegments(line, bounds) { + var result = []; + var segments = line.segments; + for (var i = 0; i < segments.length; i++) { + var sub = _boundSegment(segments[i], line.points, bounds); + if (sub.length) { + result.push.apply(result, sub); + } + } + return result; +} +function findStartAndEnd(points, count, loop, spanGaps) { + var start = 0; + var end = count - 1; + if (loop && !spanGaps) { + while (start < count && !points[start].skip) { + start++; + } + } + while (start < count && points[start].skip) { + start++; + } + start %= count; + if (loop) { + end += start; + } + while (end > start && points[end % count].skip) { + end--; + } + end %= count; + return { + start: start, + end: end + }; +} +function solidSegments(points, start, max, loop) { + var count = points.length; + var result = []; + var last = start; + var prev = points[start]; + var end; + for (end = start + 1; end <= max; ++end) { + var cur = points[end % count]; + if (cur.skip || cur.stop) { + if (!prev.skip) { + loop = false; + result.push({ + start: start % count, + end: (end - 1) % count, + loop: loop + }); + start = last = cur.stop ? end : null; + } + } else { + last = end; + if (prev.skip) { + start = end; + } + } + prev = cur; + } + if (last !== null) { + result.push({ + start: start % count, + end: last % count, + loop: loop + }); + } + return result; +} +function _computeSegments(line) { + var points = line.points; + var spanGaps = line.options.spanGaps; + var count = points.length; + if (!count) { + return []; + } + var loop = !!line._loop; + var _findStartAndEnd = findStartAndEnd(points, count, loop, spanGaps), + start = _findStartAndEnd.start, + end = _findStartAndEnd.end; + if (spanGaps === true) { + return [{ + start: start, + end: end, + loop: loop + }]; + } + var max = end < start ? end + count : end; + var completeLoop = !!line._fullLoop && start === 0 && end === count - 1; + return solidSegments(points, start, max, completeLoop); +} + +var helpers = /*#__PURE__*/Object.freeze({ +__proto__: null, +easingEffects: effects, +color: color, +getHoverColor: getHoverColor, +requestAnimFrame: requestAnimFrame, +fontString: fontString, +noop: noop, +uid: uid, +isNullOrUndef: isNullOrUndef, +isArray: isArray, +isObject: isObject, +isFinite: isNumberFinite, +valueOrDefault: valueOrDefault, +callback: callback, +each: each, +_elementsEqual: _elementsEqual, +clone: clone, +_merger: _merger, +merge: merge, +mergeIf: mergeIf, +_mergerIf: _mergerIf, +_deprecated: _deprecated, +resolveObjectKey: resolveObjectKey, +_capitalize: _capitalize, +toFontString: toFontString, +_measureText: _measureText, +_longestText: _longestText, +_alignPixel: _alignPixel, +clear: clear, +drawPoint: drawPoint, +_isPointInArea: _isPointInArea, +clipArea: clipArea, +unclipArea: unclipArea, +_steppedLineTo: _steppedLineTo, +_bezierCurveTo: _bezierCurveTo, +_lookup: _lookup, +_lookupByKey: _lookupByKey, +_rlookupByKey: _rlookupByKey, +_filterBetween: _filterBetween, +listenArrayEvents: listenArrayEvents, +unlistenArrayEvents: unlistenArrayEvents, +_arrayUnique: _arrayUnique, +splineCurve: splineCurve, +splineCurveMonotone: splineCurveMonotone, +_updateBezierControlPoints: _updateBezierControlPoints, +_getParentNode: _getParentNode, +getStyle: getStyle, +getRelativePosition: getRelativePosition, +getMaximumSize: getMaximumSize, +retinaScale: retinaScale, +supportsEventListenerOptions: supportsEventListenerOptions, +readUsedSize: readUsedSize, +_pointInLine: _pointInLine, +_steppedInterpolation: _steppedInterpolation, +_bezierInterpolation: _bezierInterpolation, +toLineHeight: toLineHeight, +toTRBL: toTRBL, +toPadding: toPadding, +toFont: toFont, +resolve: resolve, +_factorize: _factorize, +log10: log10, +isNumber: isNumber, +almostEquals: almostEquals, +almostWhole: almostWhole, +_setMinAndMaxByKey: _setMinAndMaxByKey, +sign: sign, +toRadians: toRadians, +toDegrees: toDegrees, +_decimalPlaces: _decimalPlaces, +getAngleFromPoint: getAngleFromPoint, +distanceBetweenPoints: distanceBetweenPoints, +_angleDiff: _angleDiff, +_normalizeAngle: _normalizeAngle, +_angleBetween: _angleBetween, +_limitValue: _limitValue, +_int32Range: _int32Range, +getRtlAdapter: getRtlAdapter, +overrideTextDirection: overrideTextDirection, +restoreTextDirection: restoreTextDirection, +_boundSegment: _boundSegment, +_boundSegments: _boundSegments, +_computeSegments: _computeSegments +}); + +function _abstract() { + throw new Error('This method is not implemented: either no adapter can be found or an incomplete integration was provided.'); +} +var DateAdapter = function () { + function DateAdapter(options) { + this.options = options || {}; + } + var _proto = DateAdapter.prototype; + _proto.formats = function formats() { + return _abstract(); + } + ; + _proto.parse = function parse(value, format) { + return _abstract(); + } + ; + _proto.format = function format(timestamp, _format) { + return _abstract(); + } + ; + _proto.add = function add(timestamp, amount, unit) { + return _abstract(); + } + ; + _proto.diff = function diff(a, b, unit) { + return _abstract(); + } + ; + _proto.startOf = function startOf(timestamp, unit, weekday) { + return _abstract(); + } + ; + _proto.endOf = function endOf(timestamp, unit) { + return _abstract(); + }; + return DateAdapter; +}(); +DateAdapter.override = function (members) { + _extends(DateAdapter.prototype, members); +}; +var _adapters = { + _date: DateAdapter +}; + +function computeMinSampleSize(scale, pixels) { + var min = scale._length; + var prev, curr, i, ilen; + for (i = 1, ilen = pixels.length; i < ilen; ++i) { + min = Math.min(min, Math.abs(pixels[i] - pixels[i - 1])); + } + for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) { + curr = scale.getPixelForTick(i); + min = i > 0 ? Math.min(min, Math.abs(curr - prev)) : min; + prev = curr; + } + return min; +} +function computeFitCategoryTraits(index, ruler, options) { + var thickness = options.barThickness; + var count = ruler.stackCount; + var size, ratio; + if (isNullOrUndef(thickness)) { + size = ruler.min * options.categoryPercentage; + ratio = options.barPercentage; + } else { + size = thickness * count; + ratio = 1; + } + return { + chunk: size / count, + ratio: ratio, + start: ruler.pixels[index] - size / 2 + }; +} +function computeFlexCategoryTraits(index, ruler, options) { + var pixels = ruler.pixels; + var curr = pixels[index]; + var prev = index > 0 ? pixels[index - 1] : null; + var next = index < pixels.length - 1 ? pixels[index + 1] : null; + var percent = options.categoryPercentage; + if (prev === null) { + prev = curr - (next === null ? ruler.end - ruler.start : next - curr); + } + if (next === null) { + next = curr + curr - prev; + } + var start = curr - (curr - Math.min(prev, next)) / 2 * percent; + var size = Math.abs(next - prev) / 2 * percent; + return { + chunk: size / ruler.stackCount, + ratio: options.barPercentage, + start: start + }; +} +function parseFloatBar(entry, item, vScale, i) { + var startValue = vScale.parse(entry[0], i); + var endValue = vScale.parse(entry[1], i); + var min = Math.min(startValue, endValue); + var max = Math.max(startValue, endValue); + var barStart = min; + var barEnd = max; + if (Math.abs(min) > Math.abs(max)) { + barStart = max; + barEnd = min; + } + item[vScale.axis] = barEnd; + item._custom = { + barStart: barStart, + barEnd: barEnd, + start: startValue, + end: endValue, + min: min, + max: max + }; +} +function parseValue(entry, item, vScale, i) { + if (isArray(entry)) { + parseFloatBar(entry, item, vScale, i); + } else { + item[vScale.axis] = vScale.parse(entry, i); + } + return item; +} +function parseArrayOrPrimitive(meta, data, start, count) { + var iScale = meta.iScale; + var vScale = meta.vScale; + var labels = iScale.getLabels(); + var singleScale = iScale === vScale; + var parsed = []; + var i, ilen, item, entry; + for (i = start, ilen = start + count; i < ilen; ++i) { + entry = data[i]; + item = {}; + item[iScale.axis] = singleScale || iScale.parse(labels[i], i); + parsed.push(parseValue(entry, item, vScale, i)); + } + return parsed; +} +function isFloatBar(custom) { + return custom && custom.barStart !== undefined && custom.barEnd !== undefined; +} +var BarController = function (_DatasetController) { + _inheritsLoose(BarController, _DatasetController); + function BarController() { + return _DatasetController.apply(this, arguments) || this; + } + var _proto = BarController.prototype; + _proto.parsePrimitiveData = function parsePrimitiveData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + ; + _proto.parseArrayData = function parseArrayData(meta, data, start, count) { + return parseArrayOrPrimitive(meta, data, start, count); + } + ; + _proto.parseObjectData = function parseObjectData(meta, data, start, count) { + var iScale = meta.iScale, + vScale = meta.vScale; + var _this$_parsing = this._parsing, + _this$_parsing$xAxisK = _this$_parsing.xAxisKey, + xAxisKey = _this$_parsing$xAxisK === void 0 ? 'x' : _this$_parsing$xAxisK, + _this$_parsing$yAxisK = _this$_parsing.yAxisKey, + yAxisKey = _this$_parsing$yAxisK === void 0 ? 'y' : _this$_parsing$yAxisK; + var iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey; + var vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey; + var parsed = []; + var i, ilen, item, obj; + for (i = start, ilen = start + count; i < ilen; ++i) { + obj = data[i]; + item = {}; + item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i); + parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i)); + } + return parsed; + } + ; + _proto.updateRangeFromParsed = function updateRangeFromParsed(range, scale, parsed, stack) { + _DatasetController.prototype.updateRangeFromParsed.call(this, range, scale, parsed, stack); + var custom = parsed._custom; + if (custom && scale === this._cachedMeta.vScale) { + range.min = Math.min(range.min, custom.min); + range.max = Math.max(range.max, custom.max); + } + } + ; + _proto.getLabelAndValue = function getLabelAndValue(index) { + var me = this; + var meta = me._cachedMeta; + var iScale = meta.iScale, + vScale = meta.vScale; + var parsed = me.getParsed(index); + var custom = parsed._custom; + var value = isFloatBar(custom) ? '[' + custom.start + ', ' + custom.end + ']' : '' + vScale.getLabelForValue(parsed[vScale.axis]); + return { + label: '' + iScale.getLabelForValue(parsed[iScale.axis]), + value: value + }; + }; + _proto.initialize = function initialize() { + var me = this; + me.enableOptionSharing = true; + _DatasetController.prototype.initialize.call(this); + var meta = me._cachedMeta; + meta.stack = me.getDataset().stack; + }; + _proto.update = function update(mode) { + var me = this; + var meta = me._cachedMeta; + me.updateElements(meta.data, 0, meta.data.length, mode); + }; + _proto.updateElements = function updateElements(rectangles, start, count, mode) { + var me = this; + var reset = mode === 'reset'; + var vscale = me._cachedMeta.vScale; + var base = vscale.getBasePixel(); + var horizontal = vscale.isHorizontal(); + var ruler = me._getRuler(); + var firstOpts = me.resolveDataElementOptions(start, mode); + var sharedOptions = me.getSharedOptions(firstOpts); + var includeOptions = me.includeOptions(mode, sharedOptions); + me.updateSharedOptions(sharedOptions, mode, firstOpts); + for (var i = start; i < start + count; i++) { + var options = sharedOptions || me.resolveDataElementOptions(i, mode); + var vpixels = me._calculateBarValuePixels(i, options); + var ipixels = me._calculateBarIndexPixels(i, ruler, options); + var properties = { + horizontal: horizontal, + base: reset ? base : vpixels.base, + x: horizontal ? reset ? base : vpixels.head : ipixels.center, + y: horizontal ? ipixels.center : reset ? base : vpixels.head, + height: horizontal ? ipixels.size : undefined, + width: horizontal ? undefined : ipixels.size + }; + if (includeOptions) { + properties.options = options; + } + me.updateElement(rectangles[i], i, properties, mode); + } + } + ; + _proto._getStacks = function _getStacks(last) { + var me = this; + var meta = me._cachedMeta; + var iScale = meta.iScale; + var metasets = iScale.getMatchingVisibleMetas(me._type); + var stacked = iScale.options.stacked; + var ilen = metasets.length; + var stacks = []; + var i, item; + for (i = 0; i < ilen; ++i) { + item = metasets[i]; + if (stacked === false || stacks.indexOf(item.stack) === -1 || stacked === undefined && item.stack === undefined) { + stacks.push(item.stack); + } + if (item.index === last) { + break; + } + } + if (!stacks.length) { + stacks.push(undefined); + } + return stacks; + } + ; + _proto._getStackCount = function _getStackCount() { + return this._getStacks().length; + } + ; + _proto._getStackIndex = function _getStackIndex(datasetIndex, name) { + var stacks = this._getStacks(datasetIndex); + var index = name !== undefined ? stacks.indexOf(name) : -1; + return index === -1 ? stacks.length - 1 : index; + } + ; + _proto._getRuler = function _getRuler() { + var me = this; + var meta = me._cachedMeta; + var iScale = meta.iScale; + var pixels = []; + var i, ilen; + for (i = 0, ilen = meta.data.length; i < ilen; ++i) { + pixels.push(iScale.getPixelForValue(me.getParsed(i)[iScale.axis], i)); + } + var min = computeMinSampleSize(iScale, pixels); + return { + min: min, + pixels: pixels, + start: iScale._startPixel, + end: iScale._endPixel, + stackCount: me._getStackCount(), + scale: iScale + }; + } + ; + _proto._calculateBarValuePixels = function _calculateBarValuePixels(index, options) { + var me = this; + var meta = me._cachedMeta; + var vScale = meta.vScale; + var minBarLength = options.minBarLength; + var parsed = me.getParsed(index); + var custom = parsed._custom; + var value = parsed[vScale.axis]; + var start = 0; + var length = meta._stacked ? me.applyStack(vScale, parsed) : value; + var head, size; + if (length !== value) { + start = length - value; + length = value; + } + if (isFloatBar(custom)) { + value = custom.barStart; + length = custom.barEnd - custom.barStart; + if (value !== 0 && sign(value) !== sign(custom.barEnd)) { + start = 0; + } + start += value; + } + var base = _limitValue(vScale.getPixelForValue(start), vScale._startPixel - 10, vScale._endPixel + 10); + head = vScale.getPixelForValue(start + length); + size = head - base; + if (minBarLength !== undefined && Math.abs(size) < minBarLength) { + size = size < 0 ? -minBarLength : minBarLength; + if (value === 0) { + base -= size / 2; + } + head = base + size; + } + return { + size: size, + base: base, + head: head, + center: head + size / 2 + }; + } + ; + _proto._calculateBarIndexPixels = function _calculateBarIndexPixels(index, ruler, options) { + var me = this; + var range = options.barThickness === 'flex' ? computeFlexCategoryTraits(index, ruler, options) : computeFitCategoryTraits(index, ruler, options); + var stackIndex = me._getStackIndex(me.index, me._cachedMeta.stack); + var center = range.start + range.chunk * stackIndex + range.chunk / 2; + var size = Math.min(valueOrDefault(options.maxBarThickness, Infinity), range.chunk * range.ratio); + return { + base: center - size / 2, + head: center + size / 2, + center: center, + size: size + }; + }; + _proto.draw = function draw() { + var me = this; + var chart = me.chart; + var meta = me._cachedMeta; + var vScale = meta.vScale; + var rects = meta.data; + var ilen = rects.length; + var i = 0; + clipArea(chart.ctx, chart.chartArea); + for (; i < ilen; ++i) { + if (!isNaN(me.getParsed(i)[vScale.axis])) { + rects[i].draw(me._ctx); + } + } + unclipArea(chart.ctx); + }; + return BarController; +}(DatasetController); +BarController.id = 'bar'; +BarController.defaults = { + datasetElementType: false, + dataElementType: 'rectangle', + dataElementOptions: ['backgroundColor', 'borderColor', 'borderSkipped', 'borderWidth', 'barPercentage', 'barThickness', 'categoryPercentage', 'maxBarThickness', 'minBarLength'], + hover: { + mode: 'index' + }, + datasets: { + categoryPercentage: 0.8, + barPercentage: 0.9, + animation: { + numbers: { + type: 'number', + properties: ['x', 'y', 'base', 'width', 'height'] + } + } + }, + scales: { + _index_: { + type: 'category', + offset: true, + gridLines: { + offsetGridLines: true + } + }, + _value_: { + type: 'linear', + beginAtZero: true + } + } +}; + +var BubbleController = function (_DatasetController) { + _inheritsLoose(BubbleController, _DatasetController); + function BubbleController() { + return _DatasetController.apply(this, arguments) || this; + } + var _proto = BubbleController.prototype; + _proto.initialize = function initialize() { + this.enableOptionSharing = true; + _DatasetController.prototype.initialize.call(this); + } + ; + _proto.parseObjectData = function parseObjectData(meta, data, start, count) { + var xScale = meta.xScale, + yScale = meta.yScale; + var _this$_parsing = this._parsing, + _this$_parsing$xAxisK = _this$_parsing.xAxisKey, + xAxisKey = _this$_parsing$xAxisK === void 0 ? 'x' : _this$_parsing$xAxisK, + _this$_parsing$yAxisK = _this$_parsing.yAxisKey, + yAxisKey = _this$_parsing$yAxisK === void 0 ? 'y' : _this$_parsing$yAxisK; + var parsed = []; + var i, ilen, item; + for (i = start, ilen = start + count; i < ilen; ++i) { + item = data[i]; + parsed.push({ + x: xScale.parse(resolveObjectKey(item, xAxisKey), i), + y: yScale.parse(resolveObjectKey(item, yAxisKey), i), + _custom: item && item.r && +item.r + }); + } + return parsed; + } + ; + _proto.getMaxOverflow = function getMaxOverflow() { + var me = this; + var meta = me._cachedMeta; + var i = (meta.data || []).length - 1; + var max = 0; + for (; i >= 0; --i) { + max = Math.max(max, me.getStyle(i, true).radius); + } + return max > 0 && max; + } + ; + _proto.getLabelAndValue = function getLabelAndValue(index) { + var me = this; + var meta = me._cachedMeta; + var xScale = meta.xScale, + yScale = meta.yScale; + var parsed = me.getParsed(index); + var x = xScale.getLabelForValue(parsed.x); + var y = yScale.getLabelForValue(parsed.y); + var r = parsed._custom; + return { + label: meta.label, + value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')' + }; + }; + _proto.update = function update(mode) { + var me = this; + var points = me._cachedMeta.data; + me.updateElements(points, 0, points.length, mode); + }; + _proto.updateElements = function updateElements(points, start, count, mode) { + var me = this; + var reset = mode === 'reset'; + var _me$_cachedMeta = me._cachedMeta, + xScale = _me$_cachedMeta.xScale, + yScale = _me$_cachedMeta.yScale; + var firstOpts = me.resolveDataElementOptions(start, mode); + var sharedOptions = me.getSharedOptions(firstOpts); + var includeOptions = me.includeOptions(mode, sharedOptions); + for (var i = start; i < start + count; i++) { + var point = points[i]; + var parsed = !reset && me.getParsed(i); + var x = reset ? xScale.getPixelForDecimal(0.5) : xScale.getPixelForValue(parsed.x); + var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(parsed.y); + var properties = { + x: x, + y: y, + skip: isNaN(x) || isNaN(y) + }; + if (includeOptions) { + properties.options = me.resolveDataElementOptions(i, mode); + if (reset) { + properties.options.radius = 0; + } + } + me.updateElement(point, i, properties, mode); + } + me.updateSharedOptions(sharedOptions, mode, firstOpts); + } + ; + _proto.resolveDataElementOptions = function resolveDataElementOptions(index, mode) { + var me = this; + var chart = me.chart; + var dataset = me.getDataset(); + var parsed = me.getParsed(index); + var values = _DatasetController.prototype.resolveDataElementOptions.call(this, index, mode); + var context = { + chart: chart, + dataPoint: parsed, + dataIndex: index, + dataset: dataset, + datasetIndex: me.index + }; + if (values.$shared) { + values = _extends({}, values, { + $shared: false + }); + } + if (mode !== 'active') { + values.radius = 0; + } + values.radius += resolve([parsed && parsed._custom, me._config.radius, chart.options.elements.point.radius], context, index); + return values; + }; + return BubbleController; +}(DatasetController); +BubbleController.id = 'bubble'; +BubbleController.defaults = { + datasetElementType: false, + dataElementType: 'point', + dataElementOptions: ['backgroundColor', 'borderColor', 'borderWidth', 'hitRadius', 'radius', 'pointStyle', 'rotation'], + animation: { + numbers: { + properties: ['x', 'y', 'borderWidth', 'radius'] + } + }, + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + }, + tooltips: { + callbacks: { + title: function title() { + return ''; + } + } + } +}; + +var PI$2 = Math.PI; +var DOUBLE_PI$1 = PI$2 * 2; +var HALF_PI$1 = PI$2 / 2; +function getRatioAndOffset(rotation, circumference, cutout) { + var ratioX = 1; + var ratioY = 1; + var offsetX = 0; + var offsetY = 0; + if (circumference < DOUBLE_PI$1) { + var startAngle = rotation % DOUBLE_PI$1; + startAngle += startAngle >= PI$2 ? -DOUBLE_PI$1 : startAngle < -PI$2 ? DOUBLE_PI$1 : 0; + var endAngle = startAngle + circumference; + var startX = Math.cos(startAngle); + var startY = Math.sin(startAngle); + var endX = Math.cos(endAngle); + var endY = Math.sin(endAngle); + var contains0 = startAngle <= 0 && endAngle >= 0 || endAngle >= DOUBLE_PI$1; + var contains90 = startAngle <= HALF_PI$1 && endAngle >= HALF_PI$1 || endAngle >= DOUBLE_PI$1 + HALF_PI$1; + var contains180 = startAngle === -PI$2 || endAngle >= PI$2; + var contains270 = startAngle <= -HALF_PI$1 && endAngle >= -HALF_PI$1 || endAngle >= PI$2 + HALF_PI$1; + var minX = contains180 ? -1 : Math.min(startX, startX * cutout, endX, endX * cutout); + var minY = contains270 ? -1 : Math.min(startY, startY * cutout, endY, endY * cutout); + var maxX = contains0 ? 1 : Math.max(startX, startX * cutout, endX, endX * cutout); + var maxY = contains90 ? 1 : Math.max(startY, startY * cutout, endY, endY * cutout); + ratioX = (maxX - minX) / 2; + ratioY = (maxY - minY) / 2; + offsetX = -(maxX + minX) / 2; + offsetY = -(maxY + minY) / 2; + } + return { + ratioX: ratioX, + ratioY: ratioY, + offsetX: offsetX, + offsetY: offsetY + }; +} +var DoughnutController = function (_DatasetController) { + _inheritsLoose(DoughnutController, _DatasetController); + function DoughnutController(chart, datasetIndex) { + var _this; + _this = _DatasetController.call(this, chart, datasetIndex) || this; + _this.enableOptionSharing = true; + _this.innerRadius = undefined; + _this.outerRadius = undefined; + _this.offsetX = undefined; + _this.offsetY = undefined; + return _this; + } + var _proto = DoughnutController.prototype; + _proto.linkScales = function linkScales() {} + ; + _proto.parse = function parse(start, count) { + var data = this.getDataset().data; + var meta = this._cachedMeta; + var i, ilen; + for (i = start, ilen = start + count; i < ilen; ++i) { + meta._parsed[i] = +data[i]; + } + } + ; + _proto.getRingIndex = function getRingIndex(datasetIndex) { + var ringIndex = 0; + for (var j = 0; j < datasetIndex; ++j) { + if (this.chart.isDatasetVisible(j)) { + ++ringIndex; + } + } + return ringIndex; + } + ; + _proto.update = function update(mode) { + var me = this; + var chart = me.chart; + var chartArea = chart.chartArea, + options = chart.options; + var meta = me._cachedMeta; + var arcs = meta.data; + var cutout = options.cutoutPercentage / 100 || 0; + var chartWeight = me._getRingWeight(me.index); + var _getRatioAndOffset = getRatioAndOffset(options.rotation, options.circumference, cutout), + ratioX = _getRatioAndOffset.ratioX, + ratioY = _getRatioAndOffset.ratioY, + offsetX = _getRatioAndOffset.offsetX, + offsetY = _getRatioAndOffset.offsetY; + var spacing = me.getMaxBorderWidth() + me.getMaxOffset(arcs); + var maxWidth = (chartArea.right - chartArea.left - spacing) / ratioX; + var maxHeight = (chartArea.bottom - chartArea.top - spacing) / ratioY; + var outerRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0); + var innerRadius = Math.max(outerRadius * cutout, 0); + var radiusLength = (outerRadius - innerRadius) / me._getVisibleDatasetWeightTotal(); + me.offsetX = offsetX * outerRadius; + me.offsetY = offsetY * outerRadius; + meta.total = me.calculateTotal(); + me.outerRadius = outerRadius - radiusLength * me._getRingWeightOffset(me.index); + me.innerRadius = Math.max(me.outerRadius - radiusLength * chartWeight, 0); + me.updateElements(arcs, 0, arcs.length, mode); + } + ; + _proto._circumference = function _circumference(i, reset) { + var me = this; + var opts = me.chart.options; + var meta = me._cachedMeta; + return reset && opts.animation.animateRotate ? 0 : this.chart.getDataVisibility(i) ? me.calculateCircumference(meta._parsed[i] * opts.circumference / DOUBLE_PI$1) : 0; + }; + _proto.updateElements = function updateElements(arcs, start, count, mode) { + var me = this; + var reset = mode === 'reset'; + var chart = me.chart; + var chartArea = chart.chartArea; + var opts = chart.options; + var animationOpts = opts.animation; + var centerX = (chartArea.left + chartArea.right) / 2; + var centerY = (chartArea.top + chartArea.bottom) / 2; + var animateScale = reset && animationOpts.animateScale; + var innerRadius = animateScale ? 0 : me.innerRadius; + var outerRadius = animateScale ? 0 : me.outerRadius; + var firstOpts = me.resolveDataElementOptions(start, mode); + var sharedOptions = me.getSharedOptions(firstOpts); + var includeOptions = me.includeOptions(mode, sharedOptions); + var startAngle = opts.rotation; + var i; + for (i = 0; i < start; ++i) { + startAngle += me._circumference(i, reset); + } + for (i = start; i < start + count; ++i) { + var circumference = me._circumference(i, reset); + var arc = arcs[i]; + var properties = { + x: centerX + me.offsetX, + y: centerY + me.offsetY, + startAngle: startAngle, + endAngle: startAngle + circumference, + circumference: circumference, + outerRadius: outerRadius, + innerRadius: innerRadius + }; + if (includeOptions) { + properties.options = sharedOptions || me.resolveDataElementOptions(i, mode); + } + startAngle += circumference; + me.updateElement(arc, i, properties, mode); + } + me.updateSharedOptions(sharedOptions, mode, firstOpts); + }; + _proto.calculateTotal = function calculateTotal() { + var meta = this._cachedMeta; + var metaData = meta.data; + var total = 0; + var i; + for (i = 0; i < metaData.length; i++) { + var value = meta._parsed[i]; + if (!isNaN(value) && this.chart.getDataVisibility(i)) { + total += Math.abs(value); + } + } + return total; + }; + _proto.calculateCircumference = function calculateCircumference(value) { + var total = this._cachedMeta.total; + if (total > 0 && !isNaN(value)) { + return DOUBLE_PI$1 * (Math.abs(value) / total); + } + return 0; + }; + _proto.getLabelAndValue = function getLabelAndValue(index) { + var me = this; + var meta = me._cachedMeta; + var chart = me.chart; + var labels = chart.data.labels || []; + return { + label: labels[index] || '', + value: meta._parsed[index] + }; + }; + _proto.getMaxBorderWidth = function getMaxBorderWidth(arcs) { + var me = this; + var max = 0; + var chart = me.chart; + var i, ilen, meta, controller, options; + if (!arcs) { + for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) { + if (chart.isDatasetVisible(i)) { + meta = chart.getDatasetMeta(i); + arcs = meta.data; + controller = meta.controller; + if (controller !== me) { + controller.configure(); + } + break; + } + } + } + if (!arcs) { + return 0; + } + for (i = 0, ilen = arcs.length; i < ilen; ++i) { + options = controller.resolveDataElementOptions(i); + if (options.borderAlign !== 'inner') { + max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0); + } + } + return max; + }; + _proto.getMaxOffset = function getMaxOffset(arcs) { + var max = 0; + for (var i = 0, ilen = arcs.length; i < ilen; ++i) { + var options = this.resolveDataElementOptions(i); + max = Math.max(max, options.offset || 0, options.hoverOffset || 0); + } + return max; + } + ; + _proto._getRingWeightOffset = function _getRingWeightOffset(datasetIndex) { + var ringWeightOffset = 0; + for (var i = 0; i < datasetIndex; ++i) { + if (this.chart.isDatasetVisible(i)) { + ringWeightOffset += this._getRingWeight(i); + } + } + return ringWeightOffset; + } + ; + _proto._getRingWeight = function _getRingWeight(datasetIndex) { + return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0); + } + ; + _proto._getVisibleDatasetWeightTotal = function _getVisibleDatasetWeightTotal() { + return this._getRingWeightOffset(this.chart.data.datasets.length) || 1; + }; + return DoughnutController; +}(DatasetController); +DoughnutController.id = 'doughnut'; +DoughnutController.defaults = { + datasetElementType: false, + dataElementType: 'arc', + dataElementOptions: ['backgroundColor', 'borderColor', 'borderWidth', 'borderAlign', 'offset'], + animation: { + numbers: { + type: 'number', + properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth'] + }, + animateRotate: true, + animateScale: false + }, + aspectRatio: 1, + legend: { + labels: { + generateLabels: function generateLabels(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function (label, i) { + var meta = chart.getDatasetMeta(0); + var style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick: function onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + cutoutPercentage: 50, + rotation: -HALF_PI$1, + circumference: DOUBLE_PI$1, + tooltips: { + callbacks: { + title: function title() { + return ''; + }, + label: function label(tooltipItem) { + var dataLabel = tooltipItem.label; + var value = ': ' + tooltipItem.formattedValue; + if (isArray(dataLabel)) { + dataLabel = dataLabel.slice(); + dataLabel[0] += value; + } else { + dataLabel += value; + } + return dataLabel; + } + } + } +}; + +var LineController = function (_DatasetController) { + _inheritsLoose(LineController, _DatasetController); + function LineController() { + return _DatasetController.apply(this, arguments) || this; + } + var _proto = LineController.prototype; + _proto.initialize = function initialize() { + this.enableOptionSharing = true; + _DatasetController.prototype.initialize.call(this); + }; + _proto.update = function update(mode) { + var me = this; + var meta = me._cachedMeta; + var line = meta.dataset, + _meta$data = meta.data, + points = _meta$data === void 0 ? [] : _meta$data; + var animationsDisabled = me.chart._animationsDisabled; + var _getStartAndCountOfVi = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled), + start = _getStartAndCountOfVi.start, + count = _getStartAndCountOfVi.count; + me._drawStart = start; + me._drawCount = count; + if (scaleRangesChanged(meta) && !animationsDisabled) { + start = 0; + count = points.length; + } + if (mode !== 'resize') { + var properties = { + points: points, + options: me.resolveDatasetElementOptions() + }; + me.updateElement(line, undefined, properties, mode); + } + me.updateElements(points, start, count, mode); + }; + _proto.updateElements = function updateElements(points, start, count, mode) { + var me = this; + var reset = mode === 'reset'; + var _me$_cachedMeta = me._cachedMeta, + xScale = _me$_cachedMeta.xScale, + yScale = _me$_cachedMeta.yScale, + _stacked = _me$_cachedMeta._stacked; + var firstOpts = me.resolveDataElementOptions(start, mode); + var sharedOptions = me.getSharedOptions(firstOpts); + var includeOptions = me.includeOptions(mode, sharedOptions); + var spanGaps = valueOrDefault(me._config.spanGaps, me.chart.options.spanGaps); + var maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY; + var prevParsed = start > 0 && me.getParsed(start - 1); + for (var i = start; i < start + count; ++i) { + var point = points[i]; + var parsed = me.getParsed(i); + var x = xScale.getPixelForValue(parsed.x, i); + var y = reset ? yScale.getBasePixel() : yScale.getPixelForValue(_stacked ? me.applyStack(yScale, parsed) : parsed.y, i); + var properties = { + x: x, + y: y, + skip: isNaN(x) || isNaN(y), + stop: i > 0 && parsed.x - prevParsed.x > maxGapLength + }; + if (includeOptions) { + properties.options = sharedOptions || me.resolveDataElementOptions(i, mode); + } + me.updateElement(point, i, properties, mode); + prevParsed = parsed; + } + me.updateSharedOptions(sharedOptions, mode, firstOpts); + } + ; + _proto.resolveDatasetElementOptions = function resolveDatasetElementOptions(active) { + var me = this; + var config = me._config; + var options = me.chart.options; + var lineOptions = options.elements.line; + var values = _DatasetController.prototype.resolveDatasetElementOptions.call(this, active); + var showLine = valueOrDefault(config.showLine, options.showLines); + values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps); + values.tension = valueOrDefault(config.lineTension, lineOptions.tension); + values.stepped = resolve([config.stepped, lineOptions.stepped]); + if (!showLine) { + values.borderWidth = 0; + } + return values; + } + ; + _proto.getMaxOverflow = function getMaxOverflow() { + var me = this; + var meta = me._cachedMeta; + var border = meta.dataset.options.borderWidth || 0; + var data = meta.data || []; + if (!data.length) { + return border; + } + var firstPoint = data[0].size(); + var lastPoint = data[data.length - 1].size(); + return Math.max(border, firstPoint, lastPoint) / 2; + }; + _proto.draw = function draw() { + this._cachedMeta.dataset.updateControlPoints(this.chart.chartArea); + _DatasetController.prototype.draw.call(this); + }; + return LineController; +}(DatasetController); +LineController.id = 'line'; +LineController.defaults = { + datasetElementType: 'line', + datasetElementOptions: ['backgroundColor', 'borderCapStyle', 'borderColor', 'borderDash', 'borderDashOffset', 'borderJoinStyle', 'borderWidth', 'capBezierPoints', 'cubicInterpolationMode', 'fill'], + dataElementType: 'point', + dataElementOptions: { + backgroundColor: 'pointBackgroundColor', + borderColor: 'pointBorderColor', + borderWidth: 'pointBorderWidth', + hitRadius: 'pointHitRadius', + hoverHitRadius: 'pointHitRadius', + hoverBackgroundColor: 'pointHoverBackgroundColor', + hoverBorderColor: 'pointHoverBorderColor', + hoverBorderWidth: 'pointHoverBorderWidth', + hoverRadius: 'pointHoverRadius', + pointStyle: 'pointStyle', + radius: 'pointRadius', + rotation: 'pointRotation' + }, + showLines: true, + spanGaps: false, + hover: { + mode: 'index' + }, + scales: { + _index_: { + type: 'category' + }, + _value_: { + type: 'linear' + } + } +}; +function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) { + var pointCount = points.length; + var start = 0; + var count = pointCount; + if (meta._sorted) { + var iScale = meta.iScale, + _parsed = meta._parsed; + var axis = iScale.axis; + var _iScale$getUserBounds = iScale.getUserBounds(), + min = _iScale$getUserBounds.min, + max = _iScale$getUserBounds.max, + minDefined = _iScale$getUserBounds.minDefined, + maxDefined = _iScale$getUserBounds.maxDefined; + if (minDefined) { + start = _limitValue(Math.min(_lookupByKey(_parsed, iScale.axis, min).lo, animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo), 0, pointCount - 1); + } + if (maxDefined) { + count = _limitValue(Math.max(_lookupByKey(_parsed, iScale.axis, max).hi + 1, animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1), start, pointCount) - start; + } else { + count = pointCount - start; + } + } + return { + start: start, + count: count + }; +} +function scaleRangesChanged(meta) { + var xScale = meta.xScale, + yScale = meta.yScale, + _scaleRanges = meta._scaleRanges; + var newRanges = { + xmin: xScale.min, + xmax: xScale.max, + ymin: yScale.min, + ymax: yScale.max + }; + if (!_scaleRanges) { + meta._scaleRanges = newRanges; + return true; + } + var changed = _scaleRanges.xmin !== xScale.min || _scaleRanges.xmax !== xScale.max || _scaleRanges.ymin !== yScale.min || _scaleRanges.ymax !== yScale.max; + _extends(_scaleRanges, newRanges); + return changed; +} + +function getStartAngleRadians(deg) { + return toRadians(deg) - 0.5 * Math.PI; +} +var PolarAreaController = function (_DatasetController) { + _inheritsLoose(PolarAreaController, _DatasetController); + function PolarAreaController(chart, datasetIndex) { + var _this; + _this = _DatasetController.call(this, chart, datasetIndex) || this; + _this.innerRadius = undefined; + _this.outerRadius = undefined; + return _this; + } + var _proto = PolarAreaController.prototype; + _proto.update = function update(mode) { + var arcs = this._cachedMeta.data; + this._updateRadius(); + this.updateElements(arcs, 0, arcs.length, mode); + } + ; + _proto._updateRadius = function _updateRadius() { + var me = this; + var chart = me.chart; + var chartArea = chart.chartArea; + var opts = chart.options; + var minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top); + var outerRadius = Math.max(minSize / 2, 0); + var innerRadius = Math.max(opts.cutoutPercentage ? outerRadius / 100 * opts.cutoutPercentage : 1, 0); + var radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount(); + me.outerRadius = outerRadius - radiusLength * me.index; + me.innerRadius = me.outerRadius - radiusLength; + }; + _proto.updateElements = function updateElements(arcs, start, count, mode) { + var me = this; + var reset = mode === 'reset'; + var chart = me.chart; + var dataset = me.getDataset(); + var opts = chart.options; + var animationOpts = opts.animation; + var scale = me._cachedMeta.rScale; + var centerX = scale.xCenter; + var centerY = scale.yCenter; + var datasetStartAngle = getStartAngleRadians(opts.startAngle); + var angle = datasetStartAngle; + var i; + me._cachedMeta.count = me.countVisibleElements(); + for (i = 0; i < start; ++i) { + angle += me._computeAngle(i); + } + for (i = start; i < start + count; i++) { + var arc = arcs[i]; + var startAngle = angle; + var endAngle = angle + me._computeAngle(i); + var outerRadius = this.chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0; + angle = endAngle; + if (reset) { + if (animationOpts.animateScale) { + outerRadius = 0; + } + if (animationOpts.animateRotate) { + startAngle = datasetStartAngle; + endAngle = datasetStartAngle; + } + } + var properties = { + x: centerX, + y: centerY, + innerRadius: 0, + outerRadius: outerRadius, + startAngle: startAngle, + endAngle: endAngle, + options: me.resolveDataElementOptions(i, mode) + }; + me.updateElement(arc, i, properties, mode); + } + }; + _proto.countVisibleElements = function countVisibleElements() { + var _this2 = this; + var dataset = this.getDataset(); + var meta = this._cachedMeta; + var count = 0; + meta.data.forEach(function (element, index) { + if (!isNaN(dataset.data[index]) && _this2.chart.getDataVisibility(index)) { + count++; + } + }); + return count; + } + ; + _proto._computeAngle = function _computeAngle(index) { + var me = this; + var meta = me._cachedMeta; + var count = meta.count; + var dataset = me.getDataset(); + if (isNaN(dataset.data[index]) || !this.chart.getDataVisibility(index)) { + return 0; + } + var context = { + chart: me.chart, + dataPoint: this.getParsed(index), + dataIndex: index, + dataset: dataset, + datasetIndex: me.index + }; + return resolve([me.chart.options.elements.arc.angle, 2 * Math.PI / count], context, index); + }; + return PolarAreaController; +}(DatasetController); +PolarAreaController.id = 'polarArea'; +PolarAreaController.defaults = { + dataElementType: 'arc', + dataElementOptions: ['backgroundColor', 'borderColor', 'borderWidth', 'borderAlign', 'offset'], + animation: { + numbers: { + type: 'number', + properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'] + }, + animateRotate: true, + animateScale: true + }, + aspectRatio: 1, + datasets: { + indexAxis: 'r' + }, + scales: { + r: { + type: 'radialLinear', + angleLines: { + display: false + }, + beginAtZero: true, + gridLines: { + circular: true + }, + pointLabels: { + display: false + } + } + }, + startAngle: 0, + legend: { + labels: { + generateLabels: function generateLabels(chart) { + var data = chart.data; + if (data.labels.length && data.datasets.length) { + return data.labels.map(function (label, i) { + var meta = chart.getDatasetMeta(0); + var style = meta.controller.getStyle(i); + return { + text: label, + fillStyle: style.backgroundColor, + strokeStyle: style.borderColor, + lineWidth: style.borderWidth, + hidden: !chart.getDataVisibility(i), + index: i + }; + }); + } + return []; + } + }, + onClick: function onClick(e, legendItem, legend) { + legend.chart.toggleDataVisibility(legendItem.index); + legend.chart.update(); + } + }, + tooltips: { + callbacks: { + title: function title() { + return ''; + }, + label: function label(context) { + return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue; + } + } + } +}; + +var PieController = function (_DoughnutController) { + _inheritsLoose(PieController, _DoughnutController); + function PieController() { + return _DoughnutController.apply(this, arguments) || this; + } + return PieController; +}(DoughnutController); +PieController.id = 'pie'; +PieController.defaults = { + cutoutPercentage: 0 +}; + +var RadarController = function (_DatasetController) { + _inheritsLoose(RadarController, _DatasetController); + function RadarController() { + return _DatasetController.apply(this, arguments) || this; + } + var _proto = RadarController.prototype; + _proto.getLabelAndValue = function getLabelAndValue(index) { + var me = this; + var vScale = me._cachedMeta.vScale; + var parsed = me.getParsed(index); + return { + label: vScale.getLabels()[index], + value: '' + vScale.getLabelForValue(parsed[vScale.axis]) + }; + }; + _proto.update = function update(mode) { + var me = this; + var meta = me._cachedMeta; + var line = meta.dataset; + var points = meta.data || []; + var labels = meta.iScale.getLabels(); + if (mode !== 'resize') { + var properties = { + points: points, + _loop: true, + _fullLoop: labels.length === points.length, + options: me.resolveDatasetElementOptions() + }; + me.updateElement(line, undefined, properties, mode); + } + me.updateElements(points, 0, points.length, mode); + }; + _proto.updateElements = function updateElements(points, start, count, mode) { + var me = this; + var dataset = me.getDataset(); + var scale = me._cachedMeta.rScale; + var reset = mode === 'reset'; + for (var i = start; i < start + count; i++) { + var point = points[i]; + var options = me.resolveDataElementOptions(i, mode); + var pointPosition = scale.getPointPositionForValue(i, dataset.data[i]); + var x = reset ? scale.xCenter : pointPosition.x; + var y = reset ? scale.yCenter : pointPosition.y; + var properties = { + x: x, + y: y, + angle: pointPosition.angle, + skip: isNaN(x) || isNaN(y), + options: options + }; + me.updateElement(point, i, properties, mode); + } + } + ; + _proto.resolveDatasetElementOptions = function resolveDatasetElementOptions(active) { + var me = this; + var config = me._config; + var options = me.chart.options; + var values = _DatasetController.prototype.resolveDatasetElementOptions.call(this, active); + var showLine = valueOrDefault(config.showLine, options.showLines); + values.spanGaps = valueOrDefault(config.spanGaps, options.spanGaps); + values.tension = valueOrDefault(config.lineTension, options.elements.line.tension); + if (!showLine) { + values.borderWidth = 0; + } + return values; + }; + return RadarController; +}(DatasetController); +RadarController.id = 'radar'; +RadarController.defaults = { + datasetElementType: 'line', + datasetElementOptions: ['backgroundColor', 'borderColor', 'borderCapStyle', 'borderDash', 'borderDashOffset', 'borderJoinStyle', 'borderWidth', 'fill'], + dataElementType: 'point', + dataElementOptions: { + backgroundColor: 'pointBackgroundColor', + borderColor: 'pointBorderColor', + borderWidth: 'pointBorderWidth', + hitRadius: 'pointHitRadius', + hoverBackgroundColor: 'pointHoverBackgroundColor', + hoverBorderColor: 'pointHoverBorderColor', + hoverBorderWidth: 'pointHoverBorderWidth', + hoverRadius: 'pointHoverRadius', + pointStyle: 'pointStyle', + radius: 'pointRadius', + rotation: 'pointRotation' + }, + aspectRatio: 1, + spanGaps: false, + scales: { + r: { + type: 'radialLinear' + } + }, + datasets: { + indexAxis: 'r' + }, + elements: { + line: { + fill: 'start', + tension: 0 + } + } +}; + +var ScatterController = function (_LineController) { + _inheritsLoose(ScatterController, _LineController); + function ScatterController() { + return _LineController.apply(this, arguments) || this; + } + return ScatterController; +}(LineController); +ScatterController.id = 'scatter'; +ScatterController.defaults = { + scales: { + x: { + type: 'linear' + }, + y: { + type: 'linear' + } + }, + datasets: { + showLine: false, + fill: false + }, + tooltips: { + callbacks: { + title: function title() { + return ''; + }, + label: function label(item) { + return '(' + item.label + ', ' + item.formattedValue + ')'; + } + } + } +}; + +var controllers = /*#__PURE__*/Object.freeze({ +__proto__: null, +BarController: BarController, +BubbleController: BubbleController, +DoughnutController: DoughnutController, +LineController: LineController, +PolarAreaController: PolarAreaController, +PieController: PieController, +RadarController: RadarController, +ScatterController: ScatterController +}); + +var TAU$1 = Math.PI * 2; +function clipArc(ctx, element) { + var startAngle = element.startAngle, + endAngle = element.endAngle, + pixelMargin = element.pixelMargin, + x = element.x, + y = element.y, + outerRadius = element.outerRadius, + innerRadius = element.innerRadius; + var angleMargin = pixelMargin / outerRadius; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin); + if (innerRadius > pixelMargin) { + angleMargin = pixelMargin / innerRadius; + ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true); + } else { + ctx.arc(x, y, pixelMargin, endAngle + Math.PI / 2, startAngle - Math.PI / 2); + } + ctx.closePath(); + ctx.clip(); +} +function pathArc(ctx, element) { + var x = element.x, + y = element.y, + startAngle = element.startAngle, + endAngle = element.endAngle, + pixelMargin = element.pixelMargin; + var outerRadius = Math.max(element.outerRadius - pixelMargin, 0); + var innerRadius = element.innerRadius + pixelMargin; + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, endAngle); + ctx.arc(x, y, innerRadius, endAngle, startAngle, true); + ctx.closePath(); +} +function drawArc(ctx, element) { + if (element.fullCircles) { + element.endAngle = element.startAngle + TAU$1; + pathArc(ctx, element); + for (var i = 0; i < element.fullCircles; ++i) { + ctx.fill(); + } + element.endAngle = element.startAngle + element.circumference % TAU$1; + } + pathArc(ctx, element); + ctx.fill(); +} +function drawFullCircleBorders(ctx, element, inner) { + var x = element.x, + y = element.y, + startAngle = element.startAngle, + endAngle = element.endAngle, + pixelMargin = element.pixelMargin; + var outerRadius = Math.max(element.outerRadius - pixelMargin, 0); + var innerRadius = element.innerRadius + pixelMargin; + var i; + if (inner) { + element.endAngle = element.startAngle + TAU$1; + clipArc(ctx, element); + element.endAngle = endAngle; + if (element.endAngle === element.startAngle) { + element.endAngle += TAU$1; + element.fullCircles--; + } + } + ctx.beginPath(); + ctx.arc(x, y, innerRadius, startAngle + TAU$1, startAngle, true); + for (i = 0; i < element.fullCircles; ++i) { + ctx.stroke(); + } + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU$1); + for (i = 0; i < element.fullCircles; ++i) { + ctx.stroke(); + } +} +function drawBorder(ctx, element) { + var x = element.x, + y = element.y, + startAngle = element.startAngle, + endAngle = element.endAngle, + pixelMargin = element.pixelMargin, + options = element.options; + var outerRadius = element.outerRadius; + var innerRadius = element.innerRadius + pixelMargin; + var inner = options.borderAlign === 'inner'; + if (!options.borderWidth) { + return; + } + if (inner) { + ctx.lineWidth = options.borderWidth * 2; + ctx.lineJoin = 'round'; + } else { + ctx.lineWidth = options.borderWidth; + ctx.lineJoin = 'bevel'; + } + if (element.fullCircles) { + drawFullCircleBorders(ctx, element, inner); + } + if (inner) { + clipArc(ctx, element); + } + ctx.beginPath(); + ctx.arc(x, y, outerRadius, startAngle, endAngle); + ctx.arc(x, y, innerRadius, endAngle, startAngle, true); + ctx.closePath(); + ctx.stroke(); +} +var Arc = function (_Element) { + _inheritsLoose(Arc, _Element); + function Arc(cfg) { + var _this; + _this = _Element.call(this) || this; + _this.options = undefined; + _this.circumference = undefined; + _this.startAngle = undefined; + _this.endAngle = undefined; + _this.innerRadius = undefined; + _this.outerRadius = undefined; + _this.pixelMargin = 0; + _this.fullCircles = 0; + if (cfg) { + _extends(_assertThisInitialized(_this), cfg); + } + return _this; + } + var _proto = Arc.prototype; + _proto.inRange = function inRange(chartX, chartY, useFinalPosition) { + var point = this.getProps(['x', 'y'], useFinalPosition); + var _getAngleFromPoint = getAngleFromPoint(point, { + x: chartX, + y: chartY + }), + angle = _getAngleFromPoint.angle, + distance = _getAngleFromPoint.distance; + var _this$getProps = this.getProps(['startAngle', 'endAngle', 'innerRadius', 'outerRadius', 'circumference'], useFinalPosition), + startAngle = _this$getProps.startAngle, + endAngle = _this$getProps.endAngle, + innerRadius = _this$getProps.innerRadius, + outerRadius = _this$getProps.outerRadius, + circumference = _this$getProps.circumference; + var betweenAngles = circumference >= TAU$1 || _angleBetween(angle, startAngle, endAngle); + var withinRadius = distance >= innerRadius && distance <= outerRadius; + return betweenAngles && withinRadius; + } + ; + _proto.getCenterPoint = function getCenterPoint(useFinalPosition) { + var _this$getProps2 = this.getProps(['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius'], useFinalPosition), + x = _this$getProps2.x, + y = _this$getProps2.y, + startAngle = _this$getProps2.startAngle, + endAngle = _this$getProps2.endAngle, + innerRadius = _this$getProps2.innerRadius, + outerRadius = _this$getProps2.outerRadius; + var halfAngle = (startAngle + endAngle) / 2; + var halfRadius = (innerRadius + outerRadius) / 2; + return { + x: x + Math.cos(halfAngle) * halfRadius, + y: y + Math.sin(halfAngle) * halfRadius + }; + } + ; + _proto.tooltipPosition = function tooltipPosition(useFinalPosition) { + return this.getCenterPoint(useFinalPosition); + }; + _proto.draw = function draw(ctx) { + var me = this; + var options = me.options; + var offset = options.offset || 0; + me.pixelMargin = options.borderAlign === 'inner' ? 0.33 : 0; + me.fullCircles = Math.floor(me.circumference / TAU$1); + if (me.circumference === 0) { + return; + } + ctx.save(); + if (offset && me.circumference < TAU$1) { + var halfAngle = (me.startAngle + me.endAngle) / 2; + ctx.translate(Math.cos(halfAngle) * offset, Math.sin(halfAngle) * offset); + } + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + drawArc(ctx, me); + drawBorder(ctx, me); + ctx.restore(); + }; + return Arc; +}(Element$1); +Arc.id = 'arc'; +Arc.defaults = { + borderAlign: 'center', + borderColor: '#fff', + borderWidth: 2, + offset: 0 +}; +Arc.defaultRoutes = { + backgroundColor: 'color' +}; + +function setStyle(ctx, vm) { + ctx.lineCap = vm.borderCapStyle; + ctx.setLineDash(vm.borderDash); + ctx.lineDashOffset = vm.borderDashOffset; + ctx.lineJoin = vm.borderJoinStyle; + ctx.lineWidth = vm.borderWidth; + ctx.strokeStyle = vm.borderColor; +} +function lineTo(ctx, previous, target) { + ctx.lineTo(target.x, target.y); +} +function getLineMethod(options) { + if (options.stepped) { + return _steppedLineTo; + } + if (options.tension) { + return _bezierCurveTo; + } + return lineTo; +} +function pathVars(points, segment, params) { + params = params || {}; + var count = points.length; + var start = Math.max(params.start || 0, segment.start); + var end = Math.min(params.end || count - 1, segment.end); + return { + count: count, + start: start, + loop: segment.loop, + ilen: end < start ? count + end - start : end - start + }; +} +function pathSegment(ctx, line, segment, params) { + var points = line.points, + options = line.options; + var _pathVars = pathVars(points, segment, params), + count = _pathVars.count, + start = _pathVars.start, + loop = _pathVars.loop, + ilen = _pathVars.ilen; + var lineMethod = getLineMethod(options); + var _ref = params || {}, + _ref$move = _ref.move, + move = _ref$move === void 0 ? true : _ref$move, + reverse = _ref.reverse; + var i, point, prev; + for (i = 0; i <= ilen; ++i) { + point = points[(start + (reverse ? ilen - i : i)) % count]; + if (point.skip) { + continue; + } else if (move) { + ctx.moveTo(point.x, point.y); + move = false; + } else { + lineMethod(ctx, prev, point, reverse, options.stepped); + } + prev = point; + } + if (loop) { + point = points[(start + (reverse ? ilen : 0)) % count]; + lineMethod(ctx, prev, point, reverse, options.stepped); + } + return !!loop; +} +function fastPathSegment(ctx, line, segment, params) { + var points = line.points; + var _pathVars2 = pathVars(points, segment, params), + count = _pathVars2.count, + start = _pathVars2.start, + ilen = _pathVars2.ilen; + var _ref2 = params || {}, + _ref2$move = _ref2.move, + move = _ref2$move === void 0 ? true : _ref2$move, + reverse = _ref2.reverse; + var avgX = 0; + var countX = 0; + var i, point, prevX, minY, maxY, lastY; + var pointIndex = function pointIndex(index) { + return (start + (reverse ? ilen - index : index)) % count; + }; + var drawX = function drawX() { + if (minY !== maxY) { + ctx.lineTo(avgX, maxY); + ctx.lineTo(avgX, minY); + ctx.lineTo(avgX, lastY); + } + }; + if (move) { + point = points[pointIndex(0)]; + ctx.moveTo(point.x, point.y); + } + for (i = 0; i <= ilen; ++i) { + point = points[pointIndex(i)]; + if (point.skip) { + continue; + } + var x = point.x; + var y = point.y; + var truncX = x | 0; + if (truncX === prevX) { + if (y < minY) { + minY = y; + } else if (y > maxY) { + maxY = y; + } + avgX = (countX * avgX + x) / ++countX; + } else { + drawX(); + ctx.lineTo(x, y); + prevX = truncX; + countX = 0; + minY = maxY = y; + } + lastY = y; + } + drawX(); +} +function _getSegmentMethod(line) { + var opts = line.options; + var borderDash = opts.borderDash && opts.borderDash.length; + var useFastPath = !line._loop && !opts.tension && !opts.stepped && !borderDash; + return useFastPath ? fastPathSegment : pathSegment; +} +function _getInterpolationMethod(options) { + if (options.stepped) { + return _steppedInterpolation; + } + if (options.tension) { + return _bezierInterpolation; + } + return _pointInLine; +} +var Line = function (_Element) { + _inheritsLoose(Line, _Element); + function Line(cfg) { + var _this; + _this = _Element.call(this) || this; + _this.options = undefined; + _this._loop = undefined; + _this._fullLoop = undefined; + _this._points = undefined; + _this._segments = undefined; + _this._pointsUpdated = false; + if (cfg) { + _extends(_assertThisInitialized(_this), cfg); + } + return _this; + } + var _proto = Line.prototype; + _proto.updateControlPoints = function updateControlPoints(chartArea) { + var me = this; + var options = me.options; + if (options.tension && !options.stepped && !me._pointsUpdated) { + var loop = options.spanGaps ? me._loop : me._fullLoop; + _updateBezierControlPoints(me._points, options, chartArea, loop); + me._pointsUpdated = true; + } + }; + _proto.first = function first() { + var segments = this.segments; + var points = this.points; + return segments.length && points[segments[0].start]; + } + ; + _proto.last = function last() { + var segments = this.segments; + var points = this.points; + var count = segments.length; + return count && points[segments[count - 1].end]; + } + ; + _proto.interpolate = function interpolate(point, property) { + var me = this; + var options = me.options; + var value = point[property]; + var points = me.points; + var segments = _boundSegments(me, { + property: property, + start: value, + end: value + }); + if (!segments.length) { + return; + } + var result = []; + var _interpolate = _getInterpolationMethod(options); + var i, ilen; + for (i = 0, ilen = segments.length; i < ilen; ++i) { + var _segments$i = segments[i], + start = _segments$i.start, + end = _segments$i.end; + var p1 = points[start]; + var p2 = points[end]; + if (p1 === p2) { + result.push(p1); + continue; + } + var t = Math.abs((value - p1[property]) / (p2[property] - p1[property])); + var interpolated = _interpolate(p1, p2, t, options.stepped); + interpolated[property] = point[property]; + result.push(interpolated); + } + return result.length === 1 ? result[0] : result; + } + ; + _proto.pathSegment = function pathSegment(ctx, segment, params) { + var segmentMethod = _getSegmentMethod(this); + return segmentMethod(ctx, this, segment, params); + } + ; + _proto.path = function path(ctx, start, count) { + var me = this; + var segments = me.segments; + var ilen = segments.length; + var segmentMethod = _getSegmentMethod(me); + var loop = me._loop; + start = start || 0; + count = count || me.points.length - start; + for (var i = 0; i < ilen; ++i) { + loop &= segmentMethod(ctx, me, segments[i], { + start: start, + end: start + count - 1 + }); + } + return !!loop; + } + ; + _proto.draw = function draw(ctx, chartArea, start, count) { + var options = this.options || {}; + var points = this.points || []; + if (!points.length || !options.borderWidth) { + return; + } + ctx.save(); + setStyle(ctx, options); + ctx.beginPath(); + if (this.path(ctx, start, count)) { + ctx.closePath(); + } + ctx.stroke(); + ctx.restore(); + this._pointsUpdated = false; + }; + _createClass(Line, [{ + key: "points", + set: function set(points) { + this._points = points; + delete this._segments; + }, + get: function get() { + return this._points; + } + }, { + key: "segments", + get: function get() { + return this._segments || (this._segments = _computeSegments(this)); + } + }]); + return Line; +}(Element$1); +Line.id = 'line'; +Line.defaults = { + borderCapStyle: 'butt', + borderDash: [], + borderDashOffset: 0, + borderJoinStyle: 'miter', + borderWidth: 3, + capBezierPoints: true, + fill: true, + tension: 0 +}; +Line.defaultRoutes = { + backgroundColor: 'color', + borderColor: 'color' +}; + +var Point = function (_Element) { + _inheritsLoose(Point, _Element); + function Point(cfg) { + var _this; + _this = _Element.call(this) || this; + _this.options = undefined; + _this.skip = undefined; + _this.stop = undefined; + if (cfg) { + _extends(_assertThisInitialized(_this), cfg); + } + return _this; + } + var _proto = Point.prototype; + _proto.inRange = function inRange(mouseX, mouseY, useFinalPosition) { + var options = this.options; + var _this$getProps = this.getProps(['x', 'y'], useFinalPosition), + x = _this$getProps.x, + y = _this$getProps.y; + return Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2) < Math.pow(options.hitRadius + options.radius, 2); + }; + _proto.inXRange = function inXRange(mouseX, useFinalPosition) { + var options = this.options; + var _this$getProps2 = this.getProps(['x'], useFinalPosition), + x = _this$getProps2.x; + return Math.abs(mouseX - x) < options.radius + options.hitRadius; + }; + _proto.inYRange = function inYRange(mouseY, useFinalPosition) { + var options = this.options; + var _this$getProps3 = this.getProps(['x'], useFinalPosition), + y = _this$getProps3.y; + return Math.abs(mouseY - y) < options.radius + options.hitRadius; + }; + _proto.getCenterPoint = function getCenterPoint(useFinalPosition) { + var _this$getProps4 = this.getProps(['x', 'y'], useFinalPosition), + x = _this$getProps4.x, + y = _this$getProps4.y; + return { + x: x, + y: y + }; + }; + _proto.size = function size() { + var options = this.options || {}; + var radius = Math.max(options.radius, options.hoverRadius) || 0; + var borderWidth = radius && options.borderWidth || 0; + return (radius + borderWidth) * 2; + }; + _proto.draw = function draw(ctx, chartArea) { + var me = this; + var options = me.options; + if (me.skip || options.radius <= 0) { + return; + } + if (chartArea === undefined || _isPointInArea(me, chartArea)) { + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.fillStyle = options.backgroundColor; + drawPoint(ctx, options, me.x, me.y); + } + }; + _proto.getRange = function getRange() { + var options = this.options || {}; + return options.radius + options.hitRadius; + }; + return Point; +}(Element$1); +Point.id = 'point'; +Point.defaults = { + borderWidth: 1, + hitRadius: 1, + hoverBorderWidth: 1, + hoverRadius: 4, + pointStyle: 'circle', + radius: 3 +}; +Point.defaultRoutes = { + backgroundColor: 'color', + borderColor: 'color' +}; + +function getBarBounds(bar, useFinalPosition) { + var _bar$getProps = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition), + x = _bar$getProps.x, + y = _bar$getProps.y, + base = _bar$getProps.base, + width = _bar$getProps.width, + height = _bar$getProps.height; + var left, right, top, bottom, half; + if (bar.horizontal) { + half = height / 2; + left = Math.min(x, base); + right = Math.max(x, base); + top = y - half; + bottom = y + half; + } else { + half = width / 2; + left = x - half; + right = x + half; + top = Math.min(y, base); + bottom = Math.max(y, base); + } + return { + left: left, + top: top, + right: right, + bottom: bottom + }; +} +function parseBorderSkipped(bar) { + var edge = bar.options.borderSkipped; + var res = {}; + if (!edge) { + return res; + } + edge = bar.horizontal ? parseEdge(edge, 'left', 'right', bar.base > bar.x) : parseEdge(edge, 'bottom', 'top', bar.base < bar.y); + res[edge] = true; + return res; +} +function parseEdge(edge, a, b, reverse) { + if (reverse) { + edge = swap(edge, a, b); + edge = startEnd(edge, b, a); + } else { + edge = startEnd(edge, a, b); + } + return edge; +} +function swap(orig, v1, v2) { + return orig === v1 ? v2 : orig === v2 ? v1 : orig; +} +function startEnd(v, start, end) { + return v === 'start' ? start : v === 'end' ? end : v; +} +function skipOrLimit(skip, value, min, max) { + return skip ? 0 : Math.max(Math.min(value, max), min); +} +function parseBorderWidth(bar, maxW, maxH) { + var value = bar.options.borderWidth; + var skip = parseBorderSkipped(bar); + var o = toTRBL(value); + return { + t: skipOrLimit(skip.top, o.top, 0, maxH), + r: skipOrLimit(skip.right, o.right, 0, maxW), + b: skipOrLimit(skip.bottom, o.bottom, 0, maxH), + l: skipOrLimit(skip.left, o.left, 0, maxW) + }; +} +function boundingRects(bar) { + var bounds = getBarBounds(bar); + var width = bounds.right - bounds.left; + var height = bounds.bottom - bounds.top; + var border = parseBorderWidth(bar, width / 2, height / 2); + return { + outer: { + x: bounds.left, + y: bounds.top, + w: width, + h: height + }, + inner: { + x: bounds.left + border.l, + y: bounds.top + border.t, + w: width - border.l - border.r, + h: height - border.t - border.b + } + }; +} +function _inRange(bar, x, y, useFinalPosition) { + var skipX = x === null; + var skipY = y === null; + var skipBoth = skipX && skipY; + var bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition); + return bounds && (skipX || x >= bounds.left && x <= bounds.right) && (skipY || y >= bounds.top && y <= bounds.bottom); +} +var Rectangle = function (_Element) { + _inheritsLoose(Rectangle, _Element); + function Rectangle(cfg) { + var _this; + _this = _Element.call(this) || this; + _this.options = undefined; + _this.horizontal = undefined; + _this.base = undefined; + _this.width = undefined; + _this.height = undefined; + if (cfg) { + _extends(_assertThisInitialized(_this), cfg); + } + return _this; + } + var _proto = Rectangle.prototype; + _proto.draw = function draw(ctx) { + var options = this.options; + var _boundingRects = boundingRects(this), + inner = _boundingRects.inner, + outer = _boundingRects.outer; + ctx.save(); + if (outer.w !== inner.w || outer.h !== inner.h) { + ctx.beginPath(); + ctx.rect(outer.x, outer.y, outer.w, outer.h); + ctx.clip(); + ctx.rect(inner.x, inner.y, inner.w, inner.h); + ctx.fillStyle = options.borderColor; + ctx.fill('evenodd'); + } + ctx.fillStyle = options.backgroundColor; + ctx.fillRect(inner.x, inner.y, inner.w, inner.h); + ctx.restore(); + }; + _proto.inRange = function inRange(mouseX, mouseY, useFinalPosition) { + return _inRange(this, mouseX, mouseY, useFinalPosition); + }; + _proto.inXRange = function inXRange(mouseX, useFinalPosition) { + return _inRange(this, mouseX, null, useFinalPosition); + }; + _proto.inYRange = function inYRange(mouseY, useFinalPosition) { + return _inRange(this, null, mouseY, useFinalPosition); + }; + _proto.getCenterPoint = function getCenterPoint(useFinalPosition) { + var _this$getProps = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition), + x = _this$getProps.x, + y = _this$getProps.y, + base = _this$getProps.base, + horizontal = _this$getProps.horizontal; + return { + x: horizontal ? (x + base) / 2 : x, + y: horizontal ? y : (y + base) / 2 + }; + }; + _proto.getRange = function getRange(axis) { + return axis === 'x' ? this.width / 2 : this.height / 2; + }; + return Rectangle; +}(Element$1); +Rectangle.id = 'rectangle'; +Rectangle.defaults = { + borderSkipped: 'start', + borderWidth: 0 +}; +Rectangle.defaultRoutes = { + backgroundColor: 'color', + borderColor: 'color' +}; + +var elements = /*#__PURE__*/Object.freeze({ +__proto__: null, +Arc: Arc, +Line: Line, +Point: Point, +Rectangle: Rectangle +}); + +function getLineByIndex(chart, index) { + var meta = chart.getDatasetMeta(index); + var visible = meta && chart.isDatasetVisible(index); + return visible ? meta.dataset : null; +} +function parseFillOption(line) { + var options = line.options; + var fillOption = options.fill; + var fill = valueOrDefault(fillOption && fillOption.target, fillOption); + if (fill === undefined) { + fill = !!options.backgroundColor; + } + if (fill === false || fill === null) { + return false; + } + if (fill === true) { + return 'origin'; + } + return fill; +} +function decodeFill(line, index, count) { + var fill = parseFillOption(line); + var target = parseFloat(fill); + if (isNumberFinite(target) && Math.floor(target) === target) { + if (fill[0] === '-' || fill[0] === '+') { + target = index + target; + } + if (target === index || target < 0 || target >= count) { + return false; + } + return target; + } + return ['origin', 'start', 'end', 'stack'].indexOf(fill) >= 0 && fill; +} +function computeLinearBoundary(source) { + var _source$scale = source.scale, + scale = _source$scale === void 0 ? {} : _source$scale, + fill = source.fill; + var target = null; + var horizontal; + if (fill === 'start') { + target = scale.bottom; + } else if (fill === 'end') { + target = scale.top; + } else if (scale.getBasePixel) { + target = scale.getBasePixel(); + } + if (isNumberFinite(target)) { + horizontal = scale.isHorizontal(); + return { + x: horizontal ? target : null, + y: horizontal ? null : target + }; + } + return null; +} +var simpleArc = function () { + function simpleArc(opts) { + this.x = opts.x; + this.y = opts.y; + this.radius = opts.radius; + } + var _proto = simpleArc.prototype; + _proto.pathSegment = function pathSegment(ctx, bounds, opts) { + var x = this.x, + y = this.y, + radius = this.radius; + bounds = bounds || { + start: 0, + end: Math.PI * 2 + }; + if (opts.reverse) { + ctx.arc(x, y, radius, bounds.end, bounds.start, true); + } else { + ctx.arc(x, y, radius, bounds.start, bounds.end); + } + return !opts.bounds; + }; + _proto.interpolate = function interpolate(point, property) { + var x = this.x, + y = this.y, + radius = this.radius; + var angle = point.angle; + if (property === 'angle') { + return { + x: x + Math.cos(angle) * radius, + y: y + Math.sin(angle) * radius, + angle: angle + }; + } + }; + return simpleArc; +}(); +function computeCircularBoundary(source) { + var scale = source.scale, + fill = source.fill; + var options = scale.options; + var length = scale.getLabels().length; + var target = []; + var start = options.reverse ? scale.max : scale.min; + var end = options.reverse ? scale.min : scale.max; + var value = fill === 'start' ? start : fill === 'end' ? end : scale.getBaseValue(); + var i, center; + if (options.gridLines.circular) { + center = scale.getPointPositionForValue(0, start); + return new simpleArc({ + x: center.x, + y: center.y, + radius: scale.getDistanceFromCenterForValue(value) + }); + } + for (i = 0; i < length; ++i) { + target.push(scale.getPointPositionForValue(i, value)); + } + return target; +} +function computeBoundary(source) { + var scale = source.scale || {}; + if (scale.getPointPositionForValue) { + return computeCircularBoundary(source); + } + return computeLinearBoundary(source); +} +function pointsFromSegments(boundary, line) { + var _ref = boundary || {}, + _ref$x = _ref.x, + x = _ref$x === void 0 ? null : _ref$x, + _ref$y = _ref.y, + y = _ref$y === void 0 ? null : _ref$y; + var linePoints = line.points; + var points = []; + line.segments.forEach(function (segment) { + var first = linePoints[segment.start]; + var last = linePoints[segment.end]; + if (y !== null) { + points.push({ + x: first.x, + y: y + }); + points.push({ + x: last.x, + y: y + }); + } else if (x !== null) { + points.push({ + x: x, + y: first.y + }); + points.push({ + x: x, + y: last.y + }); + } + }); + return points; +} +function buildStackLine(source) { + var chart = source.chart, + scale = source.scale, + index = source.index, + line = source.line; + var points = []; + var segments = line.segments; + var sourcePoints = line.points; + var linesBelow = getLinesBelow(chart, index); + linesBelow.push(createBoundaryLine({ + x: null, + y: scale.bottom + }, line)); + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + for (var j = segment.start; j <= segment.end; j++) { + addPointsBelow(points, sourcePoints[j], linesBelow); + } + } + return new Line({ + points: points, + options: {} + }); +} +var isLineAndNotInHideAnimation = function isLineAndNotInHideAnimation(meta) { + return meta.type === 'line' && !meta.hidden; +}; +function getLinesBelow(chart, index) { + var below = []; + var metas = chart.getSortedVisibleDatasetMetas(); + for (var i = 0; i < metas.length; i++) { + var meta = metas[i]; + if (meta.index === index) { + break; + } + if (isLineAndNotInHideAnimation(meta)) { + below.unshift(meta.dataset); + } + } + return below; +} +function addPointsBelow(points, sourcePoint, linesBelow) { + var postponed = []; + for (var j = 0; j < linesBelow.length; j++) { + var line = linesBelow[j]; + var _findPoint = findPoint(line, sourcePoint, 'x'), + first = _findPoint.first, + last = _findPoint.last, + point = _findPoint.point; + if (!point || first && last) { + continue; + } + if (first) { + postponed.unshift(point); + } else { + points.push(point); + if (!last) { + break; + } + } + } + points.push.apply(points, postponed); +} +function findPoint(line, sourcePoint, property) { + var point = line.interpolate(sourcePoint, property); + if (!point) { + return {}; + } + var pointValue = point[property]; + var segments = line.segments; + var linePoints = line.points; + var first = false; + var last = false; + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + var firstValue = linePoints[segment.start][property]; + var lastValue = linePoints[segment.end][property]; + if (pointValue >= firstValue && pointValue <= lastValue) { + first = pointValue === firstValue; + last = pointValue === lastValue; + break; + } + } + return { + first: first, + last: last, + point: point + }; +} +function getTarget(source) { + var chart = source.chart, + fill = source.fill, + line = source.line; + if (isNumberFinite(fill)) { + return getLineByIndex(chart, fill); + } + if (fill === 'stack') { + return buildStackLine(source); + } + var boundary = computeBoundary(source); + if (boundary instanceof simpleArc) { + return boundary; + } + return createBoundaryLine(boundary, line); +} +function createBoundaryLine(boundary, line) { + var points = []; + var _loop = false; + if (isArray(boundary)) { + _loop = true; + points = boundary; + } else { + points = pointsFromSegments(boundary, line); + } + return points.length ? new Line({ + points: points, + options: { + tension: 0 + }, + _loop: _loop, + _fullLoop: _loop + }) : null; +} +function resolveTarget(sources, index, propagate) { + var source = sources[index]; + var fill = source.fill; + var visited = [index]; + var target; + if (!propagate) { + return fill; + } + while (fill !== false && visited.indexOf(fill) === -1) { + if (!isNumberFinite(fill)) { + return fill; + } + target = sources[fill]; + if (!target) { + return false; + } + if (target.visible) { + return fill; + } + visited.push(fill); + fill = target.fill; + } + return false; +} +function _clip(ctx, target, clipY) { + ctx.beginPath(); + target.path(ctx); + ctx.lineTo(target.last().x, clipY); + ctx.lineTo(target.first().x, clipY); + ctx.closePath(); + ctx.clip(); +} +function getBounds(property, first, last, loop) { + if (loop) { + return; + } + var start = first[property]; + var end = last[property]; + if (property === 'angle') { + start = _normalizeAngle(start); + end = _normalizeAngle(end); + } + return { + property: property, + start: start, + end: end + }; +} +function _getEdge(a, b, prop, fn) { + if (a && b) { + return fn(a[prop], b[prop]); + } + return a ? a[prop] : b ? b[prop] : 0; +} +function _segments(line, target, property) { + var segments = line.segments; + var points = line.points; + var tpoints = target.points; + var parts = []; + for (var i = 0; i < segments.length; i++) { + var segment = segments[i]; + var bounds = getBounds(property, points[segment.start], points[segment.end], segment.loop); + if (!target.segments) { + parts.push({ + source: segment, + target: bounds, + start: points[segment.start], + end: points[segment.end] + }); + continue; + } + var subs = _boundSegments(target, bounds); + for (var j = 0; j < subs.length; ++j) { + var sub = subs[j]; + var subBounds = getBounds(property, tpoints[sub.start], tpoints[sub.end], sub.loop); + var fillSources = _boundSegment(segment, points, subBounds); + for (var k = 0; k < fillSources.length; k++) { + var _start, _end; + parts.push({ + source: fillSources[k], + target: sub, + start: (_start = {}, _start[property] = _getEdge(bounds, subBounds, 'start', Math.max), _start), + end: (_end = {}, _end[property] = _getEdge(bounds, subBounds, 'end', Math.min), _end) + }); + } + } + } + return parts; +} +function clipBounds(ctx, scale, bounds) { + var _scale$chart$chartAre = scale.chart.chartArea, + top = _scale$chart$chartAre.top, + bottom = _scale$chart$chartAre.bottom; + var _ref2 = bounds || {}, + property = _ref2.property, + start = _ref2.start, + end = _ref2.end; + if (property === 'x') { + ctx.beginPath(); + ctx.rect(start, top, end - start, bottom - top); + ctx.clip(); + } +} +function interpolatedLineTo(ctx, target, point, property) { + var interpolatedPoint = target.interpolate(point, property); + if (interpolatedPoint) { + ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y); + } +} +function _fill(ctx, cfg) { + var line = cfg.line, + target = cfg.target, + property = cfg.property, + color = cfg.color, + scale = cfg.scale; + var segments = _segments(line, target, property); + ctx.fillStyle = color; + for (var i = 0, ilen = segments.length; i < ilen; ++i) { + var _segments$i = segments[i], + src = _segments$i.source, + tgt = _segments$i.target, + start = _segments$i.start, + end = _segments$i.end; + ctx.save(); + clipBounds(ctx, scale, getBounds(property, start, end)); + ctx.beginPath(); + var lineLoop = !!line.pathSegment(ctx, src); + if (lineLoop) { + ctx.closePath(); + } else { + interpolatedLineTo(ctx, target, end, property); + } + var targetLoop = !!target.pathSegment(ctx, tgt, { + move: lineLoop, + reverse: true + }); + var loop = lineLoop && targetLoop; + if (!loop) { + interpolatedLineTo(ctx, target, start, property); + } + ctx.closePath(); + ctx.fill(loop ? 'evenodd' : 'nonzero'); + ctx.restore(); + } +} +function doFill(ctx, cfg) { + var line = cfg.line, + target = cfg.target, + above = cfg.above, + below = cfg.below, + area = cfg.area, + scale = cfg.scale; + var property = line._loop ? 'angle' : 'x'; + ctx.save(); + if (property === 'x' && below !== above) { + _clip(ctx, target, area.top); + _fill(ctx, { + line: line, + target: target, + color: above, + scale: scale, + property: property + }); + ctx.restore(); + ctx.save(); + _clip(ctx, target, area.bottom); + } + _fill(ctx, { + line: line, + target: target, + color: below, + scale: scale, + property: property + }); + ctx.restore(); +} +var plugin_filler = { + id: 'filler', + afterDatasetsUpdate: function afterDatasetsUpdate(chart, options) { + var count = (chart.data.datasets || []).length; + var propagate = options.propagate; + var sources = []; + var meta, i, line, source; + for (i = 0; i < count; ++i) { + meta = chart.getDatasetMeta(i); + line = meta.dataset; + source = null; + if (line && line.options && line instanceof Line) { + source = { + visible: chart.isDatasetVisible(i), + index: i, + fill: decodeFill(line, i, count), + chart: chart, + scale: meta.vScale, + line: line + }; + } + meta.$filler = source; + sources.push(source); + } + for (i = 0; i < count; ++i) { + source = sources[i]; + if (!source || source.fill === false) { + continue; + } + source.fill = resolveTarget(sources, i, propagate); + } + }, + beforeDatasetsDraw: function beforeDatasetsDraw(chart) { + var metasets = chart.getSortedVisibleDatasetMetas(); + var area = chart.chartArea; + var i, meta; + for (i = metasets.length - 1; i >= 0; --i) { + meta = metasets[i].$filler; + if (meta) { + meta.line.updateControlPoints(area); + } + } + }, + beforeDatasetDraw: function beforeDatasetDraw(chart, args) { + var area = chart.chartArea; + var ctx = chart.ctx; + var source = args.meta.$filler; + if (!source || source.fill === false) { + return; + } + var target = getTarget(source); + var line = source.line, + scale = source.scale; + var lineOpts = line.options; + var fillOption = lineOpts.fill; + var color = lineOpts.backgroundColor; + var _ref3 = fillOption || {}, + _ref3$above = _ref3.above, + above = _ref3$above === void 0 ? color : _ref3$above, + _ref3$below = _ref3.below, + below = _ref3$below === void 0 ? color : _ref3$below; + if (target && line.points.length) { + clipArea(ctx, area); + doFill(ctx, { + line: line, + target: target, + above: above, + below: below, + area: area, + scale: scale + }); + unclipArea(ctx); + } + }, + defaults: { + propagate: true + } +}; + +function getBoxWidth(labelOpts, fontSize) { + var boxWidth = labelOpts.boxWidth; + return labelOpts.usePointStyle && boxWidth > fontSize || isNullOrUndef(boxWidth) ? fontSize : boxWidth; +} +function getBoxHeight(labelOpts, fontSize) { + var boxHeight = labelOpts.boxHeight; + return labelOpts.usePointStyle && boxHeight > fontSize || isNullOrUndef(boxHeight) ? fontSize : boxHeight; +} +var Legend = function (_Element) { + _inheritsLoose(Legend, _Element); + function Legend(config) { + var _this; + _this = _Element.call(this) || this; + _extends(_assertThisInitialized(_this), config); + _this.legendHitBoxes = []; + _this._hoveredItem = null; + _this.doughnutMode = false; + _this.chart = config.chart; + _this.options = config.options; + _this.ctx = config.ctx; + _this.legendItems = undefined; + _this.columnWidths = undefined; + _this.columnHeights = undefined; + _this.lineWidths = undefined; + _this._minSize = undefined; + _this.maxHeight = undefined; + _this.maxWidth = undefined; + _this.top = undefined; + _this.bottom = undefined; + _this.left = undefined; + _this.right = undefined; + _this.height = undefined; + _this.width = undefined; + _this._margins = undefined; + _this.paddingTop = undefined; + _this.paddingBottom = undefined; + _this.paddingLeft = undefined; + _this.paddingRight = undefined; + _this.position = undefined; + _this.weight = undefined; + _this.fullWidth = undefined; + return _this; + } + var _proto = Legend.prototype; + _proto.beforeUpdate = function beforeUpdate() {}; + _proto.update = function update(maxWidth, maxHeight, margins) { + var me = this; + me.beforeUpdate(); + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me._margins = margins; + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + me.beforeBuildLabels(); + me.buildLabels(); + me.afterBuildLabels(); + me.beforeFit(); + me.fit(); + me.afterFit(); + me.afterUpdate(); + }; + _proto.afterUpdate = function afterUpdate() {}; + _proto.beforeSetDimensions = function beforeSetDimensions() {}; + _proto.setDimensions = function setDimensions() { + var me = this; + if (me.isHorizontal()) { + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + me.top = 0; + me.bottom = me.height; + } + me.paddingLeft = 0; + me.paddingTop = 0; + me.paddingRight = 0; + me.paddingBottom = 0; + me._minSize = { + width: 0, + height: 0 + }; + }; + _proto.afterSetDimensions = function afterSetDimensions() {}; + _proto.beforeBuildLabels = function beforeBuildLabels() {}; + _proto.buildLabels = function buildLabels() { + var me = this; + var labelOpts = me.options.labels || {}; + var legendItems = callback(labelOpts.generateLabels, [me.chart], me) || []; + if (labelOpts.filter) { + legendItems = legendItems.filter(function (item) { + return labelOpts.filter(item, me.chart.data); + }); + } + if (me.options.reverse) { + legendItems.reverse(); + } + me.legendItems = legendItems; + }; + _proto.afterBuildLabels = function afterBuildLabels() {}; + _proto.beforeFit = function beforeFit() {}; + _proto.fit = function fit() { + var me = this; + var opts = me.options; + var labelOpts = opts.labels; + var display = opts.display; + var ctx = me.ctx; + var labelFont = toFont(labelOpts.font, me.chart.options.font); + var fontSize = labelFont.size; + var boxWidth = getBoxWidth(labelOpts, fontSize); + var boxHeight = getBoxHeight(labelOpts, fontSize); + var itemHeight = Math.max(boxHeight, fontSize); + var hitboxes = me.legendHitBoxes = []; + var minSize = me._minSize; + var isHorizontal = me.isHorizontal(); + var titleHeight = me._computeTitleHeight(); + if (isHorizontal) { + minSize.width = me.maxWidth; + minSize.height = display ? 10 : 0; + } else { + minSize.width = display ? 10 : 0; + minSize.height = me.maxHeight; + } + if (!display) { + me.width = minSize.width = me.height = minSize.height = 0; + return; + } + ctx.font = labelFont.string; + if (isHorizontal) { + var lineWidths = me.lineWidths = [0]; + var totalHeight = titleHeight; + ctx.textAlign = 'left'; + ctx.textBaseline = 'middle'; + me.legendItems.forEach(function (legendItem, i) { + var width = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width; + if (i === 0 || lineWidths[lineWidths.length - 1] + width + 2 * labelOpts.padding > minSize.width) { + totalHeight += itemHeight + labelOpts.padding; + lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0; + } + hitboxes[i] = { + left: 0, + top: 0, + width: width, + height: itemHeight + }; + lineWidths[lineWidths.length - 1] += width + labelOpts.padding; + }); + minSize.height += totalHeight; + } else { + var vPadding = labelOpts.padding; + var columnWidths = me.columnWidths = []; + var columnHeights = me.columnHeights = []; + var totalWidth = labelOpts.padding; + var currentColWidth = 0; + var currentColHeight = 0; + var heightLimit = minSize.height - titleHeight; + me.legendItems.forEach(function (legendItem, i) { + var itemWidth = boxWidth + fontSize / 2 + ctx.measureText(legendItem.text).width; + if (i > 0 && currentColHeight + fontSize + 2 * vPadding > heightLimit) { + totalWidth += currentColWidth + labelOpts.padding; + columnWidths.push(currentColWidth); + columnHeights.push(currentColHeight); + currentColWidth = 0; + currentColHeight = 0; + } + currentColWidth = Math.max(currentColWidth, itemWidth); + currentColHeight += fontSize + vPadding; + hitboxes[i] = { + left: 0, + top: 0, + width: itemWidth, + height: itemHeight + }; + }); + totalWidth += currentColWidth; + columnWidths.push(currentColWidth); + columnHeights.push(currentColHeight); + minSize.width += totalWidth; + } + me.width = minSize.width; + me.height = minSize.height; + }; + _proto.afterFit = function afterFit() {} + ; + _proto.isHorizontal = function isHorizontal() { + return this.options.position === 'top' || this.options.position === 'bottom'; + } + ; + _proto.draw = function draw() { + var me = this; + var opts = me.options; + var labelOpts = opts.labels; + var defaultColor = defaults.color; + var legendHeight = me.height; + var columnHeights = me.columnHeights; + var legendWidth = me.width; + var lineWidths = me.lineWidths; + if (!opts.display) { + return; + } + me.drawTitle(); + var rtlHelper = getRtlAdapter(opts.rtl, me.left, me._minSize.width); + var ctx = me.ctx; + var labelFont = toFont(labelOpts.font, me.chart.options.font); + var fontColor = labelFont.color; + var fontSize = labelFont.size; + var cursor; + ctx.textAlign = rtlHelper.textAlign('left'); + ctx.textBaseline = 'middle'; + ctx.lineWidth = 0.5; + ctx.strokeStyle = fontColor; + ctx.fillStyle = fontColor; + ctx.font = labelFont.string; + var boxWidth = getBoxWidth(labelOpts, fontSize); + var boxHeight = getBoxHeight(labelOpts, fontSize); + var height = Math.max(fontSize, boxHeight); + var hitboxes = me.legendHitBoxes; + var drawLegendBox = function drawLegendBox(x, y, legendItem) { + if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) { + return; + } + ctx.save(); + var lineWidth = valueOrDefault(legendItem.lineWidth, 1); + ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor); + ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt'); + ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0); + ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter'); + ctx.lineWidth = lineWidth; + ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor); + if (ctx.setLineDash) { + ctx.setLineDash(valueOrDefault(legendItem.lineDash, [])); + } + if (labelOpts && labelOpts.usePointStyle) { + var drawOptions = { + radius: boxWidth * Math.SQRT2 / 2, + pointStyle: legendItem.pointStyle, + rotation: legendItem.rotation, + borderWidth: lineWidth + }; + var centerX = rtlHelper.xPlus(x, boxWidth / 2); + var centerY = y + fontSize / 2; + drawPoint(ctx, drawOptions, centerX, centerY); + } else { + var yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0); + ctx.fillRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight); + if (lineWidth !== 0) { + ctx.strokeRect(rtlHelper.leftForLtr(x, boxWidth), yBoxTop, boxWidth, boxHeight); + } + } + ctx.restore(); + }; + var fillText = function fillText(x, y, legendItem, textWidth) { + var halfFontSize = fontSize / 2; + var xLeft = rtlHelper.xPlus(x, boxWidth + halfFontSize); + var yMiddle = y + height / 2; + ctx.fillText(legendItem.text, xLeft, yMiddle); + if (legendItem.hidden) { + ctx.beginPath(); + ctx.lineWidth = 2; + ctx.moveTo(xLeft, yMiddle); + ctx.lineTo(rtlHelper.xPlus(xLeft, textWidth), yMiddle); + ctx.stroke(); + } + }; + var alignmentOffset = function alignmentOffset(dimension, blockSize) { + switch (opts.align) { + case 'start': + return labelOpts.padding; + case 'end': + return dimension - blockSize; + default: + return (dimension - blockSize + labelOpts.padding) / 2; + } + }; + var isHorizontal = me.isHorizontal(); + var titleHeight = this._computeTitleHeight(); + if (isHorizontal) { + cursor = { + x: me.left + alignmentOffset(legendWidth, lineWidths[0]), + y: me.top + labelOpts.padding + titleHeight, + line: 0 + }; + } else { + cursor = { + x: me.left + labelOpts.padding, + y: me.top + alignmentOffset(legendHeight, columnHeights[0]) + titleHeight, + line: 0 + }; + } + overrideTextDirection(me.ctx, opts.textDirection); + var itemHeight = height + labelOpts.padding; + me.legendItems.forEach(function (legendItem, i) { + var textWidth = ctx.measureText(legendItem.text).width; + var width = boxWidth + fontSize / 2 + textWidth; + var x = cursor.x; + var y = cursor.y; + rtlHelper.setWidth(me._minSize.width); + if (isHorizontal) { + if (i > 0 && x + width + labelOpts.padding > me.left + me._minSize.width) { + y = cursor.y += itemHeight; + cursor.line++; + x = cursor.x = me.left + alignmentOffset(legendWidth, lineWidths[cursor.line]); + } + } else if (i > 0 && y + itemHeight > me.top + me._minSize.height) { + x = cursor.x = x + me.columnWidths[cursor.line] + labelOpts.padding; + cursor.line++; + y = cursor.y = me.top + alignmentOffset(legendHeight, columnHeights[cursor.line]); + } + var realX = rtlHelper.x(x); + drawLegendBox(realX, y, legendItem); + hitboxes[i].left = rtlHelper.leftForLtr(realX, hitboxes[i].width); + hitboxes[i].top = y; + fillText(realX, y, legendItem, textWidth); + if (isHorizontal) { + cursor.x += width + labelOpts.padding; + } else { + cursor.y += itemHeight; + } + }); + restoreTextDirection(me.ctx, opts.textDirection); + } + ; + _proto.drawTitle = function drawTitle() { + var me = this; + var opts = me.options; + var titleOpts = opts.title; + var titleFont = toFont(titleOpts.font, me.chart.options.font); + var titlePadding = toPadding(titleOpts.padding); + if (!titleOpts.display) { + return; + } + var rtlHelper = getRtlAdapter(opts.rtl, me.left, me._minSize.width); + var ctx = me.ctx; + var position = titleOpts.position; + var x, textAlign; + var halfFontSize = titleFont.size / 2; + var y = me.top + titlePadding.top + halfFontSize; + var left = me.left; + var maxWidth = me.width; + if (this.isHorizontal()) { + maxWidth = Math.max.apply(Math, me.lineWidths); + switch (opts.align) { + case 'start': + break; + case 'end': + left = me.right - maxWidth; + break; + default: + left = (me.left + me.right) / 2 - maxWidth / 2; + break; + } + } else { + var maxHeight = Math.max.apply(Math, me.columnHeights); + switch (opts.align) { + case 'start': + break; + case 'end': + y += me.height - maxHeight; + break; + default: + y += (me.height - maxHeight) / 2; + break; + } + } + switch (position) { + case 'start': + x = left; + textAlign = 'left'; + break; + case 'end': + x = left + maxWidth; + textAlign = 'right'; + break; + default: + x = left + maxWidth / 2; + textAlign = 'center'; + break; + } + ctx.textAlign = rtlHelper.textAlign(textAlign); + ctx.textBaseline = 'middle'; + ctx.strokeStyle = titleFont.color; + ctx.fillStyle = titleFont.color; + ctx.font = titleFont.string; + ctx.fillText(titleOpts.text, x, y); + } + ; + _proto._computeTitleHeight = function _computeTitleHeight() { + var titleOpts = this.options.title; + var titleFont = toFont(titleOpts.font, this.chart.options.font); + var titlePadding = toPadding(titleOpts.padding); + return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0; + } + ; + _proto._getLegendItemAt = function _getLegendItemAt(x, y) { + var me = this; + var i, hitBox, lh; + if (x >= me.left && x <= me.right && y >= me.top && y <= me.bottom) { + lh = me.legendHitBoxes; + for (i = 0; i < lh.length; ++i) { + hitBox = lh[i]; + if (x >= hitBox.left && x <= hitBox.left + hitBox.width && y >= hitBox.top && y <= hitBox.top + hitBox.height) { + return me.legendItems[i]; + } + } + } + return null; + } + ; + _proto.handleEvent = function handleEvent(e) { + var me = this; + var opts = me.options; + var type = e.type === 'mouseup' ? 'click' : e.type; + if (type === 'mousemove') { + if (!opts.onHover && !opts.onLeave) { + return; + } + } else if (type === 'click') { + if (!opts.onClick) { + return; + } + } else { + return; + } + var hoveredItem = me._getLegendItemAt(e.x, e.y); + if (type === 'click') { + if (hoveredItem) { + callback(opts.onClick, [e, hoveredItem, me], me); + } + } else { + if (opts.onLeave && hoveredItem !== me._hoveredItem) { + if (me._hoveredItem) { + callback(opts.onLeave, [e, me._hoveredItem, me], me); + } + me._hoveredItem = hoveredItem; + } + if (hoveredItem) { + callback(opts.onHover, [e, hoveredItem, me], me); + } + } + }; + return Legend; +}(Element$1); +function resolveOptions(options) { + return options !== false && merge({}, [defaults.plugins.legend, options]); +} +function createNewLegendAndAttach(chart, legendOpts) { + var legend = new Legend({ + ctx: chart.ctx, + options: legendOpts, + chart: chart + }); + layouts.configure(chart, legend, legendOpts); + layouts.addBox(chart, legend); + chart.legend = legend; +} +var plugin_legend = { + id: 'legend', + _element: Legend, + beforeInit: function beforeInit(chart) { + var legendOpts = resolveOptions(chart.options.legend); + if (legendOpts) { + createNewLegendAndAttach(chart, legendOpts); + } + }, + beforeUpdate: function beforeUpdate(chart) { + var legendOpts = resolveOptions(chart.options.legend); + var legend = chart.legend; + if (legendOpts) { + if (legend) { + layouts.configure(chart, legend, legendOpts); + legend.options = legendOpts; + } else { + createNewLegendAndAttach(chart, legendOpts); + } + } else if (legend) { + layouts.removeBox(chart, legend); + delete chart.legend; + } + }, + afterUpdate: function afterUpdate(chart) { + if (chart.legend) { + chart.legend.buildLabels(); + } + }, + afterEvent: function afterEvent(chart, e) { + var legend = chart.legend; + if (legend) { + legend.handleEvent(e); + } + }, + defaults: { + display: true, + position: 'top', + align: 'center', + fullWidth: true, + reverse: false, + weight: 1000, + onClick: function onClick(e, legendItem, legend) { + var index = legendItem.datasetIndex; + var ci = legend.chart; + if (ci.isDatasetVisible(index)) { + ci.hide(index); + legendItem.hidden = true; + } else { + ci.show(index); + legendItem.hidden = false; + } + }, + onHover: null, + onLeave: null, + labels: { + boxWidth: 40, + padding: 10, + generateLabels: function generateLabels(chart) { + var datasets = chart.data.datasets; + var options = chart.options.legend || {}; + var usePointStyle = options.labels && options.labels.usePointStyle; + return chart._getSortedDatasetMetas().map(function (meta) { + var style = meta.controller.getStyle(usePointStyle ? 0 : undefined); + return { + text: datasets[meta.index].label, + fillStyle: style.backgroundColor, + hidden: !meta.visible, + lineCap: style.borderCapStyle, + lineDash: style.borderDash, + lineDashOffset: style.borderDashOffset, + lineJoin: style.borderJoinStyle, + lineWidth: style.borderWidth, + strokeStyle: style.borderColor, + pointStyle: style.pointStyle, + rotation: style.rotation, + datasetIndex: meta.index + }; + }, this); + } + }, + title: { + display: false, + position: 'center', + text: '' + } + } +}; + +var Title = function (_Element) { + _inheritsLoose(Title, _Element); + function Title(config) { + var _this; + _this = _Element.call(this) || this; + _extends(_assertThisInitialized(_this), config); + _this.chart = config.chart; + _this.options = config.options; + _this.ctx = config.ctx; + _this._margins = undefined; + _this._padding = undefined; + _this.top = undefined; + _this.bottom = undefined; + _this.left = undefined; + _this.right = undefined; + _this.width = undefined; + _this.height = undefined; + _this.maxWidth = undefined; + _this.maxHeight = undefined; + _this.position = undefined; + _this.weight = undefined; + _this.fullWidth = undefined; + return _this; + } + var _proto = Title.prototype; + _proto.beforeUpdate = function beforeUpdate() {}; + _proto.update = function update(maxWidth, maxHeight, margins) { + var me = this; + me.beforeUpdate(); + me.maxWidth = maxWidth; + me.maxHeight = maxHeight; + me._margins = margins; + me.beforeSetDimensions(); + me.setDimensions(); + me.afterSetDimensions(); + me.beforeBuildLabels(); + me.buildLabels(); + me.afterBuildLabels(); + me.beforeFit(); + me.fit(); + me.afterFit(); + me.afterUpdate(); + }; + _proto.afterUpdate = function afterUpdate() {}; + _proto.beforeSetDimensions = function beforeSetDimensions() {}; + _proto.setDimensions = function setDimensions() { + var me = this; + if (me.isHorizontal()) { + me.width = me.maxWidth; + me.left = 0; + me.right = me.width; + } else { + me.height = me.maxHeight; + me.top = 0; + me.bottom = me.height; + } + }; + _proto.afterSetDimensions = function afterSetDimensions() {}; + _proto.beforeBuildLabels = function beforeBuildLabels() {}; + _proto.buildLabels = function buildLabels() {}; + _proto.afterBuildLabels = function afterBuildLabels() {}; + _proto.beforeFit = function beforeFit() {}; + _proto.fit = function fit() { + var me = this; + var opts = me.options; + var minSize = {}; + var isHorizontal = me.isHorizontal(); + if (!opts.display) { + me.width = minSize.width = me.height = minSize.height = 0; + return; + } + var lineCount = isArray(opts.text) ? opts.text.length : 1; + me._padding = toPadding(opts.padding); + var textSize = lineCount * toFont(opts.font, me.chart.options.font).lineHeight + me._padding.height; + me.width = minSize.width = isHorizontal ? me.maxWidth : textSize; + me.height = minSize.height = isHorizontal ? textSize : me.maxHeight; + }; + _proto.afterFit = function afterFit() {} + ; + _proto.isHorizontal = function isHorizontal() { + var pos = this.options.position; + return pos === 'top' || pos === 'bottom'; + } + ; + _proto.draw = function draw() { + var me = this; + var ctx = me.ctx; + var opts = me.options; + if (!opts.display) { + return; + } + var fontOpts = toFont(opts.font, me.chart.options.font); + var lineHeight = fontOpts.lineHeight; + var offset = lineHeight / 2 + me._padding.top; + var rotation = 0; + var top = me.top; + var left = me.left; + var bottom = me.bottom; + var right = me.right; + var maxWidth, titleX, titleY; + var align; + if (me.isHorizontal()) { + switch (opts.align) { + case 'start': + titleX = left; + align = 'left'; + break; + case 'end': + titleX = right; + align = 'right'; + break; + default: + titleX = left + (right - left) / 2; + align = 'center'; + break; + } + titleY = top + offset; + maxWidth = right - left; + } else { + titleX = opts.position === 'left' ? left + offset : right - offset; + switch (opts.align) { + case 'start': + titleY = opts.position === 'left' ? bottom : top; + align = 'left'; + break; + case 'end': + titleY = opts.position === 'left' ? top : bottom; + align = 'right'; + break; + default: + titleY = top + (bottom - top) / 2; + align = 'center'; + break; + } + maxWidth = bottom - top; + rotation = Math.PI * (opts.position === 'left' ? -0.5 : 0.5); + } + ctx.save(); + ctx.fillStyle = fontOpts.color; + ctx.font = fontOpts.string; + ctx.translate(titleX, titleY); + ctx.rotate(rotation); + ctx.textAlign = align; + ctx.textBaseline = 'middle'; + var text = opts.text; + if (isArray(text)) { + var y = 0; + for (var i = 0; i < text.length; ++i) { + ctx.fillText(text[i], 0, y, maxWidth); + y += lineHeight; + } + } else { + ctx.fillText(text, 0, 0, maxWidth); + } + ctx.restore(); + }; + return Title; +}(Element$1); +function createNewTitleBlockAndAttach(chart, titleOpts) { + var title = new Title({ + ctx: chart.ctx, + options: titleOpts, + chart: chart + }); + layouts.configure(chart, title, titleOpts); + layouts.addBox(chart, title); + chart.titleBlock = title; +} +var plugin_title = { + id: 'title', + _element: Title, + beforeInit: function beforeInit(chart) { + var titleOpts = chart.options.title; + if (titleOpts) { + createNewTitleBlockAndAttach(chart, titleOpts); + } + }, + beforeUpdate: function beforeUpdate(chart) { + var titleOpts = chart.options.title; + var titleBlock = chart.titleBlock; + if (titleOpts) { + mergeIf(titleOpts, defaults.plugins.title); + if (titleBlock) { + layouts.configure(chart, titleBlock, titleOpts); + titleBlock.options = titleOpts; + } else { + createNewTitleBlockAndAttach(chart, titleOpts); + } + } else if (titleBlock) { + layouts.removeBox(chart, titleBlock); + delete chart.titleBlock; + } + }, + defaults: { + align: 'center', + display: false, + font: { + style: 'bold' + }, + fullWidth: true, + padding: 10, + position: 'top', + text: '', + weight: 2000 + } +}; + +var positioners = { + average: function average(items) { + if (!items.length) { + return false; + } + var i, len; + var x = 0; + var y = 0; + var count = 0; + for (i = 0, len = items.length; i < len; ++i) { + var el = items[i].element; + if (el && el.hasValue()) { + var pos = el.tooltipPosition(); + x += pos.x; + y += pos.y; + ++count; + } + } + return { + x: x / count, + y: y / count + }; + }, + nearest: function nearest(items, eventPosition) { + var x = eventPosition.x; + var y = eventPosition.y; + var minDistance = Number.POSITIVE_INFINITY; + var i, len, nearestElement; + for (i = 0, len = items.length; i < len; ++i) { + var el = items[i].element; + if (el && el.hasValue()) { + var center = el.getCenterPoint(); + var d = distanceBetweenPoints(eventPosition, center); + if (d < minDistance) { + minDistance = d; + nearestElement = el; + } + } + } + if (nearestElement) { + var tp = nearestElement.tooltipPosition(); + x = tp.x; + y = tp.y; + } + return { + x: x, + y: y + }; + } +}; +function pushOrConcat(base, toPush) { + if (toPush) { + if (isArray(toPush)) { + Array.prototype.push.apply(base, toPush); + } else { + base.push(toPush); + } + } + return base; +} +function splitNewlines(str) { + if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) { + return str.split('\n'); + } + return str; +} +function createTooltipItem(chart, item) { + var element = item.element, + datasetIndex = item.datasetIndex, + index = item.index; + var controller = chart.getDatasetMeta(datasetIndex).controller; + var _controller$getLabelA = controller.getLabelAndValue(index), + label = _controller$getLabelA.label, + value = _controller$getLabelA.value; + return { + chart: chart, + label: label, + dataPoint: controller.getParsed(index), + formattedValue: value, + dataset: controller.getDataset(), + dataIndex: index, + datasetIndex: datasetIndex, + element: element + }; +} +function resolveOptions$1(options, fallbackFont) { + options = merge({}, [defaults.plugins.tooltip, options]); + options.bodyFont = toFont(options.bodyFont, fallbackFont); + options.titleFont = toFont(options.titleFont, fallbackFont); + options.footerFont = toFont(options.footerFont, fallbackFont); + options.boxHeight = valueOrDefault(options.boxHeight, options.bodyFont.size); + options.boxWidth = valueOrDefault(options.boxWidth, options.bodyFont.size); + return options; +} +function getTooltipSize(tooltip) { + var ctx = tooltip._chart.ctx; + var body = tooltip.body, + footer = tooltip.footer, + options = tooltip.options, + title = tooltip.title; + var bodyFont = options.bodyFont, + footerFont = options.footerFont, + titleFont = options.titleFont, + boxWidth = options.boxWidth, + boxHeight = options.boxHeight; + var titleLineCount = title.length; + var footerLineCount = footer.length; + var bodyLineItemCount = body.length; + var height = options.yPadding * 2; + var width = 0; + var combinedBodyLength = body.reduce(function (count, bodyItem) { + return count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length; + }, 0); + combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length; + if (titleLineCount) { + height += titleLineCount * titleFont.size + (titleLineCount - 1) * options.titleSpacing + options.titleMarginBottom; + } + if (combinedBodyLength) { + var bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.size) : bodyFont.size; + height += bodyLineItemCount * bodyLineHeight + (combinedBodyLength - bodyLineItemCount) * bodyFont.size + (combinedBodyLength - 1) * options.bodySpacing; + } + if (footerLineCount) { + height += options.footerMarginTop + footerLineCount * footerFont.size + (footerLineCount - 1) * options.footerSpacing; + } + var widthPadding = 0; + var maxLineWidth = function maxLineWidth(line) { + width = Math.max(width, ctx.measureText(line).width + widthPadding); + }; + ctx.save(); + ctx.font = titleFont.string; + each(tooltip.title, maxLineWidth); + ctx.font = bodyFont.string; + each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth); + widthPadding = options.displayColors ? boxWidth + 2 : 0; + each(body, function (bodyItem) { + each(bodyItem.before, maxLineWidth); + each(bodyItem.lines, maxLineWidth); + each(bodyItem.after, maxLineWidth); + }); + widthPadding = 0; + ctx.font = footerFont.string; + each(tooltip.footer, maxLineWidth); + ctx.restore(); + width += 2 * options.xPadding; + return { + width: width, + height: height + }; +} +function determineAlignment(chart, options, size) { + var x = size.x, + y = size.y, + width = size.width, + height = size.height; + var chartArea = chart.chartArea; + var xAlign = 'center'; + var yAlign = 'center'; + if (y < height) { + yAlign = 'top'; + } else if (y > chart.height - height) { + yAlign = 'bottom'; + } + var lf, rf; + var midX = (chartArea.left + chartArea.right) / 2; + var midY = (chartArea.top + chartArea.bottom) / 2; + if (yAlign === 'center') { + lf = function lf(value) { + return value <= midX; + }; + rf = function rf(value) { + return value > midX; + }; + } else { + lf = function lf(value) { + return value <= width / 2; + }; + rf = function rf(value) { + return value >= chart.width - width / 2; + }; + } + var olf = function olf(value) { + return value + width + options.caretSize + options.caretPadding > chart.width; + }; + var orf = function orf(value) { + return value - width - options.caretSize - options.caretPadding < 0; + }; + var yf = function yf(value) { + return value <= midY ? 'top' : 'bottom'; + }; + if (lf(x)) { + xAlign = 'left'; + if (olf(x)) { + xAlign = 'center'; + yAlign = yf(y); + } + } else if (rf(x)) { + xAlign = 'right'; + if (orf(x)) { + xAlign = 'center'; + yAlign = yf(y); + } + } + return { + xAlign: options.xAlign ? options.xAlign : xAlign, + yAlign: options.yAlign ? options.yAlign : yAlign + }; +} +function alignX(size, xAlign, chartWidth) { + var x = size.x, + width = size.width; + if (xAlign === 'right') { + x -= width; + } else if (xAlign === 'center') { + x -= width / 2; + if (x + width > chartWidth) { + x = chartWidth - width; + } + if (x < 0) { + x = 0; + } + } + return x; +} +function alignY(size, yAlign, paddingAndSize) { + var y = size.y, + height = size.height; + if (yAlign === 'top') { + y += paddingAndSize; + } else if (yAlign === 'bottom') { + y -= height + paddingAndSize; + } else { + y -= height / 2; + } + return y; +} +function getBackgroundPoint(options, size, alignment, chart) { + var caretSize = options.caretSize, + caretPadding = options.caretPadding, + cornerRadius = options.cornerRadius; + var xAlign = alignment.xAlign, + yAlign = alignment.yAlign; + var paddingAndSize = caretSize + caretPadding; + var radiusAndPadding = cornerRadius + caretPadding; + var x = alignX(size, xAlign, chart.width); + var y = alignY(size, yAlign, paddingAndSize); + if (yAlign === 'center') { + if (xAlign === 'left') { + x += paddingAndSize; + } else if (xAlign === 'right') { + x -= paddingAndSize; + } + } else if (xAlign === 'left') { + x -= radiusAndPadding; + } else if (xAlign === 'right') { + x += radiusAndPadding; + } + return { + x: x, + y: y + }; +} +function getAlignedX(tooltip, align) { + var options = tooltip.options; + return align === 'center' ? tooltip.x + tooltip.width / 2 : align === 'right' ? tooltip.x + tooltip.width - options.xPadding : tooltip.x + options.xPadding; +} +function getBeforeAfterBodyLines(callback) { + return pushOrConcat([], splitNewlines(callback)); +} +var Tooltip = function (_Element) { + _inheritsLoose(Tooltip, _Element); + function Tooltip(config) { + var _this; + _this = _Element.call(this) || this; + _this.opacity = 0; + _this._active = []; + _this._chart = config._chart; + _this._eventPosition = undefined; + _this._size = undefined; + _this._cachedAnimations = undefined; + _this.$animations = undefined; + _this.options = undefined; + _this.dataPoints = undefined; + _this.title = undefined; + _this.beforeBody = undefined; + _this.body = undefined; + _this.afterBody = undefined; + _this.footer = undefined; + _this.xAlign = undefined; + _this.yAlign = undefined; + _this.x = undefined; + _this.y = undefined; + _this.height = undefined; + _this.width = undefined; + _this.caretX = undefined; + _this.caretY = undefined; + _this.labelColors = undefined; + _this.labelTextColors = undefined; + _this.initialize(); + return _this; + } + var _proto = Tooltip.prototype; + _proto.initialize = function initialize() { + var me = this; + var chartOpts = me._chart.options; + me.options = resolveOptions$1(chartOpts.tooltips, chartOpts.font); + } + ; + _proto._resolveAnimations = function _resolveAnimations() { + var me = this; + var cached = me._cachedAnimations; + if (cached) { + return cached; + } + var chart = me._chart; + var options = me.options; + var opts = options.enabled && chart.options.animation && options.animation; + var animations = new Animations(me._chart, opts); + me._cachedAnimations = Object.freeze(animations); + return animations; + }; + _proto.getTitle = function getTitle(context) { + var me = this; + var opts = me.options; + var callbacks = opts.callbacks; + var beforeTitle = callbacks.beforeTitle.apply(me, [context]); + var title = callbacks.title.apply(me, [context]); + var afterTitle = callbacks.afterTitle.apply(me, [context]); + var lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeTitle)); + lines = pushOrConcat(lines, splitNewlines(title)); + lines = pushOrConcat(lines, splitNewlines(afterTitle)); + return lines; + }; + _proto.getBeforeBody = function getBeforeBody(tooltipItems) { + return getBeforeAfterBodyLines(this.options.callbacks.beforeBody.apply(this, [tooltipItems])); + }; + _proto.getBody = function getBody(tooltipItems) { + var me = this; + var callbacks = me.options.callbacks; + var bodyItems = []; + each(tooltipItems, function (context) { + var bodyItem = { + before: [], + lines: [], + after: [] + }; + pushOrConcat(bodyItem.before, splitNewlines(callbacks.beforeLabel.call(me, context))); + pushOrConcat(bodyItem.lines, callbacks.label.call(me, context)); + pushOrConcat(bodyItem.after, splitNewlines(callbacks.afterLabel.call(me, context))); + bodyItems.push(bodyItem); + }); + return bodyItems; + }; + _proto.getAfterBody = function getAfterBody(tooltipItems) { + return getBeforeAfterBodyLines(this.options.callbacks.afterBody.apply(this, [tooltipItems])); + } + ; + _proto.getFooter = function getFooter(tooltipItems) { + var me = this; + var callbacks = me.options.callbacks; + var beforeFooter = callbacks.beforeFooter.apply(me, [tooltipItems]); + var footer = callbacks.footer.apply(me, [tooltipItems]); + var afterFooter = callbacks.afterFooter.apply(me, [tooltipItems]); + var lines = []; + lines = pushOrConcat(lines, splitNewlines(beforeFooter)); + lines = pushOrConcat(lines, splitNewlines(footer)); + lines = pushOrConcat(lines, splitNewlines(afterFooter)); + return lines; + } + ; + _proto._createItems = function _createItems() { + var me = this; + var active = me._active; + var options = me.options; + var data = me._chart.data; + var labelColors = []; + var labelTextColors = []; + var tooltipItems = []; + var i, len; + for (i = 0, len = active.length; i < len; ++i) { + tooltipItems.push(createTooltipItem(me._chart, active[i])); + } + if (options.filter) { + tooltipItems = tooltipItems.filter(function (element, index, array) { + return options.filter(element, index, array, data); + }); + } + if (options.itemSort) { + tooltipItems = tooltipItems.sort(function (a, b) { + return options.itemSort(a, b, data); + }); + } + each(tooltipItems, function (context) { + labelColors.push(options.callbacks.labelColor.call(me, context)); + labelTextColors.push(options.callbacks.labelTextColor.call(me, context)); + }); + me.labelColors = labelColors; + me.labelTextColors = labelTextColors; + me.dataPoints = tooltipItems; + return tooltipItems; + }; + _proto.update = function update(changed) { + var me = this; + var options = me.options; + var active = me._active; + var properties; + if (!active.length) { + if (me.opacity !== 0) { + properties = { + opacity: 0 + }; + } + } else { + var position = positioners[options.position].call(me, active, me._eventPosition); + var tooltipItems = me._createItems(); + me.title = me.getTitle(tooltipItems); + me.beforeBody = me.getBeforeBody(tooltipItems); + me.body = me.getBody(tooltipItems); + me.afterBody = me.getAfterBody(tooltipItems); + me.footer = me.getFooter(tooltipItems); + var size = me._size = getTooltipSize(me); + var positionAndSize = _extends({}, position, size); + var alignment = determineAlignment(me._chart, options, positionAndSize); + var backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, me._chart); + me.xAlign = alignment.xAlign; + me.yAlign = alignment.yAlign; + properties = { + opacity: 1, + x: backgroundPoint.x, + y: backgroundPoint.y, + width: size.width, + height: size.height, + caretX: position.x, + caretY: position.y + }; + } + if (properties) { + me._resolveAnimations().update(me, properties); + } + if (changed && options.custom) { + options.custom.call(me, { + chart: me._chart, + tooltip: me + }); + } + }; + _proto.drawCaret = function drawCaret(tooltipPoint, ctx, size) { + var caretPosition = this.getCaretPosition(tooltipPoint, size); + ctx.lineTo(caretPosition.x1, caretPosition.y1); + ctx.lineTo(caretPosition.x2, caretPosition.y2); + ctx.lineTo(caretPosition.x3, caretPosition.y3); + }; + _proto.getCaretPosition = function getCaretPosition(tooltipPoint, size) { + var xAlign = this.xAlign, + yAlign = this.yAlign, + options = this.options; + var cornerRadius = options.cornerRadius, + caretSize = options.caretSize; + var ptX = tooltipPoint.x, + ptY = tooltipPoint.y; + var width = size.width, + height = size.height; + var x1, x2, x3, y1, y2, y3; + if (yAlign === 'center') { + y2 = ptY + height / 2; + if (xAlign === 'left') { + x1 = ptX; + x2 = x1 - caretSize; + y1 = y2 + caretSize; + y3 = y2 - caretSize; + } else { + x1 = ptX + width; + x2 = x1 + caretSize; + y1 = y2 - caretSize; + y3 = y2 + caretSize; + } + x3 = x1; + } else { + if (xAlign === 'left') { + x2 = ptX + cornerRadius + caretSize; + } else if (xAlign === 'right') { + x2 = ptX + width - cornerRadius - caretSize; + } else { + x2 = this.caretX; + } + if (yAlign === 'top') { + y1 = ptY; + y2 = y1 - caretSize; + x1 = x2 - caretSize; + x3 = x2 + caretSize; + } else { + y1 = ptY + height; + y2 = y1 + caretSize; + x1 = x2 + caretSize; + x3 = x2 - caretSize; + } + y3 = y1; + } + return { + x1: x1, + x2: x2, + x3: x3, + y1: y1, + y2: y2, + y3: y3 + }; + }; + _proto.drawTitle = function drawTitle(pt, ctx) { + var me = this; + var options = me.options; + var title = me.title; + var length = title.length; + var titleFont, titleSpacing, i; + if (length) { + var rtlHelper = getRtlAdapter(options.rtl, me.x, me.width); + pt.x = getAlignedX(me, options.titleAlign); + ctx.textAlign = rtlHelper.textAlign(options.titleAlign); + ctx.textBaseline = 'middle'; + titleFont = options.titleFont; + titleSpacing = options.titleSpacing; + ctx.fillStyle = options.titleFont.color; + ctx.font = titleFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.size / 2); + pt.y += titleFont.size + titleSpacing; + if (i + 1 === length) { + pt.y += options.titleMarginBottom - titleSpacing; + } + } + } + } + ; + _proto._drawColorBox = function _drawColorBox(ctx, pt, i, rtlHelper) { + var me = this; + var options = me.options; + var labelColors = me.labelColors[i]; + var boxHeight = options.boxHeight, + boxWidth = options.boxWidth, + bodyFont = options.bodyFont; + var colorX = getAlignedX(me, 'left'); + var rtlColorX = rtlHelper.x(colorX); + var yOffSet = boxHeight < bodyFont.size ? (bodyFont.size - boxHeight) / 2 : 0; + var colorY = pt.y + yOffSet; + ctx.fillStyle = options.multiKeyBackground; + ctx.fillRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight); + ctx.lineWidth = 1; + ctx.strokeStyle = labelColors.borderColor; + ctx.strokeRect(rtlHelper.leftForLtr(rtlColorX, boxWidth), colorY, boxWidth, boxHeight); + ctx.fillStyle = labelColors.backgroundColor; + ctx.fillRect(rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - 2), colorY + 1, boxWidth - 2, boxHeight - 2); + ctx.fillStyle = me.labelTextColors[i]; + }; + _proto.drawBody = function drawBody(pt, ctx) { + var me = this; + var body = me.body, + options = me.options; + var bodyFont = options.bodyFont, + bodySpacing = options.bodySpacing, + bodyAlign = options.bodyAlign, + displayColors = options.displayColors, + boxHeight = options.boxHeight, + boxWidth = options.boxWidth; + var bodyLineHeight = bodyFont.size; + var xLinePadding = 0; + var rtlHelper = getRtlAdapter(options.rtl, me.x, me.width); + var fillLineOfText = function fillLineOfText(line) { + ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2); + pt.y += bodyLineHeight + bodySpacing; + }; + var bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign); + var bodyItem, textColor, lines, i, j, ilen, jlen; + ctx.textAlign = bodyAlign; + ctx.textBaseline = 'middle'; + ctx.font = bodyFont.string; + pt.x = getAlignedX(me, bodyAlignForCalculation); + ctx.fillStyle = bodyFont.color; + each(me.beforeBody, fillLineOfText); + xLinePadding = displayColors && bodyAlignForCalculation !== 'right' ? bodyAlign === 'center' ? boxWidth / 2 + 1 : boxWidth + 2 : 0; + for (i = 0, ilen = body.length; i < ilen; ++i) { + bodyItem = body[i]; + textColor = me.labelTextColors[i]; + ctx.fillStyle = textColor; + each(bodyItem.before, fillLineOfText); + lines = bodyItem.lines; + if (displayColors && lines.length) { + me._drawColorBox(ctx, pt, i, rtlHelper); + bodyLineHeight = Math.max(bodyFont.size, boxHeight); + } + for (j = 0, jlen = lines.length; j < jlen; ++j) { + fillLineOfText(lines[j]); + bodyLineHeight = bodyFont.size; + } + each(bodyItem.after, fillLineOfText); + } + xLinePadding = 0; + bodyLineHeight = bodyFont.size; + each(me.afterBody, fillLineOfText); + pt.y -= bodySpacing; + }; + _proto.drawFooter = function drawFooter(pt, ctx) { + var me = this; + var options = me.options; + var footer = me.footer; + var length = footer.length; + var footerFont, i; + if (length) { + var rtlHelper = getRtlAdapter(options.rtl, me.x, me.width); + pt.x = getAlignedX(me, options.footerAlign); + pt.y += options.footerMarginTop; + ctx.textAlign = rtlHelper.textAlign(options.footerAlign); + ctx.textBaseline = 'middle'; + footerFont = options.footerFont; + ctx.fillStyle = options.footerFont.color; + ctx.font = footerFont.string; + for (i = 0; i < length; ++i) { + ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.size / 2); + pt.y += footerFont.size + options.footerSpacing; + } + } + }; + _proto.drawBackground = function drawBackground(pt, ctx, tooltipSize) { + var xAlign = this.xAlign, + yAlign = this.yAlign, + options = this.options; + var x = pt.x, + y = pt.y; + var width = tooltipSize.width, + height = tooltipSize.height; + var radius = options.cornerRadius; + ctx.fillStyle = options.backgroundColor; + ctx.strokeStyle = options.borderColor; + ctx.lineWidth = options.borderWidth; + ctx.beginPath(); + ctx.moveTo(x + radius, y); + if (yAlign === 'top') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x + width - radius, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius); + if (yAlign === 'center' && xAlign === 'right') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x + width, y + height - radius); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height); + if (yAlign === 'bottom') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x + radius, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius); + if (yAlign === 'center' && xAlign === 'left') { + this.drawCaret(pt, ctx, tooltipSize); + } + ctx.lineTo(x, y + radius); + ctx.quadraticCurveTo(x, y, x + radius, y); + ctx.closePath(); + ctx.fill(); + if (options.borderWidth > 0) { + ctx.stroke(); + } + } + ; + _proto._updateAnimationTarget = function _updateAnimationTarget() { + var me = this; + var chart = me._chart; + var options = me.options; + var anims = me.$animations; + var animX = anims && anims.x; + var animY = anims && anims.y; + if (animX || animY) { + var position = positioners[options.position].call(me, me._active, me._eventPosition); + if (!position) { + return; + } + var size = me._size = getTooltipSize(me); + var positionAndSize = _extends({}, position, me._size); + var alignment = determineAlignment(chart, options, positionAndSize); + var point = getBackgroundPoint(options, positionAndSize, alignment, chart); + if (animX._to !== point.x || animY._to !== point.y) { + me.xAlign = alignment.xAlign; + me.yAlign = alignment.yAlign; + me.width = size.width; + me.height = size.height; + me.caretX = position.x; + me.caretY = position.y; + me._resolveAnimations().update(me, point); + } + } + }; + _proto.draw = function draw(ctx) { + var me = this; + var options = me.options; + var opacity = me.opacity; + if (!opacity) { + return; + } + me._updateAnimationTarget(); + var tooltipSize = { + width: me.width, + height: me.height + }; + var pt = { + x: me.x, + y: me.y + }; + opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity; + var hasTooltipContent = me.title.length || me.beforeBody.length || me.body.length || me.afterBody.length || me.footer.length; + if (options.enabled && hasTooltipContent) { + ctx.save(); + ctx.globalAlpha = opacity; + me.drawBackground(pt, ctx, tooltipSize); + overrideTextDirection(ctx, options.textDirection); + pt.y += options.yPadding; + me.drawTitle(pt, ctx); + me.drawBody(pt, ctx); + me.drawFooter(pt, ctx); + restoreTextDirection(ctx, options.textDirection); + ctx.restore(); + } + } + ; + _proto.handleEvent = function handleEvent(e, replay) { + var me = this; + var options = me.options; + var lastActive = me._active || []; + var changed = false; + var active = []; + if (e.type !== 'mouseout') { + active = me._chart.getElementsAtEventForMode(e, options.mode, options, replay); + if (options.reverse) { + active.reverse(); + } + } + var position = positioners[options.position].call(me, active, e); + var positionChanged = this.caretX !== position.x || this.caretY !== position.y; + changed = replay || !_elementsEqual(active, lastActive) || positionChanged; + if (changed) { + me._active = active; + if (options.enabled || options.custom) { + me._eventPosition = { + x: e.x, + y: e.y + }; + me.update(true); + } + } + return changed; + }; + return Tooltip; +}(Element$1); +Tooltip.positioners = positioners; +var plugin_tooltip = { + id: 'tooltip', + _element: Tooltip, + positioners: positioners, + afterInit: function afterInit(chart) { + var tooltipOpts = chart.options.tooltips; + if (tooltipOpts) { + chart.tooltip = new Tooltip({ + _chart: chart + }); + } + }, + beforeUpdate: function beforeUpdate(chart) { + if (chart.tooltip) { + chart.tooltip.initialize(); + } + }, + reset: function reset(chart) { + if (chart.tooltip) { + chart.tooltip.initialize(); + } + }, + afterDraw: function afterDraw(chart) { + var tooltip = chart.tooltip; + var args = { + tooltip: tooltip + }; + if (chart._plugins.notify(chart, 'beforeTooltipDraw', [args]) === false) { + return; + } + if (tooltip) { + tooltip.draw(chart.ctx); + } + chart._plugins.notify(chart, 'afterTooltipDraw', [args]); + }, + afterEvent: function afterEvent(chart, e, replay) { + if (chart.tooltip) { + var useFinalPosition = replay; + chart.tooltip.handleEvent(e, useFinalPosition); + } + }, + defaults: { + enabled: true, + custom: null, + mode: 'nearest', + position: 'average', + intersect: true, + backgroundColor: 'rgba(0,0,0,0.8)', + titleFont: { + style: 'bold', + color: '#fff' + }, + titleSpacing: 2, + titleMarginBottom: 6, + titleAlign: 'left', + bodySpacing: 2, + bodyFont: { + color: '#fff' + }, + bodyAlign: 'left', + footerSpacing: 2, + footerMarginTop: 6, + footerFont: { + color: '#fff', + style: 'bold' + }, + footerAlign: 'left', + yPadding: 6, + xPadding: 6, + caretPadding: 2, + caretSize: 5, + cornerRadius: 6, + multiKeyBackground: '#fff', + displayColors: true, + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + animation: { + duration: 400, + easing: 'easeOutQuart', + numbers: { + type: 'number', + properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'] + }, + opacity: { + easing: 'linear', + duration: 200 + } + }, + callbacks: { + beforeTitle: noop, + title: function title(tooltipItems) { + if (tooltipItems.length > 0) { + var item = tooltipItems[0]; + var labels = item.chart.data.labels; + var labelCount = labels ? labels.length : 0; + if (item.label) { + return item.label; + } else if (labelCount > 0 && item.dataIndex < labelCount) { + return labels[item.dataIndex]; + } + } + return ''; + }, + afterTitle: noop, + beforeBody: noop, + beforeLabel: noop, + label: function label(tooltipItem) { + var label = tooltipItem.dataset.label || ''; + if (label) { + label += ': '; + } + var value = tooltipItem.formattedValue; + if (!isNullOrUndef(value)) { + label += value; + } + return label; + }, + labelColor: function labelColor(tooltipItem) { + var meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex); + var options = meta.controller.getStyle(tooltipItem.dataIndex); + return { + borderColor: options.borderColor, + backgroundColor: options.backgroundColor + }; + }, + labelTextColor: function labelTextColor() { + return this.options.bodyFont.color; + }, + afterLabel: noop, + afterBody: noop, + beforeFooter: noop, + footer: noop, + afterFooter: noop + } + } +}; + +var plugins = /*#__PURE__*/Object.freeze({ +__proto__: null, +Filler: plugin_filler, +Legend: plugin_legend, +Title: plugin_title, +Tooltip: plugin_tooltip +}); + +var CategoryScale = function (_Scale) { + _inheritsLoose(CategoryScale, _Scale); + function CategoryScale(cfg) { + var _this; + _this = _Scale.call(this, cfg) || this; + _this._startValue = undefined; + _this._valueRange = 0; + return _this; + } + var _proto = CategoryScale.prototype; + _proto.parse = function parse(raw, index) { + var labels = this.getLabels(); + if (labels[index] === raw) { + return index; + } + var first = labels.indexOf(raw); + var last = labels.lastIndexOf(raw); + return first === -1 || first !== last ? index : first; + }; + _proto.determineDataLimits = function determineDataLimits() { + var me = this; + var max = me.getLabels().length - 1; + me.min = Math.max(me._userMin || 0, 0); + me.max = Math.min(me._userMax || max, max); + }; + _proto.buildTicks = function buildTicks() { + var me = this; + var min = me.min; + var max = me.max; + var offset = me.options.offset; + var ticks = []; + var labels = me.getLabels(); + labels = min === 0 && max === labels.length - 1 ? labels : labels.slice(min, max + 1); + me._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1); + me._startValue = me.min - (offset ? 0.5 : 0); + for (var value = min; value <= max; value++) { + ticks.push({ + value: value + }); + } + return ticks; + }; + _proto.getLabelForValue = function getLabelForValue(value) { + var me = this; + var labels = me.getLabels(); + if (value >= 0 && value < labels.length) { + return labels[value]; + } + return value; + } + ; + _proto.configure = function configure() { + var me = this; + _Scale.prototype.configure.call(this); + if (!me.isHorizontal()) { + me._reversePixels = !me._reversePixels; + } + } + ; + _proto.getPixelForValue = function getPixelForValue(value) { + var me = this; + if (typeof value !== 'number') { + value = me.parse(value); + } + return me.getPixelForDecimal((value - me._startValue) / me._valueRange); + } + ; + _proto.getPixelForTick = function getPixelForTick(index) { + var me = this; + var ticks = me.ticks; + if (index < 0 || index > ticks.length - 1) { + return null; + } + return me.getPixelForValue(ticks[index].value); + }; + _proto.getValueForPixel = function getValueForPixel(pixel) { + var me = this; + var value = Math.round(me._startValue + me.getDecimalForPixel(pixel) * me._valueRange); + return Math.min(Math.max(value, 0), me.ticks.length - 1); + }; + _proto.getBasePixel = function getBasePixel() { + return this.bottom; + }; + return CategoryScale; +}(Scale); +CategoryScale.id = 'category'; +CategoryScale.defaults = { + ticks: { + callback: CategoryScale.prototype.getLabelForValue + } +}; + +function niceNum(range) { + var exponent = Math.floor(log10(range)); + var fraction = range / Math.pow(10, exponent); + var niceFraction; + if (fraction <= 1.0) { + niceFraction = 1; + } else if (fraction <= 2) { + niceFraction = 2; + } else if (fraction <= 5) { + niceFraction = 5; + } else { + niceFraction = 10; + } + return niceFraction * Math.pow(10, exponent); +} +function generateTicks(generationOptions, dataRange) { + var ticks = []; + var MIN_SPACING = 1e-14; + var stepSize = generationOptions.stepSize, + min = generationOptions.min, + max = generationOptions.max, + precision = generationOptions.precision; + var unit = stepSize || 1; + var maxNumSpaces = generationOptions.maxTicks - 1; + var rmin = dataRange.min, + rmax = dataRange.max; + var spacing = niceNum((rmax - rmin) / maxNumSpaces / unit) * unit; + var factor, niceMin, niceMax, numSpaces; + if (spacing < MIN_SPACING && isNullOrUndef(min) && isNullOrUndef(max)) { + return [{ + value: rmin + }, { + value: rmax + }]; + } + numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing); + if (numSpaces > maxNumSpaces) { + spacing = niceNum(numSpaces * spacing / maxNumSpaces / unit) * unit; + } + if (stepSize || isNullOrUndef(precision)) { + factor = Math.pow(10, _decimalPlaces(spacing)); + } else { + factor = Math.pow(10, precision); + spacing = Math.ceil(spacing * factor) / factor; + } + niceMin = Math.floor(rmin / spacing) * spacing; + niceMax = Math.ceil(rmax / spacing) * spacing; + if (stepSize && !isNullOrUndef(min) && !isNullOrUndef(max)) { + if (almostWhole((max - min) / stepSize, spacing / 1000)) { + niceMin = min; + niceMax = max; + } + } + numSpaces = (niceMax - niceMin) / spacing; + if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) { + numSpaces = Math.round(numSpaces); + } else { + numSpaces = Math.ceil(numSpaces); + } + niceMin = Math.round(niceMin * factor) / factor; + niceMax = Math.round(niceMax * factor) / factor; + ticks.push({ + value: isNullOrUndef(min) ? niceMin : min + }); + for (var j = 1; j < numSpaces; ++j) { + ticks.push({ + value: Math.round((niceMin + j * spacing) * factor) / factor + }); + } + ticks.push({ + value: isNullOrUndef(max) ? niceMax : max + }); + return ticks; +} +var LinearScaleBase = function (_Scale) { + _inheritsLoose(LinearScaleBase, _Scale); + function LinearScaleBase(cfg) { + var _this; + _this = _Scale.call(this, cfg) || this; + _this.start = undefined; + _this.end = undefined; + _this._startValue = undefined; + _this._endValue = undefined; + _this._valueRange = 0; + return _this; + } + var _proto = LinearScaleBase.prototype; + _proto.parse = function parse(raw, index) { + if (isNullOrUndef(raw)) { + return NaN; + } + if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) { + return NaN; + } + return +raw; + }; + _proto.handleTickRangeOptions = function handleTickRangeOptions() { + var me = this; + var opts = me.options; + if (opts.beginAtZero) { + var minSign = sign(me.min); + var maxSign = sign(me.max); + if (minSign < 0 && maxSign < 0) { + me.max = 0; + } else if (minSign > 0 && maxSign > 0) { + me.min = 0; + } + } + var setMin = opts.min !== undefined || opts.suggestedMin !== undefined; + var setMax = opts.max !== undefined || opts.suggestedMax !== undefined; + if (opts.min !== undefined) { + me.min = opts.min; + } else if (opts.suggestedMin !== undefined) { + if (me.min === null) { + me.min = opts.suggestedMin; + } else { + me.min = Math.min(me.min, opts.suggestedMin); + } + } + if (opts.max !== undefined) { + me.max = opts.max; + } else if (opts.suggestedMax !== undefined) { + if (me.max === null) { + me.max = opts.suggestedMax; + } else { + me.max = Math.max(me.max, opts.suggestedMax); + } + } + if (setMin !== setMax) { + if (me.min >= me.max) { + if (setMin) { + me.max = me.min + 1; + } else { + me.min = me.max - 1; + } + } + } + if (me.min === me.max) { + me.max++; + if (!opts.beginAtZero) { + me.min--; + } + } + }; + _proto.getTickLimit = function getTickLimit() { + var me = this; + var tickOpts = me.options.ticks; + var maxTicksLimit = tickOpts.maxTicksLimit, + stepSize = tickOpts.stepSize; + var maxTicks; + if (stepSize) { + maxTicks = Math.ceil(me.max / stepSize) - Math.floor(me.min / stepSize) + 1; + } else { + maxTicks = me.computeTickLimit(); + maxTicksLimit = maxTicksLimit || 11; + } + if (maxTicksLimit) { + maxTicks = Math.min(maxTicksLimit, maxTicks); + } + return maxTicks; + } + ; + _proto.computeTickLimit = function computeTickLimit() { + return Number.POSITIVE_INFINITY; + }; + _proto.buildTicks = function buildTicks() { + var me = this; + var opts = me.options; + var tickOpts = opts.ticks; + var maxTicks = me.getTickLimit(); + maxTicks = Math.max(2, maxTicks); + var numericGeneratorOptions = { + maxTicks: maxTicks, + min: opts.min, + max: opts.max, + precision: tickOpts.precision, + stepSize: valueOrDefault(tickOpts.fixedStepSize, tickOpts.stepSize) + }; + var ticks = generateTicks(numericGeneratorOptions, me); + _setMinAndMaxByKey(ticks, me, 'value'); + if (opts.reverse) { + ticks.reverse(); + me.start = me.max; + me.end = me.min; + } else { + me.start = me.min; + me.end = me.max; + } + return ticks; + } + ; + _proto.configure = function configure() { + var me = this; + var ticks = me.ticks; + var start = me.min; + var end = me.max; + _Scale.prototype.configure.call(this); + if (me.options.offset && ticks.length) { + var offset = (end - start) / Math.max(ticks.length - 1, 1) / 2; + start -= offset; + end += offset; + } + me._startValue = start; + me._endValue = end; + me._valueRange = end - start; + }; + _proto.getLabelForValue = function getLabelForValue(value) { + return new Intl.NumberFormat(this.options.locale).format(value); + }; + return LinearScaleBase; +}(Scale); + +var LinearScale = function (_LinearScaleBase) { + _inheritsLoose(LinearScale, _LinearScaleBase); + function LinearScale() { + return _LinearScaleBase.apply(this, arguments) || this; + } + var _proto = LinearScale.prototype; + _proto.determineDataLimits = function determineDataLimits() { + var me = this; + var options = me.options; + var _me$getMinMax = me.getMinMax(true), + min = _me$getMinMax.min, + max = _me$getMinMax.max; + me.min = isNumberFinite(min) ? min : valueOrDefault(options.suggestedMin, 0); + me.max = isNumberFinite(max) ? max : valueOrDefault(options.suggestedMax, 1); + if (options.stacked && min > 0) { + me.min = 0; + } + me.handleTickRangeOptions(); + } + ; + _proto.computeTickLimit = function computeTickLimit() { + var me = this; + if (me.isHorizontal()) { + return Math.ceil(me.width / 40); + } + var tickFont = me._resolveTickFontOptions(0); + return Math.ceil(me.height / tickFont.lineHeight); + } + ; + _proto.getPixelForValue = function getPixelForValue(value) { + var me = this; + return me.getPixelForDecimal((value - me._startValue) / me._valueRange); + }; + _proto.getValueForPixel = function getValueForPixel(pixel) { + return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange; + }; + return LinearScale; +}(LinearScaleBase); +LinearScale.id = 'linear'; +LinearScale.defaults = { + ticks: { + callback: Ticks.formatters.numeric + } +}; + +function isMajor(tickVal) { + var remain = tickVal / Math.pow(10, Math.floor(log10(tickVal))); + return remain === 1; +} +function finiteOrDefault(value, def) { + return isNumberFinite(value) ? value : def; +} +function generateTicks$1(generationOptions, dataRange) { + var endExp = Math.floor(log10(dataRange.max)); + var endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp)); + var ticks = []; + var tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min)))); + var exp = Math.floor(log10(tickVal)); + var significand = Math.floor(tickVal / Math.pow(10, exp)); + var precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1; + do { + ticks.push({ + value: tickVal, + major: isMajor(tickVal) + }); + ++significand; + if (significand === 10) { + significand = 1; + ++exp; + precision = exp >= 0 ? 1 : precision; + } + tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision; + } while (exp < endExp || exp === endExp && significand < endSignificand); + var lastTick = finiteOrDefault(generationOptions.max, tickVal); + ticks.push({ + value: lastTick, + major: isMajor(tickVal) + }); + return ticks; +} +var LogarithmicScale = function (_Scale) { + _inheritsLoose(LogarithmicScale, _Scale); + function LogarithmicScale(cfg) { + var _this; + _this = _Scale.call(this, cfg) || this; + _this.start = undefined; + _this.end = undefined; + _this._startValue = undefined; + _this._valueRange = 0; + return _this; + } + var _proto = LogarithmicScale.prototype; + _proto.parse = function parse(raw, index) { + var value = LinearScaleBase.prototype.parse.apply(this, [raw, index]); + if (value === 0) { + return undefined; + } + return isNumberFinite(value) && value > 0 ? value : NaN; + }; + _proto.determineDataLimits = function determineDataLimits() { + var me = this; + var _me$getMinMax = me.getMinMax(true), + min = _me$getMinMax.min, + max = _me$getMinMax.max; + me.min = isNumberFinite(min) ? Math.max(0, min) : null; + me.max = isNumberFinite(max) ? Math.max(0, max) : null; + me.handleTickRangeOptions(); + }; + _proto.handleTickRangeOptions = function handleTickRangeOptions() { + var me = this; + var DEFAULT_MIN = 1; + var DEFAULT_MAX = 10; + var min = me.min; + var max = me.max; + if (min === max) { + if (min <= 0) { + min = DEFAULT_MIN; + max = DEFAULT_MAX; + } else { + min = Math.pow(10, Math.floor(log10(min)) - 1); + max = Math.pow(10, Math.floor(log10(max)) + 1); + } + } + if (min <= 0) { + min = Math.pow(10, Math.floor(log10(max)) - 1); + } + if (max <= 0) { + max = Math.pow(10, Math.floor(log10(min)) + 1); + } + me.min = min; + me.max = max; + }; + _proto.buildTicks = function buildTicks() { + var me = this; + var opts = me.options; + var generationOptions = { + min: me._userMin, + max: me._userMax + }; + var ticks = generateTicks$1(generationOptions, me); + var reverse = !me.isHorizontal(); + _setMinAndMaxByKey(ticks, me, 'value'); + if (opts.reverse) { + reverse = !reverse; + me.start = me.max; + me.end = me.min; + } else { + me.start = me.min; + me.end = me.max; + } + if (reverse) { + ticks.reverse(); + } + return ticks; + } + ; + _proto.getLabelForValue = function getLabelForValue(value) { + return value === undefined ? '0' : new Intl.NumberFormat(this.options.locale).format(value); + } + ; + _proto.configure = function configure() { + var me = this; + var start = me.min; + _Scale.prototype.configure.call(this); + me._startValue = log10(start); + me._valueRange = log10(me.max) - log10(start); + }; + _proto.getPixelForValue = function getPixelForValue(value) { + var me = this; + if (value === undefined || value === 0) { + value = me.min; + } + return me.getPixelForDecimal(value === me.min ? 0 : (log10(value) - me._startValue) / me._valueRange); + }; + _proto.getValueForPixel = function getValueForPixel(pixel) { + var me = this; + var decimal = me.getDecimalForPixel(pixel); + return Math.pow(10, me._startValue + decimal * me._valueRange); + }; + return LogarithmicScale; +}(Scale); +LogarithmicScale.id = 'logarithmic'; +LogarithmicScale.defaults = { + ticks: { + callback: Ticks.formatters.logarithmic, + major: { + enabled: true + } + } +}; + +function getTickBackdropHeight(opts) { + var tickOpts = opts.ticks; + if (tickOpts.display && opts.display) { + return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + tickOpts.backdropPaddingY * 2; + } + return 0; +} +function measureLabelSize(ctx, lineHeight, label) { + if (isArray(label)) { + return { + w: _longestText(ctx, ctx.font, label), + h: label.length * lineHeight + }; + } + return { + w: ctx.measureText(label).width, + h: lineHeight + }; +} +function determineLimits(angle, pos, size, min, max) { + if (angle === min || angle === max) { + return { + start: pos - size / 2, + end: pos + size / 2 + }; + } else if (angle < min || angle > max) { + return { + start: pos - size, + end: pos + }; + } + return { + start: pos, + end: pos + size + }; +} +function fitWithPointLabels(scale) { + var furthestLimits = { + l: 0, + r: scale.width, + t: 0, + b: scale.height - scale.paddingTop + }; + var furthestAngles = {}; + var i, textSize, pointPosition; + scale._pointLabelSizes = []; + var valueCount = scale.chart.data.labels.length; + for (i = 0; i < valueCount; i++) { + pointPosition = scale.getPointPosition(i, scale.drawingArea + 5); + var context = { + chart: scale.chart, + scale: scale, + index: i, + label: scale.pointLabels[i] + }; + var plFont = toFont(resolve([scale.options.pointLabels.font], context, i), scale.chart.options.font); + scale.ctx.font = plFont.string; + textSize = measureLabelSize(scale.ctx, plFont.lineHeight, scale.pointLabels[i]); + scale._pointLabelSizes[i] = textSize; + var angleRadians = scale.getIndexAngle(i); + var angle = toDegrees(angleRadians); + var hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180); + var vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270); + if (hLimits.start < furthestLimits.l) { + furthestLimits.l = hLimits.start; + furthestAngles.l = angleRadians; + } + if (hLimits.end > furthestLimits.r) { + furthestLimits.r = hLimits.end; + furthestAngles.r = angleRadians; + } + if (vLimits.start < furthestLimits.t) { + furthestLimits.t = vLimits.start; + furthestAngles.t = angleRadians; + } + if (vLimits.end > furthestLimits.b) { + furthestLimits.b = vLimits.end; + furthestAngles.b = angleRadians; + } + } + scale._setReductions(scale.drawingArea, furthestLimits, furthestAngles); +} +function getTextAlignForAngle(angle) { + if (angle === 0 || angle === 180) { + return 'center'; + } else if (angle < 180) { + return 'left'; + } + return 'right'; +} +function fillText(ctx, text, position, lineHeight) { + var y = position.y + lineHeight / 2; + var i, ilen; + if (isArray(text)) { + for (i = 0, ilen = text.length; i < ilen; ++i) { + ctx.fillText(text[i], position.x, y); + y += lineHeight; + } + } else { + ctx.fillText(text, position.x, y); + } +} +function adjustPointPositionForLabelHeight(angle, textSize, position) { + if (angle === 90 || angle === 270) { + position.y -= textSize.h / 2; + } else if (angle > 270 || angle < 90) { + position.y -= textSize.h; + } +} +function drawPointLabels(scale) { + var ctx = scale.ctx; + var opts = scale.options; + var pointLabelOpts = opts.pointLabels; + var tickBackdropHeight = getTickBackdropHeight(opts); + var outerDistance = scale.getDistanceFromCenterForValue(opts.ticks.reverse ? scale.min : scale.max); + ctx.save(); + ctx.textBaseline = 'middle'; + for (var i = scale.chart.data.labels.length - 1; i >= 0; i--) { + var extra = i === 0 ? tickBackdropHeight / 2 : 0; + var pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + 5); + var context = { + chart: scale.chart, + scale: scale, + index: i, + label: scale.pointLabels[i] + }; + var plFont = toFont(resolve([pointLabelOpts.font], context, i), scale.chart.options.font); + ctx.font = plFont.string; + ctx.fillStyle = plFont.color; + var angle = toDegrees(scale.getIndexAngle(i)); + ctx.textAlign = getTextAlignForAngle(angle); + adjustPointPositionForLabelHeight(angle, scale._pointLabelSizes[i], pointLabelPosition); + fillText(ctx, scale.pointLabels[i], pointLabelPosition, plFont.lineHeight); + } + ctx.restore(); +} +function drawRadiusLine(scale, gridLineOpts, radius, index) { + var ctx = scale.ctx; + var circular = gridLineOpts.circular; + var valueCount = scale.chart.data.labels.length; + var context = { + chart: scale.chart, + scale: scale, + index: index, + tick: scale.ticks[index] + }; + var lineColor = resolve([gridLineOpts.color], context, index - 1); + var lineWidth = resolve([gridLineOpts.lineWidth], context, index - 1); + var pointPosition; + if (!circular && !valueCount || !lineColor || !lineWidth) { + return; + } + ctx.save(); + ctx.strokeStyle = lineColor; + ctx.lineWidth = lineWidth; + if (ctx.setLineDash) { + ctx.setLineDash(resolve([gridLineOpts.borderDash, []], context)); + ctx.lineDashOffset = resolve([gridLineOpts.borderDashOffset], context, index - 1); + } + ctx.beginPath(); + if (circular) { + ctx.arc(scale.xCenter, scale.yCenter, radius, 0, Math.PI * 2); + } else { + pointPosition = scale.getPointPosition(0, radius); + ctx.moveTo(pointPosition.x, pointPosition.y); + for (var i = 1; i < valueCount; i++) { + pointPosition = scale.getPointPosition(i, radius); + ctx.lineTo(pointPosition.x, pointPosition.y); + } + } + ctx.closePath(); + ctx.stroke(); + ctx.restore(); +} +function numberOrZero$1(param) { + return isNumber(param) ? param : 0; +} +var RadialLinearScale = function (_LinearScaleBase) { + _inheritsLoose(RadialLinearScale, _LinearScaleBase); + function RadialLinearScale(cfg) { + var _this; + _this = _LinearScaleBase.call(this, cfg) || this; + _this.xCenter = undefined; + _this.yCenter = undefined; + _this.drawingArea = undefined; + _this.pointLabels = []; + return _this; + } + var _proto = RadialLinearScale.prototype; + _proto.init = function init(options) { + _LinearScaleBase.prototype.init.call(this, options); + this.axis = 'r'; + }; + _proto.setDimensions = function setDimensions() { + var me = this; + me.width = me.maxWidth; + me.height = me.maxHeight; + me.paddingTop = getTickBackdropHeight(me.options) / 2; + me.xCenter = Math.floor(me.width / 2); + me.yCenter = Math.floor((me.height - me.paddingTop) / 2); + me.drawingArea = Math.min(me.height - me.paddingTop, me.width) / 2; + }; + _proto.determineDataLimits = function determineDataLimits() { + var me = this; + var _me$getMinMax = me.getMinMax(false), + min = _me$getMinMax.min, + max = _me$getMinMax.max; + me.min = isNumberFinite(min) && !isNaN(min) ? min : 0; + me.max = isNumberFinite(max) && !isNaN(max) ? max : 0; + me.handleTickRangeOptions(); + } + ; + _proto.computeTickLimit = function computeTickLimit() { + return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options)); + }; + _proto.generateTickLabels = function generateTickLabels(ticks) { + var me = this; + LinearScaleBase.prototype.generateTickLabels.call(me, ticks); + me.pointLabels = me.chart.data.labels.map(function (value, index) { + var label = callback(me.options.pointLabels.callback, [value, index], me); + return label || label === 0 ? label : ''; + }); + }; + _proto.fit = function fit() { + var me = this; + var opts = me.options; + if (opts.display && opts.pointLabels.display) { + fitWithPointLabels(me); + } else { + me.setCenterPoint(0, 0, 0, 0); + } + } + ; + _proto._setReductions = function _setReductions(largestPossibleRadius, furthestLimits, furthestAngles) { + var me = this; + var radiusReductionLeft = furthestLimits.l / Math.sin(furthestAngles.l); + var radiusReductionRight = Math.max(furthestLimits.r - me.width, 0) / Math.sin(furthestAngles.r); + var radiusReductionTop = -furthestLimits.t / Math.cos(furthestAngles.t); + var radiusReductionBottom = -Math.max(furthestLimits.b - (me.height - me.paddingTop), 0) / Math.cos(furthestAngles.b); + radiusReductionLeft = numberOrZero$1(radiusReductionLeft); + radiusReductionRight = numberOrZero$1(radiusReductionRight); + radiusReductionTop = numberOrZero$1(radiusReductionTop); + radiusReductionBottom = numberOrZero$1(radiusReductionBottom); + me.drawingArea = Math.min(Math.floor(largestPossibleRadius - (radiusReductionLeft + radiusReductionRight) / 2), Math.floor(largestPossibleRadius - (radiusReductionTop + radiusReductionBottom) / 2)); + me.setCenterPoint(radiusReductionLeft, radiusReductionRight, radiusReductionTop, radiusReductionBottom); + }; + _proto.setCenterPoint = function setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) { + var me = this; + var maxRight = me.width - rightMovement - me.drawingArea; + var maxLeft = leftMovement + me.drawingArea; + var maxTop = topMovement + me.drawingArea; + var maxBottom = me.height - me.paddingTop - bottomMovement - me.drawingArea; + me.xCenter = Math.floor((maxLeft + maxRight) / 2 + me.left); + me.yCenter = Math.floor((maxTop + maxBottom) / 2 + me.top + me.paddingTop); + }; + _proto.getIndexAngle = function getIndexAngle(index) { + var chart = this.chart; + var angleMultiplier = Math.PI * 2 / chart.data.labels.length; + var options = chart.options || {}; + var startAngle = options.startAngle || 0; + return _normalizeAngle(index * angleMultiplier + toRadians(startAngle)); + }; + _proto.getDistanceFromCenterForValue = function getDistanceFromCenterForValue(value) { + var me = this; + if (isNullOrUndef(value)) { + return NaN; + } + var scalingFactor = me.drawingArea / (me.max - me.min); + if (me.options.reverse) { + return (me.max - value) * scalingFactor; + } + return (value - me.min) * scalingFactor; + }; + _proto.getValueForDistanceFromCenter = function getValueForDistanceFromCenter(distance) { + if (isNullOrUndef(distance)) { + return NaN; + } + var me = this; + var scaledDistance = distance / (me.drawingArea / (me.max - me.min)); + return me.options.reverse ? me.max - scaledDistance : me.min + scaledDistance; + }; + _proto.getPointPosition = function getPointPosition(index, distanceFromCenter) { + var me = this; + var angle = me.getIndexAngle(index) - Math.PI / 2; + return { + x: Math.cos(angle) * distanceFromCenter + me.xCenter, + y: Math.sin(angle) * distanceFromCenter + me.yCenter, + angle: angle + }; + }; + _proto.getPointPositionForValue = function getPointPositionForValue(index, value) { + return this.getPointPosition(index, this.getDistanceFromCenterForValue(value)); + }; + _proto.getBasePosition = function getBasePosition(index) { + return this.getPointPositionForValue(index || 0, this.getBaseValue()); + } + ; + _proto.drawGrid = function drawGrid() { + var me = this; + var ctx = me.ctx; + var opts = me.options; + var gridLineOpts = opts.gridLines; + var angleLineOpts = opts.angleLines; + var i, offset, position; + if (opts.pointLabels.display) { + drawPointLabels(me); + } + if (gridLineOpts.display) { + me.ticks.forEach(function (tick, index) { + if (index !== 0) { + offset = me.getDistanceFromCenterForValue(me.ticks[index].value); + drawRadiusLine(me, gridLineOpts, offset, index); + } + }); + } + if (angleLineOpts.display) { + ctx.save(); + for (i = me.chart.data.labels.length - 1; i >= 0; i--) { + var context = { + chart: me.chart, + scale: me, + index: i, + label: me.pointLabels[i] + }; + var lineWidth = resolve([angleLineOpts.lineWidth, gridLineOpts.lineWidth], context, i); + var color = resolve([angleLineOpts.color, gridLineOpts.color], context, i); + if (!lineWidth || !color) { + continue; + } + ctx.lineWidth = lineWidth; + ctx.strokeStyle = color; + if (ctx.setLineDash) { + ctx.setLineDash(resolve([angleLineOpts.borderDash, gridLineOpts.borderDash, []], context)); + ctx.lineDashOffset = resolve([angleLineOpts.borderDashOffset, gridLineOpts.borderDashOffset, 0.0], context, i); + } + offset = me.getDistanceFromCenterForValue(opts.ticks.reverse ? me.min : me.max); + position = me.getPointPosition(i, offset); + ctx.beginPath(); + ctx.moveTo(me.xCenter, me.yCenter); + ctx.lineTo(position.x, position.y); + ctx.stroke(); + } + ctx.restore(); + } + } + ; + _proto.drawLabels = function drawLabels() { + var me = this; + var ctx = me.ctx; + var opts = me.options; + var tickOpts = opts.ticks; + if (!tickOpts.display) { + return; + } + var startAngle = me.getIndexAngle(0); + var offset, width; + ctx.save(); + ctx.translate(me.xCenter, me.yCenter); + ctx.rotate(startAngle); + ctx.textAlign = 'center'; + ctx.textBaseline = 'middle'; + me.ticks.forEach(function (tick, index) { + var context = { + chart: me.chart, + scale: me, + index: index, + tick: tick + }; + if (index === 0 && !opts.reverse) { + return; + } + var tickFont = me._resolveTickFontOptions(index); + ctx.font = tickFont.string; + offset = me.getDistanceFromCenterForValue(me.ticks[index].value); + var showLabelBackdrop = resolve([tickOpts.showLabelBackdrop], context, index); + if (showLabelBackdrop) { + width = ctx.measureText(tick.label).width; + ctx.fillStyle = resolve([tickOpts.backdropColor], context, index); + ctx.fillRect(-width / 2 - tickOpts.backdropPaddingX, -offset - tickFont.size / 2 - tickOpts.backdropPaddingY, width + tickOpts.backdropPaddingX * 2, tickFont.size + tickOpts.backdropPaddingY * 2); + } + ctx.fillStyle = tickFont.color; + ctx.fillText(tick.label, 0, -offset); + }); + ctx.restore(); + } + ; + _proto.drawTitle = function drawTitle() {}; + return RadialLinearScale; +}(LinearScaleBase); +RadialLinearScale.id = 'radialLinear'; +RadialLinearScale.defaults = { + display: true, + animate: true, + position: 'chartArea', + angleLines: { + display: true, + color: 'rgba(0,0,0,0.1)', + lineWidth: 1, + borderDash: [], + borderDashOffset: 0.0 + }, + gridLines: { + circular: false + }, + ticks: { + showLabelBackdrop: true, + backdropColor: 'rgba(255,255,255,0.75)', + backdropPaddingY: 2, + backdropPaddingX: 2, + callback: Ticks.formatters.numeric + }, + pointLabels: { + display: true, + font: { + size: 10 + }, + callback: function callback(label) { + return label; + } + } +}; + +var MAX_INTEGER = Number.MAX_SAFE_INTEGER || 9007199254740991; +var INTERVALS = { + millisecond: { + common: true, + size: 1, + steps: 1000 + }, + second: { + common: true, + size: 1000, + steps: 60 + }, + minute: { + common: true, + size: 60000, + steps: 60 + }, + hour: { + common: true, + size: 3600000, + steps: 24 + }, + day: { + common: true, + size: 86400000, + steps: 30 + }, + week: { + common: false, + size: 604800000, + steps: 4 + }, + month: { + common: true, + size: 2.628e9, + steps: 12 + }, + quarter: { + common: false, + size: 7.884e9, + steps: 4 + }, + year: { + common: true, + size: 3.154e10 + } +}; +var UNITS = +Object.keys(INTERVALS); +function sorter(a, b) { + return a - b; +} +function _parse(scale, input) { + if (isNullOrUndef(input)) { + return null; + } + var adapter = scale._adapter; + var options = scale.options.time; + var parser = options.parser, + round = options.round, + isoWeekday = options.isoWeekday; + var value = input; + if (typeof parser === 'function') { + value = parser(value); + } + if (!isNumberFinite(value)) { + value = typeof parser === 'string' ? adapter.parse(value, parser) : adapter.parse(value); + } + if (value === null) { + return value; + } + if (round) { + value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true) ? scale._adapter.startOf(value, 'isoWeek', isoWeekday) : scale._adapter.startOf(value, round); + } + return +value; +} +function determineUnitForAutoTicks(minUnit, min, max, capacity) { + var ilen = UNITS.length; + for (var i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) { + var interval = INTERVALS[UNITS[i]]; + var factor = interval.steps ? interval.steps : MAX_INTEGER; + if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) { + return UNITS[i]; + } + } + return UNITS[ilen - 1]; +} +function determineUnitForFormatting(scale, numTicks, minUnit, min, max) { + for (var i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) { + var unit = UNITS[i]; + if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) { + return unit; + } + } + return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0]; +} +function determineMajorUnit(unit) { + for (var i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) { + if (INTERVALS[UNITS[i]].common) { + return UNITS[i]; + } + } +} +function addTick(ticks, time, timestamps) { + if (!timestamps) { + ticks[time] = true; + } else if (timestamps.length) { + var _lookup2 = _lookup(timestamps, time), + lo = _lookup2.lo, + hi = _lookup2.hi; + var timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi]; + ticks[timestamp] = true; + } +} +function setMajorTicks(scale, ticks, map, majorUnit) { + var adapter = scale._adapter; + var first = +adapter.startOf(ticks[0].value, majorUnit); + var last = ticks[ticks.length - 1].value; + var major, index; + for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) { + index = map[major]; + if (index >= 0) { + ticks[index].major = true; + } + } + return ticks; +} +function ticksFromTimestamps(scale, values, majorUnit) { + var ticks = []; + var map = {}; + var ilen = values.length; + var i, value; + for (i = 0; i < ilen; ++i) { + value = values[i]; + map[value] = i; + ticks.push({ + value: value, + major: false + }); + } + return ilen === 0 || !majorUnit ? ticks : setMajorTicks(scale, ticks, map, majorUnit); +} +var TimeScale = function (_Scale) { + _inheritsLoose(TimeScale, _Scale); + function TimeScale(props) { + var _this; + _this = _Scale.call(this, props) || this; + _this._cache = { + data: [], + labels: [], + all: [] + }; + _this._unit = 'day'; + _this._majorUnit = undefined; + _this._offsets = {}; + _this._normalized = false; + return _this; + } + var _proto = TimeScale.prototype; + _proto.init = function init(scaleOpts, opts) { + var time = scaleOpts.time || (scaleOpts.time = {}); + var adapter = this._adapter = new _adapters._date(scaleOpts.adapters.date); + mergeIf(time.displayFormats, adapter.formats()); + _Scale.prototype.init.call(this, scaleOpts); + this._normalized = opts.normalized; + } + ; + _proto.parse = function parse(raw, index) { + if (raw === undefined) { + return NaN; + } + return _parse(this, raw); + }; + _proto.invalidateCaches = function invalidateCaches() { + this._cache = { + data: [], + labels: [], + all: [] + }; + }; + _proto.determineDataLimits = function determineDataLimits() { + var me = this; + var options = me.options; + var adapter = me._adapter; + var unit = options.time.unit || 'day'; + var _me$getUserBounds = me.getUserBounds(), + min = _me$getUserBounds.min, + max = _me$getUserBounds.max, + minDefined = _me$getUserBounds.minDefined, + maxDefined = _me$getUserBounds.maxDefined; + function _applyBounds(bounds) { + if (!minDefined && !isNaN(bounds.min)) { + min = Math.min(min, bounds.min); + } + if (!maxDefined && !isNaN(bounds.max)) { + max = Math.max(max, bounds.max); + } + } + if (!minDefined || !maxDefined) { + _applyBounds(me._getLabelBounds()); + if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') { + _applyBounds(me.getMinMax(false)); + } + } + min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit); + max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1; + me.min = Math.min(min, max); + me.max = Math.max(min + 1, max); + } + ; + _proto._getLabelBounds = function _getLabelBounds() { + var arr = this.getLabelTimestamps(); + var min = Number.POSITIVE_INFINITY; + var max = Number.NEGATIVE_INFINITY; + if (arr.length) { + min = arr[0]; + max = arr[arr.length - 1]; + } + return { + min: min, + max: max + }; + } + ; + _proto.buildTicks = function buildTicks() { + var me = this; + var options = me.options; + var timeOpts = options.time; + var tickOpts = options.ticks; + var timestamps = tickOpts.source === 'labels' ? me.getLabelTimestamps() : me._generate(); + if (options.bounds === 'ticks' && timestamps.length) { + me.min = me._userMin || timestamps[0]; + me.max = me._userMax || timestamps[timestamps.length - 1]; + } + var min = me.min; + var max = me.max; + var ticks = _filterBetween(timestamps, min, max); + me._unit = timeOpts.unit || (tickOpts.autoSkip ? determineUnitForAutoTicks(timeOpts.minUnit, me.min, me.max, me._getLabelCapacity(min)) : determineUnitForFormatting(me, ticks.length, timeOpts.minUnit, me.min, me.max)); + me._majorUnit = !tickOpts.major.enabled || me._unit === 'year' ? undefined : determineMajorUnit(me._unit); + me.initOffsets(timestamps); + if (options.reverse) { + ticks.reverse(); + } + return ticksFromTimestamps(me, ticks, me._majorUnit); + } + ; + _proto.initOffsets = function initOffsets(timestamps) { + var me = this; + var start = 0; + var end = 0; + var first, last; + if (me.options.offset && timestamps.length) { + first = me.getDecimalForValue(timestamps[0]); + if (timestamps.length === 1) { + start = 1 - first; + } else { + start = (me.getDecimalForValue(timestamps[1]) - first) / 2; + } + last = me.getDecimalForValue(timestamps[timestamps.length - 1]); + if (timestamps.length === 1) { + end = last; + } else { + end = (last - me.getDecimalForValue(timestamps[timestamps.length - 2])) / 2; + } + } + me._offsets = { + start: start, + end: end, + factor: 1 / (start + 1 + end) + }; + } + ; + _proto._generate = function _generate() { + var me = this; + var adapter = me._adapter; + var min = me.min; + var max = me.max; + var options = me.options; + var timeOpts = options.time; + var minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, me._getLabelCapacity(min)); + var stepSize = valueOrDefault(timeOpts.stepSize, 1); + var weekday = minor === 'week' ? timeOpts.isoWeekday : false; + var hasWeekday = isNumber(weekday) || weekday === true; + var ticks = {}; + var first = min; + var time; + if (hasWeekday) { + first = +adapter.startOf(first, 'isoWeek', weekday); + } + first = +adapter.startOf(first, hasWeekday ? 'day' : minor); + if (adapter.diff(max, min, minor) > 100000 * stepSize) { + throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor); + } + var timestamps = options.ticks.source === 'data' && me.getDataTimestamps(); + for (time = first; time < max; time = +adapter.add(time, stepSize, minor)) { + addTick(ticks, time, timestamps); + } + if (time === max || options.bounds === 'ticks') { + addTick(ticks, time, timestamps); + } + return Object.keys(ticks).sort(function (a, b) { + return a - b; + }).map(function (x) { + return +x; + }); + } + ; + _proto.getLabelForValue = function getLabelForValue(value) { + var me = this; + var adapter = me._adapter; + var timeOpts = me.options.time; + if (timeOpts.tooltipFormat) { + return adapter.format(value, timeOpts.tooltipFormat); + } + return adapter.format(value, timeOpts.displayFormats.datetime); + } + ; + _proto._tickFormatFunction = function _tickFormatFunction(time, index, ticks, format) { + var me = this; + var options = me.options; + var formats = options.time.displayFormats; + var unit = me._unit; + var majorUnit = me._majorUnit; + var minorFormat = unit && formats[unit]; + var majorFormat = majorUnit && formats[majorUnit]; + var tick = ticks[index]; + var major = majorUnit && majorFormat && tick && tick.major; + var label = me._adapter.format(time, format || (major ? majorFormat : minorFormat)); + var formatter = options.ticks.callback; + return formatter ? formatter(label, index, ticks) : label; + } + ; + _proto.generateTickLabels = function generateTickLabels(ticks) { + var i, ilen, tick; + for (i = 0, ilen = ticks.length; i < ilen; ++i) { + tick = ticks[i]; + tick.label = this._tickFormatFunction(tick.value, i, ticks); + } + } + ; + _proto.getDecimalForValue = function getDecimalForValue(value) { + var me = this; + return (value - me.min) / (me.max - me.min); + } + ; + _proto.getPixelForValue = function getPixelForValue(value) { + var me = this; + var offsets = me._offsets; + var pos = me.getDecimalForValue(value); + return me.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + ; + _proto.getValueForPixel = function getValueForPixel(pixel) { + var me = this; + var offsets = me._offsets; + var pos = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return me.min + pos * (me.max - me.min); + } + ; + _proto._getLabelSize = function _getLabelSize(label) { + var me = this; + var ticksOpts = me.options.ticks; + var tickLabelWidth = me.ctx.measureText(label).width; + var angle = toRadians(me.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation); + var cosRotation = Math.cos(angle); + var sinRotation = Math.sin(angle); + var tickFontSize = me._resolveTickFontOptions(0).size; + return { + w: tickLabelWidth * cosRotation + tickFontSize * sinRotation, + h: tickLabelWidth * sinRotation + tickFontSize * cosRotation + }; + } + ; + _proto._getLabelCapacity = function _getLabelCapacity(exampleTime) { + var me = this; + var timeOpts = me.options.time; + var displayFormats = timeOpts.displayFormats; + var format = displayFormats[timeOpts.unit] || displayFormats.millisecond; + var exampleLabel = me._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(me, [exampleTime], me._majorUnit), format); + var size = me._getLabelSize(exampleLabel); + var capacity = Math.floor(me.isHorizontal() ? me.width / size.w : me.height / size.h) - 1; + return capacity > 0 ? capacity : 1; + } + ; + _proto.getDataTimestamps = function getDataTimestamps() { + var me = this; + var timestamps = me._cache.data || []; + var i, ilen; + if (timestamps.length) { + return timestamps; + } + var metas = me.getMatchingVisibleMetas(); + if (me._normalized && metas.length) { + return me._cache.data = metas[0].controller.getAllParsedValues(me); + } + for (i = 0, ilen = metas.length; i < ilen; ++i) { + timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(me)); + } + return me._cache.data = me.normalize(timestamps); + } + ; + _proto.getLabelTimestamps = function getLabelTimestamps() { + var me = this; + var timestamps = me._cache.labels || []; + var i, ilen; + if (timestamps.length) { + return timestamps; + } + var labels = me.getLabels(); + for (i = 0, ilen = labels.length; i < ilen; ++i) { + timestamps.push(_parse(me, labels[i])); + } + return me._cache.labels = me._normalized ? timestamps : me.normalize(timestamps); + } + ; + _proto.normalize = function normalize(values) { + return _arrayUnique(values.sort(sorter)); + }; + return TimeScale; +}(Scale); +TimeScale.id = 'time'; +TimeScale.defaults = { + bounds: 'data', + adapters: {}, + time: { + parser: false, + unit: false, + round: false, + isoWeekday: false, + minUnit: 'millisecond', + displayFormats: {} + }, + ticks: { + source: 'auto', + major: { + enabled: false + } + } +}; + +function interpolate(table, val, reverse) { + var prevSource, nextSource, prevTarget, nextTarget; + if (reverse) { + prevSource = Math.floor(val); + nextSource = Math.ceil(val); + prevTarget = table[prevSource]; + nextTarget = table[nextSource]; + } else { + var result = _lookup(table, val); + prevTarget = result.lo; + nextTarget = result.hi; + prevSource = table[prevTarget]; + nextSource = table[nextTarget]; + } + var span = nextSource - prevSource; + return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget; +} +var TimeSeriesScale = function (_TimeScale) { + _inheritsLoose(TimeSeriesScale, _TimeScale); + function TimeSeriesScale(props) { + var _this; + _this = _TimeScale.call(this, props) || this; + _this._table = []; + _this._maxIndex = undefined; + return _this; + } + var _proto = TimeSeriesScale.prototype; + _proto.initOffsets = function initOffsets() { + var me = this; + var timestamps = me._getTimestampsForTable(); + me._table = me.buildLookupTable(timestamps); + me._maxIndex = me._table.length - 1; + _TimeScale.prototype.initOffsets.call(this, timestamps); + } + ; + _proto.buildLookupTable = function buildLookupTable(timestamps) { + var me = this; + var min = me.min, + max = me.max; + if (!timestamps.length) { + return [{ + time: min, + pos: 0 + }, { + time: max, + pos: 1 + }]; + } + var items = [min]; + var i, ilen, curr; + for (i = 0, ilen = timestamps.length; i < ilen; ++i) { + curr = timestamps[i]; + if (curr > min && curr < max) { + items.push(curr); + } + } + items.push(max); + return items; + } + ; + _proto._getTimestampsForTable = function _getTimestampsForTable() { + var me = this; + var timestamps = me._cache.all || []; + if (timestamps.length) { + return timestamps; + } + var data = me.getDataTimestamps(); + var label = me.getLabelTimestamps(); + if (data.length && label.length) { + timestamps = me.normalize(data.concat(label)); + } else { + timestamps = data.length ? data : label; + } + timestamps = me._cache.all = timestamps; + return timestamps; + } + ; + _proto.getPixelForValue = function getPixelForValue(value, index) { + var me = this; + var offsets = me._offsets; + var pos = me._normalized && me._maxIndex > 0 && !isNullOrUndef(index) ? index / me._maxIndex : me.getDecimalForValue(value); + return me.getPixelForDecimal((offsets.start + pos) * offsets.factor); + } + ; + _proto.getDecimalForValue = function getDecimalForValue(value) { + return interpolate(this._table, value) / this._maxIndex; + } + ; + _proto.getValueForPixel = function getValueForPixel(pixel) { + var me = this; + var offsets = me._offsets; + var decimal = me.getDecimalForPixel(pixel) / offsets.factor - offsets.end; + return interpolate(me._table, decimal * this._maxIndex, true); + }; + return TimeSeriesScale; +}(TimeScale); +TimeSeriesScale.id = 'timeseries'; +TimeSeriesScale.defaults = TimeScale.defaults; + +var scales = /*#__PURE__*/Object.freeze({ +__proto__: null, +CategoryScale: CategoryScale, +LinearScale: LinearScale, +LogarithmicScale: LogarithmicScale, +RadialLinearScale: RadialLinearScale, +TimeScale: TimeScale, +TimeSeriesScale: TimeSeriesScale +}); + +Chart.register(controllers, scales, elements, plugins); +Chart.helpers = _extends({}, helpers); +Chart._adapters = _adapters; +Chart.Animation = Animation; +Chart.Animations = Animations; +Chart.animator = animator; +Chart.controllers = registry.controllers.items; +Chart.DatasetController = DatasetController; +Chart.Element = Element$1; +Chart.elements = elements; +Chart.Interaction = Interaction; +Chart.layouts = layouts; +Chart.platforms = platforms; +Chart.Scale = Scale; +Chart.Ticks = Ticks; +_extends(Chart, controllers, scales, elements, plugins, platforms); +Chart.Chart = Chart; +if (typeof window !== 'undefined') { + window.Chart = Chart; +} + +return Chart; + +}))); diff --git a/dist/chart.min.js b/dist/chart.min.js new file mode 100644 index 00000000000..eb23f73de15 --- /dev/null +++ b/dist/chart.min.js @@ -0,0 +1,13 @@ +/*! + * Chart.js v3.0.0-beta.2 + * https://www.chartjs.org + * (c) 2020 Chart.js Contributors + * Released under the MIT License + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).Chart=e()}(this,(function(){"use strict";function t(t,e){for(var n=0;n=0;--s)(a=o[s])._active?(a.tick(e),l=!0):(o[s]=o[o.length-1],o.pop());l&&(r.draw(),t._notify(r,i,e,"progress")),r.options.animation.debug&&function(t,e,n,i){var r=1e3/(n-i)|0,a=t.ctx;a.save(),a.clearRect(0,0,50,24),a.fillStyle="black",a.textAlign="right",e&&(a.fillText(e,50,8),a.fillText(r+" fps",50,18)),a.restore()}(r,o.length,e,t._lastDate),o.length||(i.running=!1,t._notify(r,i,e,"complete")),n+=o.length}})),t._lastDate=e,0===n&&(t._running=!1)},e._getAnims=function(t){var e=this._charts,n=e.get(t);return n||(n={running:!1,items:[],listeners:{complete:[],progress:[]}},e.set(t,n)),n},e.listen=function(t,e,n){this._getAnims(t).listeners[e].push(n)},e.add=function(t,e){var n;e&&e.length&&(n=this._getAnims(t).items).push.apply(n,e)},e.has=function(t){return this._getAnims(t).items.length>0},e.start=function(t){var e=this._charts.get(t);e&&(e.running=!0,e.start=Date.now(),e.duration=e.items.reduce((function(t,e){return Math.max(t,e._duration)}),0),this._refresh())},e.running=function(t){if(!this._running)return!1;var e=this._charts.get(t);return!!(e&&e.running&&e.items.length)},e.stop=function(t){var e=this._charts.get(t);if(e&&e.items.length){for(var n=e.items,i=n.length-1;i>=0;--i)n[i].cancel();e.items=[],this._notify(t,e,Date.now(),"complete")}},e.remove=function(t){return this._charts.delete(t)},t}());function l(){}var c,u=(c=0,function(){return c++});function h(t){return null==t}function d(t){if(Array.isArray&&Array.isArray(t))return!0;var e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)}function f(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)}var p=function(t){return("number"==typeof t||t instanceof Number)&&isFinite(+t)};function g(t,e){return void 0===t?e:t}function v(t,e,n){if(t&&"function"==typeof t.call)return t.apply(n,e)}function m(t,e,n,i){var r,a,o;if(d(t))if(a=t.length,i)for(r=a-1;r>=0;r--)e.call(n,t[r],r);else for(r=0;ri&&(i=a),i}function I(t,e,n,i){var r=(i=i||{}).data=i.data||{},a=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(r=i.data={},a=i.garbageCollect=[],i.font=e),t.save(),t.font=e;var o,s,l,c,u,h=0,f=n.length;for(o=0;on.length){for(o=0;o0&&t.stroke()}}function W(t,e){var n=.5;return t.x>e.left-n&&t.xe.top-n&&t.y1;)n(i=a+r>>1)?a=i:r=i;return{lo:a,hi:r}}var X=function(t,e,n){return U(t,n,(function(i){return t[i][e]=n}))};function q(t,e,n){for(var i=0,r=t.length;ii&&t[r-1]>n;)r--;return i>0||r0||($.forEach((function(e){delete t[e]})),delete t._chartjs)}}function Q(t){var e,n,i=new Set;for(e=0,n=t.length;e0||l>0)n=s,i=l;else{var u=e.getBoundingClientRect();n=o.clientX-u.left,i=o.clientY-u.top,c=!0}return{x:n,y:i,box:c}}(t,n),c=l.x,u=l.y,h=l.box,d=o.left+(h&&s.left),f=o.top+(h&&s.top),p=e.width,g=e.height;return a&&(p-=o.width+s.width,g-=o.height+s.height),{x:Math.round((c-d)/p*n.width/i),y:Math.round((u-f)/g*n.height/i)}}var ot=Number.POSITIVE_INFINITY;function st(t,e,n,i){var r=et(t),a=rt(r,"margin"),o=tt(r.maxWidth,t,"clientWidth")||ot,s=tt(r.maxHeight,t,"clientHeight")||ot,l=function(t,e,n){var i,r;if(void 0===e||void 0===n){var a=J(t);if(a){var o=a.getBoundingClientRect(),s=et(a),l=rt(s,"border","width"),c=rt(s,"padding");e=o.width-c.width-l.width,n=o.height-c.height-l.height,i=tt(s.maxWidth,a,"clientWidth"),r=tt(s.maxHeight,a,"clientHeight")}else e=t.clientWidth,n=t.clientHeight}return{width:e,height:n,maxWidth:i||ot,maxHeight:r||ot}}(t,e,n),c=l.width,u=l.height;if("content-box"===r.boxSizing){var h=rt(r,"border","width"),d=rt(r,"padding");c-=d.width+h.width,u-=d.height+h.height}return c=Math.max(0,c-a.width),u=Math.max(0,i?Math.floor(c/i):u-a.height),{width:Math.min(c,o,l.maxWidth),height:Math.min(u,s,l.maxHeight)}}function lt(t,e){var n=t.currentDevicePixelRatio=e||"undefined"!=typeof window&&window.devicePixelRatio||1,i=t.canvas,r=t.width,a=t.height;i.height=a*n,i.width=r*n,t.ctx.setTransform(n,0,0,n,0,0),!i.style||i.style.height||i.style.width||(i.style.height=a+"px",i.style.width=r+"px")}var ct=function(){var t=!1;try{var e={get passive(){return t=!0,!1}};window.addEventListener("test",null,e),window.removeEventListener("test",null,e)}catch(t){}return t}();function ut(t,e){var n=nt(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?+i[1]:void 0}function ht(t,e){return"native"in t?{x:t.x,y:t.y}:at(t,e)}function dt(t,e,n,i){var r=t.controller,a=t.data,o=t._sorted,s=r._cachedMeta.iScale;if(s&&e===s.axis&&o&&a.length){var l=s._reversePixels?K:X;if(!i)return l(a,e,n);if(r._sharedOptions){var c=a[0],u="function"==typeof c.getRange&&c.getRange(e);if(u){var h=l(a,e,n-u),d=l(a,e,n+u);return{lo:h.lo,hi:d.hi}}}}return{lo:0,hi:a.length-1}}function ft(t,e,n,i,r){for(var a=t.getSortedVisibleDatasetMetas(),o=n[e],s=0,l=a.length;s0){var s=o[0].datasetIndex,l=t.getDatasetMeta(s).data;o=[];for(var c=0;c0},t.prototype.connect_=function(){zt&&!this.connected_&&(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),Nt?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},t.prototype.disconnect_=function(){zt&&this.connected_&&(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},t.prototype.onTransitionEnd_=function(t){var e=t.propertyName,n=void 0===e?"":e;Wt.some((function(t){return!!~n.indexOf(t)}))&&this.refresh()},t.getInstance=function(){return this.instance_||(this.instance_=new t),this.instance_},t.instance_=null,t}(),jt=function(t,e){for(var n=0,i=Object.keys(e);n0},t}(),ee="undefined"!=typeof WeakMap?new WeakMap:new It,ne=function t(e){if(!(this instanceof t))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var n=Ht.getInstance(),i=new te(e,n,this);ee.set(this,i)};["observe","unobserve","disconnect"].forEach((function(t){ne.prototype[t]=function(){var e;return(e=ee.get(this))[t].apply(e,arguments)}}));var ie=void 0!==Vt.ResizeObserver?Vt.ResizeObserver:ne,re={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"},ae=function(t){return null===t||""===t};var oe=!!ct&&{passive:!0};function se(t,e,n){t.canvas.removeEventListener(e,n,oe)}function le(t,e,n){var i=t.canvas,r=i&&J(i)||i,a=new MutationObserver((function(t){var e=J(r);t.forEach((function(t){for(var i=0;i=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e,n=0;return 0===t?0:1===t?1:(n||(n=.3),e=n/(2*Math.PI)*Math.asin(1),-1*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n))},easeOutElastic:function(t){var e,n=0;return 0===t?0:1===t?1:(n||(n=.3),e=n/(2*Math.PI)*Math.asin(1),1*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e,n=0;return 0===t?0:2==(t/=.5)?1:(n||(n=.45),e=n/(2*Math.PI)*Math.asin(1),t<1?1*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*-.5:1*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*.5+1)},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-Te.easeOutBounce(1-t)},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*Te.easeInBounce(2*t):.5*Te.easeOutBounce(2*t-1)+.5}},Oe={0:0,1:1,2:2,3:3,4:4,5:5,6:6,7:7,8:8,9:9,A:10,B:11,C:12,D:13,E:14,F:15,a:10,b:11,c:12,d:13,e:14,f:15},Ae="0123456789ABCDEF",Ee=function(t){return Ae[15&t]},Le=function(t){return Ae[(240&t)>>4]+Ae[15&t]},Ce=function(t){return(240&t)>>4==(15&t)}; +/*! + * @kurkle/color v0.1.9 + * https://github.com/kurkle/color#readme + * (c) 2020 Jukka Kurkela + * Released under the MIT License + */function Fe(t){var e=function(t){return Ce(t.r)&&Ce(t.g)&&Ce(t.b)&&Ce(t.a)}(t)?Ee:Le;return t?"#"+e(t.r)+e(t.g)+e(t.b)+(t.a<255?e(t.a):""):t}function Re(t){return t+.5|0}var Ie=function(t,e,n){return Math.max(Math.min(t,n),e)};function ze(t){return Ie(Re(2.55*t),0,255)}function Ve(t){return Ie(Re(255*t),0,255)}function Be(t){return Ie(Re(t/2.55)/100,0,1)}function We(t){return Ie(Re(100*t),0,100)}var Ne=/^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;var He=/^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;function je(t,e,n){var i=e*Math.min(n,1-n),r=function(e,r){return void 0===r&&(r=(e+t/30)%12),n-i*Math.max(Math.min(r-3,9-r,1),-1)};return[r(0),r(8),r(4)]}function Ye(t,e,n){var i=function(i,r){return void 0===r&&(r=(i+t/60)%6),n-n*e*Math.max(Math.min(r,4-r,1),0)};return[i(5),i(3),i(1)]}function Ue(t,e,n){var i,r=je(t,1,.5);for(e+n>1&&(e*=i=1/(e+n),n*=i),i=0;i<3;i++)r[i]*=1-e-n,r[i]+=e;return r}function Xe(t){var e,n,i,r=t.r/255,a=t.g/255,o=t.b/255,s=Math.max(r,a,o),l=Math.min(r,a,o),c=(s+l)/2;return s!==l&&(i=s-l,n=c>.5?i/(2-s-l):i/(s+l),e=60*(e=s===r?(a-o)/i+(a>16&255,n>>8&255,255&n]}return a}()).transparent=[0,0,0,0]);var e=Ze[t.toLowerCase()];return e&&{r:e[0],g:e[1],b:e[2],a:4===e.length?e[3]:255}}function en(t,e,n){if(t){var i=Xe(t);i[e]=Math.max(0,Math.min(i[e]+i[e]*n,0===e?360:1)),i=qe(i),t.r=i[0],t.g=i[1],t.b=i[2]}}function nn(t,e){return t?n(e||{},t):t}function rn(t){var e={r:0,g:0,b:0,a:255};return Array.isArray(t)?t.length>=3&&(e={r:t[0],g:t[1],b:t[2],a:255},t.length>3&&(e.a=Ve(t[3]))):(e=nn(t,{r:0,g:0,b:0,a:1})).a=Ve(e.a),e}function an(t){return"r"===t.charAt(0)?function(t){var e,n,i,r=Ne.exec(t),a=255;if(r){if(r[7]!==e){var o=+r[7];a=255&(r[8]?ze(o):255*o)}return e=+r[1],n=+r[3],i=+r[5],{r:e=255&(r[2]?ze(e):e),g:n=255&(r[4]?ze(n):n),b:i=255&(r[6]?ze(i):i),a:a}}}(t):Ge(t)}var on=function(){function t(e){if(e instanceof t)return e;var n,i,r,a,o=typeof e;"object"===o?n=rn(e):"string"===o&&(a=(i=e).length,"#"===i[0]&&(4===a||5===a?r={r:255&17*Oe[i[1]],g:255&17*Oe[i[2]],b:255&17*Oe[i[3]],a:5===a?17*Oe[i[4]]:255}:7!==a&&9!==a||(r={r:Oe[i[1]]<<4|Oe[i[2]],g:Oe[i[3]]<<4|Oe[i[4]],b:Oe[i[5]]<<4|Oe[i[6]],a:9===a?Oe[i[7]]<<4|Oe[i[8]]:255})),n=r||tn(e)||an(e)),this._rgb=n,this._valid=!!n}var n=t.prototype;return n.rgbString=function(){return this._valid?(t=this._rgb)&&(t.a<255?"rgba("+t.r+", "+t.g+", "+t.b+", "+Be(t.a)+")":"rgb("+t.r+", "+t.g+", "+t.b+")"):this._rgb;var t},n.hexString=function(){return this._valid?Fe(this._rgb):this._rgb},n.hslString=function(){return this._valid?function(t){if(t){var e=Xe(t),n=e[0],i=We(e[1]),r=We(e[2]);return t.a<255?"hsla("+n+", "+i+"%, "+r+"%, "+Be(t.a)+")":"hsl("+n+", "+i+"%, "+r+"%)"}}(this._rgb):this._rgb},n.mix=function(t,e){var n=this;if(t){var i,r=n.rgb,a=t.rgb,o=e===i?.5:e,s=2*o-1,l=r.a-a.a,c=((s*l==-1?s:(s+l)/(1+s*l))+1)/2;i=1-c,r.r=255&c*r.r+i*a.r+.5,r.g=255&c*r.g+i*a.g+.5,r.b=255&c*r.b+i*a.b+.5,r.a=o*r.a+(1-o)*a.a,n.rgb=r}return n},n.clone=function(){return new t(this.rgb)},n.alpha=function(t){return this._rgb.a=Ve(t),this},n.clearer=function(t){return this._rgb.a*=1-t,this},n.greyscale=function(){var t=this._rgb,e=Re(.3*t.r+.59*t.g+.11*t.b);return t.r=t.g=t.b=e,this},n.opaquer=function(t){return this._rgb.a*=1+t,this},n.negate=function(){var t=this._rgb;return t.r=255-t.r,t.g=255-t.g,t.b=255-t.b,this},n.lighten=function(t){return en(this._rgb,2,t),this},n.darken=function(t){return en(this._rgb,2,-t),this},n.saturate=function(t){return en(this._rgb,1,t),this},n.desaturate=function(t){return en(this._rgb,1,-t),this},n.rotate=function(t){return function(t,e){var n=Xe(t);n[0]=$e(n[0]+e),n=qe(n),t.r=n[0],t.g=n[1],t.b=n[2]}(this._rgb,t),this},e(t,[{key:"valid",get:function(){return this._valid}},{key:"rgb",get:function(){var t=nn(this._rgb);return t&&(t.a=Be(t.a)),t},set:function(t){this._rgb=rn(t)}}]),t}();function sn(t){return new on(t)}var ln=function(t){return t instanceof CanvasGradient||t instanceof CanvasPattern};function cn(t){return ln(t)?t:sn(t)}function un(t){return ln(t)?t:sn(t).saturate(.5).darken(.1).hexString()}var hn="transparent",dn={boolean:function(t,e,n){return n>.5?e:t},color:function(t,e,n){var i=cn(t||hn),r=i.valid&&cn(e||hn);return r&&r.valid?r.mix(i,n).hexString():e},number:function(t,e,n){return t+(e-t)*n}},fn=function(){function t(t,e,n,i){var r=e[n];i=Mt([t.to,i,r,t.from]);var a=Mt([t.from,r,i]);this._active=!0,this._fn=t.fn||dn[t.type||typeof a],this._easing=Te[t.easing||"linear"],this._start=Math.floor(Date.now()+(t.delay||0)),this._duration=Math.floor(t.duration),this._loop=!!t.loop,this._target=e,this._prop=n,this._from=a,this._to=i,this._promises=void 0}var e=t.prototype;return e.active=function(){return this._active},e.update=function(t,e,n){var i=this;if(i._active){var r=i._target[i._prop],a=n-i._start,o=i._duration-a;i._start=n,i._duration=Math.floor(Math.max(o,t.duration)),i._loop=!!t.loop,i._to=Mt([t.to,e,r,t.from]),i._from=Mt([t.from,r,e])}},e.cancel=function(){var t=this;t._active&&(t.tick(Date.now()),t._active=!1,t._notify(!1))},e.tick=function(t){var e,n=this,i=t-n._start,r=n._duration,a=n._prop,o=n._from,s=n._loop,l=n._to;if(n._active=o!==l&&(s||i1?2-e:e,e=n._easing(Math.min(1,Math.max(0,e))),n._target[a]=n._fn(o,l,e))},e.wait=function(){var t=this._promises||(this._promises=[]);return new _e((function(e,n){t.push({res:e,rej:n})}))},e._notify=function(t){for(var e=t?"res":"rej",n=this._promises||[],i=0;i=0||(r[n]=t[n]);return r}(o,["properties"]));e.set(t,n({},s,a))}}else e.set(t,n({},i,a))}))}))}},e._animateOptions=function(t,e){var i=e.options,r=function(t,e){if(!e)return;var i=t.options;if(!i)return void(t.options=e);i.$shared&&!e.$shared&&(t.options=i=n({},i,{$shared:!1,$animations:{}}));return i}(t,i);if(!r)return[];var a=this._createAnimations(r,i);return i.$shared&&!r.$shared&&function(t,e){for(var n=[],i=Object.keys(e),r=0;r=0;--n){var l=o[n];if("$"!==l.charAt(0))if("options"!==l){var c=e[l],u=a[l],h=i.get(l);if(u){if(h&&u.active()){u.update(h,c,s);continue}u.cancel()}h&&h.duration?(a[l]=u=new fn(h,t,l,c),r.push(u)):t[l]=c}else r.push.apply(r,this._animateOptions(t,e))}return r},e.update=function(t,e){if(0===this._properties.size)return function(t,e){var i=t.options,r=e.options;i&&r&&(i.$shared&&!r.$shared?t.options=n({},i,r,{$shared:!1}):n(i,r),delete e.options)}(t,e),void n(t,e);var i=this._createAnimations(t,e);return i.length?(s.add(this._chart,i),!0):void 0},t}();var vn=Math.PI,mn=2*vn,bn=mn+vn;function xn(t){var e,n=[],i=Math.sqrt(t);for(e=1;e=t}function kn(t,e,n){var i,r,a;for(i=0,r=t.length;i0?1:-1};function Sn(t){return t*(vn/180)}function Dn(t){return t*(180/vn)}function Tn(t){if(p(t)){for(var e=1,n=0;Math.round(t*e)/e!==t;)e*=10,n++;return n}}function On(t,e){var n=e.x-t.x,i=e.y-t.y,r=Math.sqrt(n*n+i*i),a=Math.atan2(i,n);return a<-.5*vn&&(a+=mn),{angle:a,distance:r}}function An(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))}function En(t,e){return(t-e+bn)%mn-vn}function Ln(t){return(t%mn+mn)%mn}function Cn(t,e,n){var i=Ln(t),r=Ln(e),a=Ln(n),o=Ln(r-i),s=Ln(a-i),l=Ln(i-r),c=Ln(i-a);return i===r||i===a||o>s&&l0&&(g=s._sorted,a=s._parsed[t-1]),!1===o._parsing)s._parsed=l,s._sorted=!0;else{i=d(l[t])?o.parseArrayData(s,l,t,e):f(l[t])?o.parseObjectData(s,l,t,e):o.parsePrimitiveData(s,l,t,e);for(n=0;na||v=0;--n)if(!m()){o.updateRangeFromParsed(f,t,r,d);break}return f},e.getAllParsedValues=function(t){var e,n,i,r=this._cachedMeta._parsed,a=[];for(e=0,n=r.length;e=0;a--)n=r[a],e[n]=un(i[n])},e.getStyle=function(t,e){var n=this,i=n._cachedMeta.dataset;n._config||n.configure();var r=i&&void 0===t?n.resolveDatasetElementOptions(e):n.resolveDataElementOptions(t||0,e&&"active");return e&&n._addAutomaticHoverColors(t,r),r},e._getContext=function(t,e){return{chart:this.chart,dataPoint:this.getParsed(t),dataIndex:t,dataset:this.getDataset(),datasetIndex:this.index,active:e}},e.resolveDatasetElementOptions=function(t){return this._resolveOptions(this.datasetElementOptions,{active:t,type:this.datasetElementType.id})},e.resolveDataElementOptions=function(t,e){var n=this,i="active"===(e=e||"default"),r=n._cachedDataOpts,a=n.enableOptionSharing;if(r[e])return r[e];var o={cacheable:!i},s=n._resolveOptions(n.dataElementOptions,{index:t,active:i,info:o,type:n.dataElementType.id});return o.cacheable&&(s.$shared=a,r[e]=a?Object.freeze(s):s),s},e._resolveOptions=function(t,e){for(var n=this,i=e.index,r=e.active,a=e.type,o=e.info,s=n._config,l=n.chart.options.elements[a]||{},c={},u=n._getContext(i,r),h=function(t){return d(t)?t:Object.keys(t)}(t),f=0,p=h.length;fn?t._insertElements(n,i-n):i1e15)&&(r="scientific");var s=i.length>3?i[2].value-i[1].value:i[1].value-i[0].value;Math.abs(s)>1&&t!==Math.floor(t)&&(s=t-Math.floor(t));var l=yn(Math.abs(s)),c=Math.max(Math.min(-1*Math.floor(l),20),0),u={notation:r,minimumFractionDigits:c,maximumFractionDigits:c};n(u,this.options.ticks.format);var h=a+JSON.stringify(u),d=Kn.get(h);return d||(d=new Intl.NumberFormat(a,u),Kn.set(h,d)),d.format(t)},logarithmic:function(t,e,n){if(0===t)return"0";var i=t/Math.pow(10,Math.floor(yn(t)));return 1===i||2===i||5===i?qn.numeric.call(this,t,e,n):""}},$n={formatters:qn};function Gn(t,e){for(var n=[],i=t.length/e,r=t.length,a=0;as+l)))return c}function Qn(t){return t.drawTicks?t.tickMarkLength:0}function Jn(t,e){if(!t.display)return 0;var n=wt(t.font,e),i=_t(t.padding);return n.lineHeight+i.height}function ti(t,e,n,i,r){var a,o,s,l=g(i,0),c=Math.min(g(r,t.length),t.length),u=0;for(n=Math.ceil(n),r&&(n=(a=r-i)/Math.floor(a/n)),s=l;s<0;)u++,s=Math.round(l+u*n);for(o=Math.max(l,0);o=l||o<=1||!i.isHorizontal())i.labelRotation=s;else{var u=i._getLabelSizes(),h=u.widest.width,d=u.highest.height-u.highest.offset,f=Math.min(i.maxWidth,i.chart.width-h);h+6>(t=r.offset?i.maxWidth/o:f/(o-1))&&(t=f/(o-(r.offset?.5:1)),e=i.maxHeight-Qn(r.gridLines)-a.padding-Jn(r.scaleLabel,i.chart.options.font),n=Math.sqrt(h*h+d*d),c=Dn(Math.min(Math.asin(Math.min((u.highest.height+6)/t,1)),Math.asin(Math.min(e/n,1))-Math.asin(d/n))),c=Math.max(s,Math.min(l,c))),i.labelRotation=c}},r.afterCalculateLabelRotation=function(){v(this.options.afterCalculateLabelRotation,[this])},r.beforeFit=function(){v(this.options.beforeFit,[this])},r.fit=function(){var t=this,e={width:0,height:0},n=t.chart,i=t.options,r=i.ticks,a=i.scaleLabel,o=i.gridLines,s=t._isVisible(),l="top"!==i.position&&"x"===t.axis,c=t.isHorizontal(),u=s&&Jn(a,n.options.font);if(c?e.width=t.maxWidth:s&&(e.width=Qn(o)+u),c?s&&(e.height=Qn(o)+u):e.height=t.maxHeight,r.display&&s&&t.ticks.length){var h=t._getLabelSizes(),d=h.first,f=h.last,p=h.widest,g=h.highest,v=.8*g.offset,m=r.padding;if(c){var b=0!==t.labelRotation,x=Sn(t.labelRotation),y=Math.cos(x),_=Math.sin(x),w=_*p.width+y*(g.height-(b?g.offset:0))+(b?0:v);e.height=Math.min(t.maxHeight,e.height+w+m);var M,k,P=t.getPixelForTick(0)-t.left,S=t.right-t.getPixelForTick(t.ticks.length-1);b?(M=l?y*d.width+_*d.offset:_*(d.height-d.offset),k=l?_*(f.height-f.offset):y*f.width+_*f.offset):(M=d.width/2,k=f.width/2),t.paddingLeft=Math.max((M-P)*t.width/(t.width-P),0)+3,t.paddingRight=Math.max((k-S)*t.width/(t.width-S),0)+3}else{var D=r.mirror?0:p.width+m+v;e.width=Math.min(t.maxWidth,e.width+D),t.paddingTop=f.height/2,t.paddingBottom=d.height/2}}t._handleMargins(),c?(t.width=t._length=n.width-t._margins.left-t._margins.right,t.height=e.height):(t.width=e.width,t.height=t._length=n.height-t._margins.top-t._margins.bottom)},r._handleMargins=function(){var t=this;t._margins&&(t._margins.left=Math.max(t.paddingLeft,t._margins.left),t._margins.top=Math.max(t.paddingTop,t._margins.top),t._margins.right=Math.max(t.paddingRight,t._margins.right),t._margins.bottom=Math.max(t.paddingBottom,t._margins.bottom))},r.afterFit=function(){v(this.options.afterFit,[this])},r.isHorizontal=function(){var t=this.options,e=t.axis,n=t.position;return"top"===n||"bottom"===n||"x"===e},r.isFullWidth=function(){return this.options.fullWidth},r._convertTicksToLabels=function(t){var e=this;e.beforeTickToLabelConversion(),e.generateTickLabels(t),e.afterTickToLabelConversion()},r._getLabelSizes=function(){var t=this,e=t._labelSizes;return e||(t._labelSizes=e=t._computeLabelSizes()),e},r._computeLabelSizes=function(){var t=this,e=t.ctx,n=t._longestTextCache,i=t.options.ticks.sampleSize,r=[],a=[],o=[],s=t.ticks;ie){for(n=0;ne.length-1?null:this.getPixelForValue(e[t].value)},r.getPixelForDecimal=function(t){var e=this;return e._reversePixels&&(t=1-t),Rn(e._startPixel+t*e._length)},r.getDecimalForPixel=function(t){var e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e},r.getBasePixel=function(){return this.getPixelForValue(this.getBaseValue())},r.getBaseValue=function(){var t=this.min,e=this.max;return t<0&&e<0?e:t>0&&e>0?t:0},r._autoSkip=function(t){var e=this,n=e.options.ticks,i=n.maxTicksLimit||e._length/e._tickSize(),r=n.major.enabled?function(t){var e,n,i=[];for(e=0,n=t.length;ei)return function(t,e,n,i){var r,a=0,o=n[0];for(i=Math.ceil(i),r=0;rr)return l}return Math.max(r,1)}(r,t,i);if(a>0){var u,d,f=a>1?Math.round((s-o)/(a-1)):null;for(ti(t,l,c,h(f)?0:o-f,o),u=0,d=a-1;us*r?s/i:l/r:l*r0},r._computeGridLineItems=function(t){var e,n,i,r,a,o,s,l,c,u,h,d,p=this,g=p.axis,v=p.chart,m=p.options,b=m.gridLines,x=m.position,y=b.offsetGridLines,_=p.isHorizontal(),w=p.ticks,M=w.length+(y?1:0),k=Qn(b),P=[],S={chart:v,scale:p,tick:w[0],index:0},D=b.drawBorder?Mt([b.borderWidth,b.lineWidth,0],S,0):0,T=D/2,O=function(t){return z(v,t,D)};if("top"===x)e=O(p.bottom),o=p.bottom-k,l=e-T,u=O(t.top)+T,d=t.bottom;else if("bottom"===x)e=O(p.top),u=t.top,d=O(t.bottom)-T,o=e+T,l=p.top+k;else if("left"===x)e=O(p.right),a=p.right-k,s=e-T,c=O(t.left)+T,h=t.right;else if("right"===x)e=O(p.left),c=t.left,h=O(t.right)-T,a=e+T,s=p.left+k;else if("x"===g){if("center"===x)e=O((t.top+t.bottom)/2);else if(f(x)){var A=Object.keys(x)[0],E=x[A];e=O(p.chart.scales[A].getPixelForValue(E))}u=t.top,d=t.bottom,l=(o=e+T)+k}else if("y"===g){if("center"===x)e=O((t.left+t.right)/2);else if(f(x)){var L=Object.keys(x)[0],C=x[L];e=O(p.chart.scales[L].getPixelForValue(C))}s=(a=e-T)-k,c=t.left,h=t.right}for(n=0;n0&&""!==c.strokeStyle;o.save(),o.translate(l.x,l.y),o.rotate(l.rotation),o.font=c.string,o.fillStyle=c.color,o.textBaseline="middle",o.textAlign=l.textAlign,u&&(o.strokeStyle=c.strokeStyle,o.lineWidth=c.lineWidth);var h=l.label,f=l.textOffset;if(d(h))for(i=0,a=h.length;in){for(var r=n;r=0;--n)t._drawDataset(e[n]);t._plugins.notify(t,"afterDatasetsDraw")}},e._drawDataset=function(t){var e=this,n=e.ctx,i=t._clip,r=e.chartArea,a={meta:t,index:t.index};!1!==e._plugins.notify(e,"beforeDatasetDraw",[a])&&(N(n,{left:!1===i.left?0:r.left-i.left,right:!1===i.right?e.width:r.right+i.right,top:!1===i.top?0:r.top-i.top,bottom:!1===i.bottom?e.height:r.bottom+i.bottom}),t.controller.draw(),H(n),e._plugins.notify(e,"afterDatasetDraw",[a]))},e.getElementAtEvent=function(t){return mt.modes.nearest(this,t,{intersect:!0})},e.getElementsAtEvent=function(t){return mt.modes.index(this,t,{intersect:!0})},e.getElementsAtXAxis=function(t){return mt.modes.index(this,t,{intersect:!1})},e.getElementsAtEventForMode=function(t,e,n,i){var r=mt.modes[e];return"function"==typeof r?r(this,t,n,i):[]},e.getDatasetAtEvent=function(t){return mt.modes.dataset(this,t,{intersect:!0})},e.getDatasetMeta=function(t){var e=this.data.datasets[t],n=this._metasets,i=n.filter((function(t){return t._dataset===e})).pop();return i||(i=n[t]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e.order||0,index:t,_dataset:e,_parsed:[],_sorted:!1}),i},e.getVisibleDatasetCount=function(){return this.getSortedVisibleDatasetMetas().length},e.isDatasetVisible=function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},e.setDatasetVisibility=function(t,e){this.getDatasetMeta(t).hidden=!e},e.toggleDataVisibility=function(t){this._hiddenIndices[t]=!this._hiddenIndices[t]},e.getDataVisibility=function(t){return!this._hiddenIndices[t]},e._updateDatasetVisibility=function(t,e){var n=this,i=e?"show":"hide",r=n.getDatasetMeta(t),a=r.controller._resolveAnimations(void 0,i);n.setDatasetVisibility(t,e),a.update(r,{visible:e}),n.update((function(e){return e.datasetIndex===t?i:void 0}))},e.hide=function(t){this._updateDatasetVisibility(t,!1)},e.show=function(t){this._updateDatasetVisibility(t,!0)},e._destroyDatasetMeta=function(t){var e=this,n=e._metasets&&e._metasets[t];n&&(n.controller._destroy(),delete e._metasets[t])},e.destroy=function(){var e,n,i=this,r=i.canvas;for(i.stop(),s.remove(i),e=0,n=i.data.datasets.length;e0?u[e-1]:null,(r=e0?u[e-1]:null,r=e0&&W(t[n-1],e)&&(r.controlPointPreviousX=yi(r.controlPointPreviousX,e.left,e.right),r.controlPointPreviousY=yi(r.controlPointPreviousY,e.top,e.bottom)),n0?e.y:t.y}}function ki(t,e,n,i){var r={x:t.controlPointNextX,y:t.controlPointNextY},a={x:e.controlPointPreviousX,y:e.controlPointPreviousY},o=wi(t,r,n),s=wi(r,a,n),l=wi(a,e,n),c=wi(o,s,n),u=wi(s,l,n);return wi(c,u,n)}function Pi(t,e,n){return t?function(t,e){return{x:function(n){return t+t+e-n},setWidth:function(t){e=t},textAlign:function(t){return"center"===t?t:"right"===t?"left":"right"},xPlus:function(t,e){return t-e},leftForLtr:function(t,e){return t-e}}}(e,n):{x:function(t){return t},setWidth:function(t){},textAlign:function(t){return t},xPlus:function(t,e){return t+e},leftForLtr:function(t,e){return t}}}function Si(t,e){var n,i;"ltr"!==e&&"rtl"!==e||(i=[(n=t.canvas.style).getPropertyValue("direction"),n.getPropertyPriority("direction")],n.setProperty("direction",e,"important"),t.prevTextDirection=i)}function Di(t,e){void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}function Ti(t){return"angle"===t?{between:Cn,compare:En,normalize:Ln}:{between:function(t,e,n){return t>=e&&t<=n},compare:function(t,e){return t-e},normalize:function(t){return t}}}function Oi(t,e,n,i){return{start:t%i,end:e%i,loop:n&&(e-t+1)%i==0}}function Ai(t,e,n){if(!n)return[t];for(var i,r,a,o=n.property,s=n.start,l=n.end,c=e.length,u=Ti(o),h=u.compare,d=u.between,f=u.normalize,p=function(t,e,n){var i,r,a=n.property,o=n.start,s=n.end,l=Ti(a),c=l.between,u=l.normalize,h=e.length,d=t.start,f=t.end,p=t.loop;if(p){for(d+=h,f+=h,i=0,r=h;ir&&t[a%e].skip;)a--;return{start:r,end:a%=e}}(e,i,r,n),o=a.start,s=a.end;return!0===n?[{start:o,end:s,loop:r}]:function(t,e,n,i){var r,a=t.length,o=[],s=e,l=t[e];for(r=e+1;r<=n;++r){var c=t[r%a];c.skip||c.stop?l.skip||(i=!1,o.push({start:e%a,end:(r-1)%a,loop:i}),e=s=c.stop?r:null):(s=r,l.skip&&(e=r)),l=c}return null!==s&&o.push({start:e%a,end:s%a,loop:i}),o}(e,o,sMath.abs(s)&&(l=s,c=o),e[n.axis]=c,e._custom={barStart:l,barEnd:c,start:r,end:a,min:o,max:s}}(t,e,n,i):e[n.axis]=n.parse(t,i),e}function Vi(t,e,n,i){var r,a,o,s,l=t.iScale,c=t.vScale,u=l.getLabels(),h=l===c,d=[];for(r=n,a=n+i;r0?Math.min(o,Math.abs(i-n)):o,n=i;return o}(r,a),pixels:a,start:r._startPixel,end:r._endPixel,stackCount:n._getStackCount(),scale:r}},n._calculateBarValuePixels=function(t,e){var n,i,r=this,a=r._cachedMeta,o=a.vScale,s=e.minBarLength,l=r.getParsed(t),c=l._custom,u=l[o.axis],h=0,d=a._stacked?r.applyStack(o,l):u;d!==u&&(h=d-u,d=u),Bi(c)&&(u=c.barStart,d=c.barEnd-c.barStart,0!==u&&Pn(u)!==Pn(c.barEnd)&&(h=0),h+=u);var f=Fn(o.getPixelForValue(h),o._startPixel-10,o._endPixel+10);return i=(n=o.getPixelForValue(h+d))-f,void 0!==s&&Math.abs(i)0?i[t-1]:null,o=t=0;--t)e=Math.max(e,this.getStyle(t,!0).radius);return e>0&&e},r.getLabelAndValue=function(t){var e=this._cachedMeta,n=e.xScale,i=e.yScale,r=this.getParsed(t),a=n.getLabelForValue(r.x),o=i.getLabelForValue(r.y),s=r._custom;return{label:e.label,value:"("+a+", "+o+(s?", "+s:"")+")"}},r.update=function(t){var e=this._cachedMeta.data;this.updateElements(e,0,e.length,t)},r.updateElements=function(t,e,n,i){for(var r=this,a="reset"===i,o=r._cachedMeta,s=o.xScale,l=o.yScale,c=r.resolveDataElementOptions(e,i),u=r.getSharedOptions(c),h=r.includeOptions(i,u),d=e;d=Hi?-ji:s<-Hi?ji:0)+e,c=Math.cos(s),u=Math.sin(s),h=Math.cos(l),d=Math.sin(l),f=s<=0&&l>=0||l>=ji,p=s<=Yi&&l>=Yi||l>=ji+Yi,g=s<=-Yi&&l>=-Yi||l>=Hi+Yi,v=s===-Hi||l>=Hi?-1:Math.min(c,c*n,h,h*n),m=g?-1:Math.min(u,u*n,d,d*n),b=f?1:Math.max(c,c*n,h,h*n),x=p?1:Math.max(u,u*n,d,d*n);i=(b-v)/2,r=(x-m)/2,a=-(b+v)/2,o=-(x+m)/2}return{ratioX:i,ratioY:r,offsetX:a,offsetY:o}}(r.rotation,r.circumference,s),u=c.ratioX,h=c.ratioY,d=c.offsetX,f=c.offsetY,p=e.getMaxBorderWidth()+e.getMaxOffset(o),g=(i.right-i.left-p)/u,v=(i.bottom-i.top-p)/h,m=Math.max(Math.min(g,v)/2,0),b=(m-Math.max(m*s,0))/e._getVisibleDatasetWeightTotal();e.offsetX=d*m,e.offsetY=f*m,a.total=e.calculateTotal(),e.outerRadius=m-b*e._getRingWeightOffset(e.index),e.innerRadius=Math.max(e.outerRadius-b*l,0),e.updateElements(o,0,o.length,t)},n._circumference=function(t,e){var n=this,i=n.chart.options,r=n._cachedMeta;return e&&i.animation.animateRotate?0:this.chart.getDataVisibility(t)?n.calculateCircumference(r._parsed[t]*i.circumference/ji):0},n.updateElements=function(t,e,n,i){var r,a=this,o="reset"===i,s=a.chart,l=s.chartArea,c=s.options,u=c.animation,h=(l.left+l.right)/2,d=(l.top+l.bottom)/2,f=o&&u.animateScale,p=f?0:a.innerRadius,g=f?0:a.outerRadius,v=a.resolveDataElementOptions(e,i),m=a.getSharedOptions(v),b=a.includeOptions(i,m),x=c.rotation;for(r=0;r0&&!isNaN(t)?ji*(Math.abs(t)/e):0},n.getLabelAndValue=function(t){var e=this._cachedMeta;return{label:(this.chart.data.labels||[])[t]||"",value:e._parsed[t]}},n.getMaxBorderWidth=function(t){var e,n,i,r,a,o=0,s=this.chart;if(!t)for(e=0,n=s.data.datasets.length;e0&&r.getParsed(e-1),m=e;m0&&x.x-v.x>p};d&&(w.options=h||r.resolveDataElementOptions(m,i)),r.updateElement(b,m,w,i),v=x}r.updateSharedOptions(h,i,u)},r.resolveDatasetElementOptions=function(e){var n=this._config,i=this.chart.options,r=i.elements.line,a=t.prototype.resolveDatasetElementOptions.call(this,e),o=g(n.showLine,i.showLines);return a.spanGaps=g(n.spanGaps,i.spanGaps),a.tension=g(n.lineTension,r.tension),a.stepped=Mt([n.stepped,r.stepped]),o||(a.borderWidth=0),a},r.getMaxOverflow=function(){var t=this._cachedMeta,e=t.dataset.options.borderWidth||0,n=t.data||[];if(!n.length)return e;var i=n[0].size(),r=n[n.length-1].size();return Math.max(e,i,r)/2},r.draw=function(){this._cachedMeta.dataset.updateControlPoints(this.chart.chartArea),t.prototype.draw.call(this)},e}(Un);Xi.id="line",Xi.defaults={datasetElementType:"line",datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth","capBezierPoints","cubicInterpolationMode","fill"],dataElementType:"point",dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverHitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},showLines:!0,spanGaps:!1,hover:{mode:"index"},scales:{_index_:{type:"category"},_value_:{type:"linear"}}};var Ki=function(t){function e(e,n){var i;return(i=t.call(this,e,n)||this).innerRadius=void 0,i.outerRadius=void 0,i}i(e,t);var n=e.prototype;return n.update=function(t){var e=this._cachedMeta.data;this._updateRadius(),this.updateElements(e,0,e.length,t)},n._updateRadius=function(){var t=this,e=t.chart,n=e.chartArea,i=e.options,r=Math.min(n.right-n.left,n.bottom-n.top),a=Math.max(r/2,0),o=(a-Math.max(i.cutoutPercentage?a/100*i.cutoutPercentage:1,0))/e.getVisibleDatasetCount();t.outerRadius=a-o*t.index,t.innerRadius=t.outerRadius-o},n.updateElements=function(t,e,n,i){var r,a=this,o="reset"===i,s=a.chart,l=a.getDataset(),c=s.options,u=c.animation,h=a._cachedMeta.rScale,d=h.xCenter,f=h.yCenter,p=Sn(c.startAngle)-.5*Math.PI,g=p;for(a._cachedMeta.count=a.countVisibleElements(),r=0;rr?(c=r/l,t.arc(a,o,l,i+c,n-c,!0)):t.arc(a,o,r,i+Math.PI/2,n-Math.PI/2),t.closePath(),t.clip()}function tr(t,e){var n=e.x,i=e.y,r=e.startAngle,a=e.endAngle,o=e.pixelMargin,s=Math.max(e.outerRadius-o,0),l=e.innerRadius+o;t.beginPath(),t.arc(n,i,s,r,a),t.arc(n,i,l,a,r,!0),t.closePath()}function er(t,e){var n=e.x,i=e.y,r=e.startAngle,a=e.endAngle,o=e.pixelMargin,s=e.options,l=e.outerRadius,c=e.innerRadius+o,u="inner"===s.borderAlign;s.borderWidth&&(u?(t.lineWidth=2*s.borderWidth,t.lineJoin="round"):(t.lineWidth=s.borderWidth,t.lineJoin="bevel"),e.fullCircles&&function(t,e,n){var i,r=e.x,a=e.y,o=e.startAngle,s=e.endAngle,l=e.pixelMargin,c=Math.max(e.outerRadius-l,0),u=e.innerRadius+l;for(n&&(e.endAngle=e.startAngle+Qi,Ji(t,e),e.endAngle=s,e.endAngle===e.startAngle&&(e.endAngle+=Qi,e.fullCircles--)),t.beginPath(),t.arc(r,a,u,o+Qi,o,!0),i=0;i=Qi||Cn(r,s,l))&&(a>=c&&a<=u)},a.getCenterPoint=function(t){var e=this.getProps(["x","y","startAngle","endAngle","innerRadius","outerRadius"],t),n=e.x,i=e.y,r=(e.startAngle+e.endAngle)/2,a=(e.innerRadius+e.outerRadius)/2;return{x:n+Math.cos(r)*a,y:i+Math.sin(r)*a}},a.tooltipPosition=function(t){return this.getCenterPoint(t)},a.draw=function(t){var e=this,n=e.options,i=n.offset||0;if(e.pixelMargin="inner"===n.borderAlign?.33:0,e.fullCircles=Math.floor(e.circumference/Qi),0!==e.circumference){if(t.save(),i&&e.circumferencel&&(l=k),x=(y*x+M)/++y):(w(),t.lineTo(M,k),o=P,y=0,s=l=k),c=k}w()}function sr(t){var e=t.options,n=e.borderDash&&e.borderDash.length;return!(t._loop||e.tension||e.stepped||n)?or:ar}nr.id="arc",nr.defaults={borderAlign:"center",borderColor:"#fff",borderWidth:2,offset:0},nr.defaultRoutes={backgroundColor:"color"};var lr=function(t){function a(e){var i;return(i=t.call(this)||this).options=void 0,i._loop=void 0,i._fullLoop=void 0,i._points=void 0,i._segments=void 0,i._pointsUpdated=!1,e&&n(r(i),e),i}i(a,t);var o=a.prototype;return o.updateControlPoints=function(t){var e=this,n=e.options;if(n.tension&&!n.stepped&&!e._pointsUpdated){var i=n.spanGaps?e._loop:e._fullLoop;_i(e._points,n,t,i),e._pointsUpdated=!0}},o.first=function(){var t=this.segments,e=this.points;return t.length&&e[t[0].start]},o.last=function(){var t=this.segments,e=this.points,n=t.length;return n&&e[t[n-1].end]},o.interpolate=function(t,e){var n=this,i=n.options,r=t[e],a=n.points,o=Ei(n,{property:e,start:r,end:r});if(o.length){var s,l,c=[],u=function(t){return t.stepped?Mi:t.tension?ki:wi}(i);for(s=0,l=o.length;st.x):hr(e,"bottom","top",t.base=o.left&&e<=o.right)&&(a||n>=o.top&&n<=o.bottom)}cr.id="point",cr.defaults={borderWidth:1,hitRadius:1,hoverBorderWidth:1,hoverRadius:4,pointStyle:"circle",radius:3},cr.defaultRoutes={backgroundColor:"color",borderColor:"color"};var vr=function(t){function e(e){var i;return(i=t.call(this)||this).options=void 0,i.horizontal=void 0,i.base=void 0,i.width=void 0,i.height=void 0,e&&n(r(i),e),i}i(e,t);var a=e.prototype;return a.draw=function(t){var e,n,i,r,a,o=this.options,s=(n=ur(e=this),i=n.right-n.left,r=n.bottom-n.top,a=pr(e,i/2,r/2),{outer:{x:n.left,y:n.top,w:i,h:r},inner:{x:n.left+a.l,y:n.top+a.t,w:i-a.l-a.r,h:r-a.t-a.b}}),l=s.inner,c=s.outer;t.save(),c.w===l.w&&c.h===l.h||(t.beginPath(),t.rect(c.x,c.y,c.w,c.h),t.clip(),t.rect(l.x,l.y,l.w,l.h),t.fillStyle=o.borderColor,t.fill("evenodd")),t.fillStyle=o.backgroundColor,t.fillRect(l.x,l.y,l.w,l.h),t.restore()},a.inRange=function(t,e,n){return gr(this,t,e,n)},a.inXRange=function(t,e){return gr(this,t,null,e)},a.inYRange=function(t,e){return gr(this,null,t,e)},a.getCenterPoint=function(t){var e=this.getProps(["x","y","base","horizontal"],t),n=e.x,i=e.y,r=e.base,a=e.horizontal;return{x:a?(n+r)/2:n,y:a?i:(i+r)/2}},a.getRange=function(t){return"x"===t?this.width/2:this.height/2},e}(Xn);vr.id="rectangle",vr.defaults={borderSkipped:"start",borderWidth:0},vr.defaultRoutes={backgroundColor:"color",borderColor:"color"};var mr=Object.freeze({__proto__:null,Arc:nr,Line:lr,Point:cr,Rectangle:vr});function br(t,e,n){var i=function(t){var e=t.options,n=e.fill,i=g(n&&n.target,n);return void 0===i&&(i=!!e.backgroundColor),!1!==i&&null!==i&&(!0===i?"origin":i)}(t),r=parseFloat(i);return p(r)&&Math.floor(r)===r?("-"!==i[0]&&"+"!==i[0]||(r=e+r),!(r===e||r<0||r>=n)&&r):["origin","start","end","stack"].indexOf(i)>=0&&i}var xr=function(){function t(t){this.x=t.x,this.y=t.y,this.radius=t.radius}var e=t.prototype;return e.pathSegment=function(t,e,n){var i=this.x,r=this.y,a=this.radius;return e=e||{start:0,end:2*Math.PI},n.reverse?t.arc(i,r,a,e.end,e.start,!0):t.arc(i,r,a,e.start,e.end),!n.bounds},e.interpolate=function(t,e){var n=this.x,i=this.y,r=this.radius,a=t.angle;if("angle"===e)return{x:n+Math.cos(a)*r,y:i+Math.sin(a)*r,angle:a}},t}();function yr(t){return(t.scale||{}).getPointPositionForValue?function(t){var e,n,i=t.scale,r=t.fill,a=i.options,o=i.getLabels().length,s=[],l=a.reverse?i.max:i.min,c=a.reverse?i.min:i.max,u="start"===r?l:"end"===r?c:i.getBaseValue();if(a.gridLines.circular)return n=i.getPointPositionForValue(0,l),new xr({x:n.x,y:n.y,radius:i.getDistanceFromCenterForValue(u)});for(e=0;e=h&&r<=d){s=r===h,l=r===d;break}}return{first:s,last:l,point:i}}function Pr(t,e){var n=[],i=!1;return d(t)?(i=!0,n=t):n=function(t,e){var n=t||{},i=n.x,r=void 0===i?null:i,a=n.y,o=void 0===a?null:a,s=e.points,l=[];return e.segments.forEach((function(t){var e=s[t.start],n=s[t.end];null!==o?(l.push({x:e.x,y:o}),l.push({x:n.x,y:o})):null!==r&&(l.push({x:r,y:e.y}),l.push({x:r,y:n.y}))})),l}(t,e),n.length?new lr({points:n,options:{tension:0},_loop:i,_fullLoop:i}):null}function Sr(t,e,n){var i,r=t[e].fill,a=[e];if(!n)return r;for(;!1!==r&&-1===a.indexOf(r);){if(!p(r))return r;if(!(i=t[r]))return!1;if(i.visible)return r;a.push(r),r=i.fill}return!1}function Dr(t,e,n){t.beginPath(),e.path(t),t.lineTo(e.last().x,n),t.lineTo(e.first().x,n),t.closePath(),t.clip()}function Tr(t,e,n,i){if(!i){var r=e[t],a=n[t];return"angle"===t&&(r=Ln(r),a=Ln(a)),{property:t,start:r,end:a}}}function Or(t,e,n,i){return t&&e?i(t[n],e[n]):t?t[n]:e?e[n]:0}function Ar(t,e,n){var i=e.chart.chartArea,r=i.top,a=i.bottom,o=n||{},s=o.property,l=o.start,c=o.end;"x"===s&&(t.beginPath(),t.rect(l,r,c-l,a-r),t.clip())}function Er(t,e,n,i){var r=e.interpolate(n,i);r&&t.lineTo(r.x,r.y)}function Lr(t,e){var n=e.line,i=e.target,r=e.property,a=e.color,o=e.scale,s=function(t,e,n){for(var i=t.segments,r=t.points,a=e.points,o=[],s=0;s=0;--e)(n=i[e].$filler)&&n.line.updateControlPoints(r)},beforeDatasetDraw:function(t,e){var n=t.chartArea,i=t.ctx,r=e.meta.$filler;if(r&&!1!==r.fill){var a=function(t){var e=t.chart,n=t.fill,i=t.line;if(p(n))return function(t,e){var n=t.getDatasetMeta(e);return n&&t.isDatasetVisible(e)?n.dataset:null}(e,n);if("stack"===n)return _r(t);var r=yr(t);return r instanceof xr?r:Pr(r,i)}(r),o=r.line,s=r.scale,l=o.options,c=l.fill,u=l.backgroundColor,h=c||{},d=h.above,f=void 0===d?u:d,g=h.below,v=void 0===g?u:g;a&&o.points.length&&(N(i,n),function(t,e){var n=e.line,i=e.target,r=e.above,a=e.below,o=e.area,s=e.scale,l=n._loop?"angle":"x";t.save(),"x"===l&&a!==r&&(Dr(t,i,o.top),Lr(t,{line:n,target:i,color:r,scale:s,property:l}),t.restore(),t.save(),Dr(t,i,o.bottom)),Lr(t,{line:n,target:i,color:a,scale:s,property:l}),t.restore()}(i,{line:o,target:a,above:f,below:v,area:n,scale:s}),H(i))}},defaults:{propagate:!0}};function Fr(t,e){var n=t.boxWidth;return t.usePointStyle&&n>e||h(n)?e:n}function Rr(t,e){var n=t.boxHeight;return t.usePointStyle&&n>e||h(n)?e:n}var Ir=function(t){function e(e){var i;return n(r(i=t.call(this)||this),e),i.legendHitBoxes=[],i._hoveredItem=null,i.doughnutMode=!1,i.chart=e.chart,i.options=e.options,i.ctx=e.ctx,i.legendItems=void 0,i.columnWidths=void 0,i.columnHeights=void 0,i.lineWidths=void 0,i._minSize=void 0,i.maxHeight=void 0,i.maxWidth=void 0,i.top=void 0,i.bottom=void 0,i.left=void 0,i.right=void 0,i.height=void 0,i.width=void 0,i._margins=void 0,i.paddingTop=void 0,i.paddingBottom=void 0,i.paddingLeft=void 0,i.paddingRight=void 0,i.position=void 0,i.weight=void 0,i.fullWidth=void 0,i}i(e,t);var a=e.prototype;return a.beforeUpdate=function(){},a.update=function(t,e,n){var i=this;i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i._margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate()},a.afterUpdate=function(){},a.beforeSetDimensions=function(){},a.setDimensions=function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t._minSize={width:0,height:0}},a.afterSetDimensions=function(){},a.beforeBuildLabels=function(){},a.buildLabels=function(){var t=this,e=t.options.labels||{},n=v(e.generateLabels,[t.chart],t)||[];e.filter&&(n=n.filter((function(n){return e.filter(n,t.chart.data)}))),t.options.reverse&&n.reverse(),t.legendItems=n},a.afterBuildLabels=function(){},a.beforeFit=function(){},a.fit=function(){var t=this,e=t.options,n=e.labels,i=e.display,r=t.ctx,a=wt(n.font,t.chart.options.font),o=a.size,s=Fr(n,o),l=Rr(n,o),c=Math.max(l,o),u=t.legendHitBoxes=[],h=t._minSize,d=t.isHorizontal(),f=t._computeTitleHeight();if(d?(h.width=t.maxWidth,h.height=i?10:0):(h.width=i?10:0,h.height=t.maxHeight),i){if(r.font=a.string,d){var p=t.lineWidths=[0],g=f;r.textAlign="left",r.textBaseline="middle",t.legendItems.forEach((function(t,e){var i=s+o/2+r.measureText(t.text).width;(0===e||p[p.length-1]+i+2*n.padding>h.width)&&(g+=c+n.padding,p[p.length-(e>0?0:1)]=0),u[e]={left:0,top:0,width:i,height:c},p[p.length-1]+=i+n.padding})),h.height+=g}else{var v=n.padding,m=t.columnWidths=[],b=t.columnHeights=[],x=n.padding,y=0,_=0,w=h.height-f;t.legendItems.forEach((function(t,e){var i=s+o/2+r.measureText(t.text).width;e>0&&_+o+2*v>w&&(x+=y+n.padding,m.push(y),b.push(_),y=0,_=0),y=Math.max(y,i),_+=o+v,u[e]={left:0,top:0,width:i,height:c}})),x+=y,m.push(y),b.push(_),h.width+=x}t.width=h.width,t.height=h.height}else t.width=h.width=t.height=h.height=0},a.afterFit=function(){},a.isHorizontal=function(){return"top"===this.options.position||"bottom"===this.options.position},a.draw=function(){var t=this,e=t.options,n=e.labels,i=D.color,r=t.height,a=t.columnHeights,o=t.width,s=t.lineWidths;if(e.display){t.drawTitle();var l,c=Pi(e.rtl,t.left,t._minSize.width),u=t.ctx,h=wt(n.font,t.chart.options.font),d=h.color,f=h.size;u.textAlign=c.textAlign("left"),u.textBaseline="middle",u.lineWidth=.5,u.strokeStyle=d,u.fillStyle=d,u.font=h.string;var p=Fr(n,f),v=Rr(n,f),m=Math.max(f,v),b=t.legendHitBoxes,x=function(t,i){switch(e.align){case"start":return n.padding;case"end":return t-i;default:return(t-i+n.padding)/2}},y=t.isHorizontal(),_=this._computeTitleHeight();l=y?{x:t.left+x(o,s[0]),y:t.top+n.padding+_,line:0}:{x:t.left+n.padding,y:t.top+x(r,a[0])+_,line:0},Si(t.ctx,e.textDirection);var w=m+n.padding;t.legendItems.forEach((function(e,h){var d=u.measureText(e.text).width,_=p+f/2+d,M=l.x,k=l.y;c.setWidth(t._minSize.width),y?h>0&&M+_+n.padding>t.left+t._minSize.width&&(k=l.y+=w,l.line++,M=l.x=t.left+x(o,s[l.line])):h>0&&k+w>t.top+t._minSize.height&&(M=l.x=M+t.columnWidths[l.line]+n.padding,l.line++,k=l.y=t.top+x(r,a[l.line]));var P=c.x(M);!function(t,e,r){if(!(isNaN(p)||p<=0||isNaN(v)||v<0)){u.save();var a=g(r.lineWidth,1);if(u.fillStyle=g(r.fillStyle,i),u.lineCap=g(r.lineCap,"butt"),u.lineDashOffset=g(r.lineDashOffset,0),u.lineJoin=g(r.lineJoin,"miter"),u.lineWidth=a,u.strokeStyle=g(r.strokeStyle,i),u.setLineDash&&u.setLineDash(g(r.lineDash,[])),n&&n.usePointStyle){var o={radius:p*Math.SQRT2/2,pointStyle:r.pointStyle,rotation:r.rotation,borderWidth:a},s=c.xPlus(t,p/2);B(u,o,s,e+f/2)}else{var l=e+Math.max((f-v)/2,0);u.fillRect(c.leftForLtr(t,p),l,p,v),0!==a&&u.strokeRect(c.leftForLtr(t,p),l,p,v)}u.restore()}}(P,k,e),b[h].left=c.leftForLtr(P,b[h].width),b[h].top=k,function(t,e,n,i){var r=f/2,a=c.xPlus(t,p+r),o=e+m/2;u.fillText(n.text,a,o),n.hidden&&(u.beginPath(),u.lineWidth=2,u.moveTo(a,o),u.lineTo(c.xPlus(a,i),o),u.stroke())}(P,k,e,d),y?l.x+=_+n.padding:l.y+=w})),Di(t.ctx,e.textDirection)}},a.drawTitle=function(){var t=this,e=t.options,n=e.title,i=wt(n.font,t.chart.options.font),r=_t(n.padding);if(n.display){var a,o,s=Pi(e.rtl,t.left,t._minSize.width),l=t.ctx,c=n.position,u=i.size/2,h=t.top+r.top+u,d=t.left,f=t.width;if(this.isHorizontal())switch(f=Math.max.apply(Math,t.lineWidths),e.align){case"start":break;case"end":d=t.right-f;break;default:d=(t.left+t.right)/2-f/2}else{var p=Math.max.apply(Math,t.columnHeights);switch(e.align){case"start":break;case"end":h+=t.height-p;break;default:h+=(t.height-p)/2}}switch(c){case"start":a=d,o="left";break;case"end":a=d+f,o="right";break;default:a=d+f/2,o="center"}l.textAlign=s.textAlign(o),l.textBaseline="middle",l.strokeStyle=i.color,l.fillStyle=i.color,l.font=i.string,l.fillText(n.text,a,h)}},a._computeTitleHeight=function(){var t=this.options.title,e=wt(t.font,this.chart.options.font),n=_t(t.padding);return t.display?e.lineHeight+n.height:0},a._getLegendItemAt=function(t,e){var n,i,r,a=this;if(t>=a.left&&t<=a.right&&e>=a.top&&e<=a.bottom)for(r=a.legendHitBoxes,n=0;n=(i=r[n]).left&&t<=i.left+i.width&&e>=i.top&&e<=i.top+i.height)return a.legendItems[n];return null},a.handleEvent=function(t){var e=this,n=e.options,i="mouseup"===t.type?"click":t.type;if("mousemove"===i){if(!n.onHover&&!n.onLeave)return}else{if("click"!==i)return;if(!n.onClick)return}var r=e._getLegendItemAt(t.x,t.y);"click"===i?r&&v(n.onClick,[t,r,e],e):(n.onLeave&&r!==e._hoveredItem&&(e._hoveredItem&&v(n.onLeave,[t,e._hoveredItem,e],e),e._hoveredItem=r),r&&v(n.onHover,[t,r,e],e))},e}(Xn);function zr(t){return!1!==t&&_({},[D.plugins.legend,t])}function Vr(t,e){var n=new Ir({ctx:t.ctx,options:e,chart:t});Ct.configure(t,n,e),Ct.addBox(t,n),t.legend=n}var Br={id:"legend",_element:Ir,beforeInit:function(t){var e=zr(t.options.legend);e&&Vr(t,e)},beforeUpdate:function(t){var e=zr(t.options.legend),n=t.legend;e?n?(Ct.configure(t,n,e),n.options=e):Vr(t,e):n&&(Ct.removeBox(t,n),delete t.legend)},afterUpdate:function(t){t.legend&&t.legend.buildLabels()},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)},defaults:{display:!0,position:"top",align:"center",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e,n){var i=e.datasetIndex,r=n.chart;r.isDatasetVisible(i)?(r.hide(i),e.hidden=!0):(r.show(i),e.hidden=!1)},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data.datasets,n=t.options.legend||{},i=n.labels&&n.labels.usePointStyle;return t._getSortedDatasetMetas().map((function(t){var n=t.controller.getStyle(i?0:void 0);return{text:e[t.index].label,fillStyle:n.backgroundColor,hidden:!t.visible,lineCap:n.borderCapStyle,lineDash:n.borderDash,lineDashOffset:n.borderDashOffset,lineJoin:n.borderJoinStyle,lineWidth:n.borderWidth,strokeStyle:n.borderColor,pointStyle:n.pointStyle,rotation:n.rotation,datasetIndex:t.index}}),this)}},title:{display:!1,position:"center",text:""}}},Wr=function(t){function e(e){var i;return n(r(i=t.call(this)||this),e),i.chart=e.chart,i.options=e.options,i.ctx=e.ctx,i._margins=void 0,i._padding=void 0,i.top=void 0,i.bottom=void 0,i.left=void 0,i.right=void 0,i.width=void 0,i.height=void 0,i.maxWidth=void 0,i.maxHeight=void 0,i.position=void 0,i.weight=void 0,i.fullWidth=void 0,i}i(e,t);var a=e.prototype;return a.beforeUpdate=function(){},a.update=function(t,e,n){var i=this;i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i._margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate()},a.afterUpdate=function(){},a.beforeSetDimensions=function(){},a.setDimensions=function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height)},a.afterSetDimensions=function(){},a.beforeBuildLabels=function(){},a.buildLabels=function(){},a.afterBuildLabels=function(){},a.beforeFit=function(){},a.fit=function(){var t=this,e=t.options,n={},i=t.isHorizontal();if(e.display){var r=d(e.text)?e.text.length:1;t._padding=_t(e.padding);var a=r*wt(e.font,t.chart.options.font).lineHeight+t._padding.height;t.width=n.width=i?t.maxWidth:a,t.height=n.height=i?a:t.maxHeight}else t.width=n.width=t.height=n.height=0},a.afterFit=function(){},a.isHorizontal=function(){var t=this.options.position;return"top"===t||"bottom"===t},a.draw=function(){var t=this,e=t.ctx,n=t.options;if(n.display){var i,r,a,o,s=wt(n.font,t.chart.options.font),l=s.lineHeight,c=l/2+t._padding.top,u=0,h=t.top,f=t.left,p=t.bottom,g=t.right;if(t.isHorizontal()){switch(n.align){case"start":r=f,o="left";break;case"end":r=g,o="right";break;default:r=f+(g-f)/2,o="center"}a=h+c,i=g-f}else{switch(r="left"===n.position?f+c:g-c,n.align){case"start":a="left"===n.position?p:h,o="left";break;case"end":a="left"===n.position?h:p,o="right";break;default:a=h+(p-h)/2,o="center"}i=p-h,u=Math.PI*("left"===n.position?-.5:.5)}e.save(),e.fillStyle=s.color,e.font=s.string,e.translate(r,a),e.rotate(u),e.textAlign=o,e.textBaseline="middle";var v=n.text;if(d(v))for(var m=0,b=0;b-1?t.split("\n"):t}function Xr(t,e){var n=e.element,i=e.datasetIndex,r=e.index,a=t.getDatasetMeta(i).controller,o=a.getLabelAndValue(r),s=o.label,l=o.value;return{chart:t,label:s,dataPoint:a.getParsed(r),formattedValue:l,dataset:a.getDataset(),dataIndex:r,datasetIndex:i,element:n}}function Kr(t){var e=t._chart.ctx,n=t.body,i=t.footer,r=t.options,a=t.title,o=r.bodyFont,s=r.footerFont,l=r.titleFont,c=r.boxWidth,u=r.boxHeight,h=a.length,d=i.length,f=n.length,p=2*r.yPadding,g=0,v=n.reduce((function(t,e){return t+e.before.length+e.lines.length+e.after.length}),0);(v+=t.beforeBody.length+t.afterBody.length,h&&(p+=h*l.size+(h-1)*r.titleSpacing+r.titleMarginBottom),v)&&(p+=f*(r.displayColors?Math.max(u,o.size):o.size)+(v-f)*o.size+(v-1)*r.bodySpacing);d&&(p+=r.footerMarginTop+d*s.size+(d-1)*r.footerSpacing);var b=0,x=function(t){g=Math.max(g,e.measureText(t).width+b)};return e.save(),e.font=l.string,m(t.title,x),e.font=o.string,m(t.beforeBody.concat(t.afterBody),x),b=r.displayColors?c+2:0,m(n,(function(t){m(t.before,x),m(t.lines,x),m(t.after,x)})),b=0,e.font=s.string,m(t.footer,x),e.restore(),{width:g+=2*r.xPadding,height:p}}function qr(t,e,n){var i,r,a=n.x,o=n.y,s=n.width,l=n.height,c=t.chartArea,u="center",h="center";ot.height-l&&(h="bottom");var d=(c.left+c.right)/2,f=(c.top+c.bottom)/2;"center"===h?(i=function(t){return t<=d},r=function(t){return t>d}):(i=function(t){return t<=s/2},r=function(e){return e>=t.width-s/2});var p=function(t){return t<=f?"top":"bottom"};return i(a)?(u="left",a+s+e.caretSize+e.caretPadding>t.width&&(u="center",h=p(o))):r(a)&&(u="right",function(t){return t-s-e.caretSize-e.caretPadding<0}(a)&&(u="center",h=p(o))),{xAlign:e.xAlign?e.xAlign:u,yAlign:e.yAlign?e.yAlign:h}}function $r(t,e,n,i){var r=t.caretSize,a=t.caretPadding,o=t.cornerRadius,s=n.xAlign,l=n.yAlign,c=r+a,u=o+a,h=function(t,e,n){var i=t.x,r=t.width;return"right"===e?i-=r:"center"===e&&((i-=r/2)+r>n&&(i=n-r),i<0&&(i=0)),i}(e,s,i.width);return"center"===l?"left"===s?h+=c:"right"===s&&(h-=c):"left"===s?h-=u:"right"===s&&(h+=u),{x:h,y:function(t,e,n){var i=t.y,r=t.height;return"top"===e?i+=n:i-="bottom"===e?r+n:r/2,i}(e,l,c)}}function Gr(t,e){var n=t.options;return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-n.xPadding:t.x+n.xPadding}function Zr(t){return Yr([],Ur(t))}var Qr=function(t){function e(e){var n;return(n=t.call(this)||this).opacity=0,n._active=[],n._chart=e._chart,n._eventPosition=void 0,n._size=void 0,n._cachedAnimations=void 0,n.$animations=void 0,n.options=void 0,n.dataPoints=void 0,n.title=void 0,n.beforeBody=void 0,n.body=void 0,n.afterBody=void 0,n.footer=void 0,n.xAlign=void 0,n.yAlign=void 0,n.x=void 0,n.y=void 0,n.height=void 0,n.width=void 0,n.caretX=void 0,n.caretY=void 0,n.labelColors=void 0,n.labelTextColors=void 0,n.initialize(),n}i(e,t);var r=e.prototype;return r.initialize=function(){var t,e,n=this._chart.options;this.options=(t=n.tooltips,e=n.font,(t=_({},[D.plugins.tooltip,t])).bodyFont=wt(t.bodyFont,e),t.titleFont=wt(t.titleFont,e),t.footerFont=wt(t.footerFont,e),t.boxHeight=g(t.boxHeight,t.bodyFont.size),t.boxWidth=g(t.boxWidth,t.bodyFont.size),t)},r._resolveAnimations=function(){var t=this,e=t._cachedAnimations;if(e)return e;var n=t._chart,i=t.options,r=i.enabled&&n.options.animation&&i.animation,a=new gn(t._chart,r);return t._cachedAnimations=Object.freeze(a),a},r.getTitle=function(t){var e=this,n=e.options.callbacks,i=n.beforeTitle.apply(e,[t]),r=n.title.apply(e,[t]),a=n.afterTitle.apply(e,[t]),o=[];return o=Yr(o,Ur(i)),o=Yr(o,Ur(r)),o=Yr(o,Ur(a))},r.getBeforeBody=function(t){return Zr(this.options.callbacks.beforeBody.apply(this,[t]))},r.getBody=function(t){var e=this,n=e.options.callbacks,i=[];return m(t,(function(t){var r={before:[],lines:[],after:[]};Yr(r.before,Ur(n.beforeLabel.call(e,t))),Yr(r.lines,n.label.call(e,t)),Yr(r.after,Ur(n.afterLabel.call(e,t))),i.push(r)})),i},r.getAfterBody=function(t){return Zr(this.options.callbacks.afterBody.apply(this,[t]))},r.getFooter=function(t){var e=this,n=e.options.callbacks,i=n.beforeFooter.apply(e,[t]),r=n.footer.apply(e,[t]),a=n.afterFooter.apply(e,[t]),o=[];return o=Yr(o,Ur(i)),o=Yr(o,Ur(r)),o=Yr(o,Ur(a))},r._createItems=function(){var t,e,n=this,i=n._active,r=n.options,a=n._chart.data,o=[],s=[],l=[];for(t=0,e=i.length;t0&&e.stroke()},r._updateAnimationTarget=function(){var t=this,e=t._chart,i=t.options,r=t.$animations,a=r&&r.x,o=r&&r.y;if(a||o){var s=jr[i.position].call(t,t._active,t._eventPosition);if(!s)return;var l=t._size=Kr(t),c=n({},s,t._size),u=qr(e,i,c),h=$r(i,c,u,e);a._to===h.x&&o._to===h.y||(t.xAlign=u.xAlign,t.yAlign=u.yAlign,t.width=l.width,t.height=l.height,t.caretX=s.x,t.caretY=s.y,t._resolveAnimations().update(t,h))}},r.draw=function(t){var e=this,n=e.options,i=e.opacity;if(i){e._updateAnimationTarget();var r={width:e.width,height:e.height},a={x:e.x,y:e.y};i=Math.abs(i)<.001?0:i;var o=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;n.enabled&&o&&(t.save(),t.globalAlpha=i,e.drawBackground(a,t,r),Si(t,n.textDirection),a.y+=n.yPadding,e.drawTitle(a,t),e.drawBody(a,t),e.drawFooter(a,t),Di(t,n.textDirection),t.restore())}},r.handleEvent=function(t,e){var n,i=this,r=i.options,a=i._active||[],o=[];"mouseout"!==t.type&&(o=i._chart.getElementsAtEventForMode(t,r.mode,r,e),r.reverse&&o.reverse());var s=jr[r.position].call(i,o,t),l=this.caretX!==s.x||this.caretY!==s.y;return(n=e||!b(o,a)||l)&&(i._active=o,(r.enabled||r.custom)&&(i._eventPosition={x:t.x,y:t.y},i.update(!0))),n},e}(Xn);Qr.positioners=jr;var Jr={id:"tooltip",_element:Qr,positioners:jr,afterInit:function(t){t.options.tooltips&&(t.tooltip=new Qr({_chart:t}))},beforeUpdate:function(t){t.tooltip&&t.tooltip.initialize()},reset:function(t){t.tooltip&&t.tooltip.initialize()},afterDraw:function(t){var e=t.tooltip,n={tooltip:e};!1!==t._plugins.notify(t,"beforeTooltipDraw",[n])&&(e&&e.draw(t.ctx),t._plugins.notify(t,"afterTooltipDraw",[n]))},afterEvent:function(t,e,n){if(t.tooltip){var i=n;t.tooltip.handleEvent(e,i)}},defaults:{enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFont:{style:"bold",color:"#fff"},titleSpacing:2,titleMarginBottom:6,titleAlign:"left",bodySpacing:2,bodyFont:{color:"#fff"},bodyAlign:"left",footerSpacing:2,footerMarginTop:6,footerFont:{color:"#fff",style:"bold"},footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,animation:{duration:400,easing:"easeOutQuart",numbers:{type:"number",properties:["x","y","width","height","caretX","caretY"]},opacity:{easing:"linear",duration:200}},callbacks:{beforeTitle:l,title:function(t){if(t.length>0){var e=t[0],n=e.chart.data.labels,i=n?n.length:0;if(e.label)return e.label;if(i>0&&e.dataIndex=0&&te.length-1?null:this.getPixelForValue(e[t].value)},n.getValueForPixel=function(t){var e=this,n=Math.round(e._startValue+e.getDecimalForPixel(t)*e._valueRange);return Math.min(Math.max(n,0),e.ticks.length-1)},n.getBasePixel=function(){return this.bottom},e}(ei);function na(t){var e=Math.floor(yn(t)),n=t/Math.pow(10,e);return(n<=1?1:n<=2?2:n<=5?5:10)*Math.pow(10,e)}ea.id="category",ea.defaults={ticks:{callback:ea.prototype.getLabelForValue}};var ia=function(t){function e(e){var n;return(n=t.call(this,e)||this).start=void 0,n.end=void 0,n._startValue=void 0,n._endValue=void 0,n._valueRange=0,n}i(e,t);var n=e.prototype;return n.parse=function(t,e){return h(t)||("number"==typeof t||t instanceof Number)&&!isFinite(+t)?NaN:+t},n.handleTickRangeOptions=function(){var t=this,e=t.options;if(e.beginAtZero){var n=Pn(t.min),i=Pn(t.max);n<0&&i<0?t.max=0:n>0&&i>0&&(t.min=0)}var r=void 0!==e.min||void 0!==e.suggestedMin,a=void 0!==e.max||void 0!==e.suggestedMax;void 0!==e.min?t.min=e.min:void 0!==e.suggestedMin&&(null===t.min?t.min=e.suggestedMin:t.min=Math.min(t.min,e.suggestedMin)),void 0!==e.max?t.max=e.max:void 0!==e.suggestedMax&&(null===t.max?t.max=e.suggestedMax:t.max=Math.max(t.max,e.suggestedMax)),r!==a&&t.min>=t.max&&(r?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},n.getTickLimit=function(){var t,e=this,n=e.options.ticks,i=n.maxTicksLimit,r=n.stepSize;return r?t=Math.ceil(e.max/r)-Math.floor(e.min/r)+1:(t=e.computeTickLimit(),i=i||11),i&&(t=Math.min(i,t)),t},n.computeTickLimit=function(){return Number.POSITIVE_INFINITY},n.buildTicks=function(){var t=this,e=t.options,n=e.ticks,i=t.getTickLimit(),r=function(t,e){var n,i,r,a,o=[],s=t.stepSize,l=t.min,c=t.max,u=t.precision,d=s||1,f=t.maxTicks-1,p=e.min,g=e.max,v=na((g-p)/f/d)*d;if(v<1e-14&&h(l)&&h(c))return[{value:p},{value:g}];(a=Math.ceil(g/v)-Math.floor(p/v))>f&&(v=na(a*v/f/d)*d),s||h(u)?n=Math.pow(10,Tn(v)):(n=Math.pow(10,u),v=Math.ceil(v*n)/n),i=Math.floor(p/v)*v,r=Math.ceil(g/v)*v,!s||h(l)||h(c)||Mn((c-l)/s,v/1e3)&&(i=l,r=c),a=wn(a=(r-i)/v,Math.round(a),v/1e3)?Math.round(a):Math.ceil(a),i=Math.round(i*n)/n,r=Math.round(r*n)/n,o.push({value:h(l)?i:l});for(var m=1;m0&&(t.min=0),t.handleTickRangeOptions()},n.computeTickLimit=function(){var t=this;if(t.isHorizontal())return Math.ceil(t.width/40);var e=t._resolveTickFontOptions(0);return Math.ceil(t.height/e.lineHeight)},n.getPixelForValue=function(t){var e=this;return e.getPixelForDecimal((t-e._startValue)/e._valueRange)},n.getValueForPixel=function(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange},e}(ia);function aa(t){return 1===t/Math.pow(10,Math.floor(yn(t)))}function oa(t,e){return p(t)?t:e}ra.id="linear",ra.defaults={ticks:{callback:$n.formatters.numeric}};var sa=function(t){function e(e){var n;return(n=t.call(this,e)||this).start=void 0,n.end=void 0,n._startValue=void 0,n._valueRange=0,n}i(e,t);var n=e.prototype;return n.parse=function(t,e){var n=ia.prototype.parse.apply(this,[t,e]);if(0!==n)return p(n)&&n>0?n:NaN},n.determineDataLimits=function(){var t=this,e=t.getMinMax(!0),n=e.min,i=e.max;t.min=p(n)?Math.max(0,n):null,t.max=p(i)?Math.max(0,i):null,t.handleTickRangeOptions()},n.handleTickRangeOptions=function(){var t=this,e=t.min,n=t.max;e===n&&(e<=0?(e=1,n=10):(e=Math.pow(10,Math.floor(yn(e))-1),n=Math.pow(10,Math.floor(yn(n))+1))),e<=0&&(e=Math.pow(10,Math.floor(yn(n))-1)),n<=0&&(n=Math.pow(10,Math.floor(yn(e))+1)),t.min=e,t.max=n},n.buildTicks=function(){var t=this,e=t.options,n=function(t,e){var n=Math.floor(yn(e.max)),i=Math.ceil(e.max/Math.pow(10,n)),r=[],a=oa(t.min,Math.pow(10,Math.floor(yn(e.min)))),o=Math.floor(yn(a)),s=Math.floor(a/Math.pow(10,o)),l=o<0?Math.pow(10,Math.abs(o)):1;do{r.push({value:a,major:aa(a)}),10==++s&&(s=1,l=++o>=0?1:l),a=Math.round(s*Math.pow(10,o)*l)/l}while(or?{start:e-n,end:e}:{start:e,end:e+n}}function ua(t){return 0===t||180===t?"center":t<180?"left":"right"}function ha(t,e,n,i){var r,a,o=n.y+i/2;if(d(e))for(r=0,a=e.length;r270||t<90)&&(n.y-=e.h)}function fa(t){return _n(t)?t:0}sa.id="logarithmic",sa.defaults={ticks:{callback:$n.formatters.logarithmic,major:{enabled:!0}}};var pa=function(t){function e(e){var n;return(n=t.call(this,e)||this).xCenter=void 0,n.yCenter=void 0,n.drawingArea=void 0,n.pointLabels=[],n}i(e,t);var n=e.prototype;return n.init=function(e){t.prototype.init.call(this,e),this.axis="r"},n.setDimensions=function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=la(t.options)/2,t.xCenter=Math.floor(t.width/2),t.yCenter=Math.floor((t.height-t.paddingTop)/2),t.drawingArea=Math.min(t.height-t.paddingTop,t.width)/2},n.determineDataLimits=function(){var t=this,e=t.getMinMax(!1),n=e.min,i=e.max;t.min=p(n)&&!isNaN(n)?n:0,t.max=p(i)&&!isNaN(i)?i:0,t.handleTickRangeOptions()},n.computeTickLimit=function(){return Math.ceil(this.drawingArea/la(this.options))},n.generateTickLabels=function(t){var e=this;ia.prototype.generateTickLabels.call(e,t),e.pointLabels=e.chart.data.labels.map((function(t,n){var i=v(e.options.pointLabels.callback,[t,n],e);return i||0===i?i:""}))},n.fit=function(){var t=this,e=t.options;e.display&&e.pointLabels.display?function(t){var e,n,i,r={l:0,r:t.width,t:0,b:t.height-t.paddingTop},a={};t._pointLabelSizes=[];var o,s,l,c=t.chart.data.labels.length;for(e=0;er.r&&(r.r=g.end,a.r=f),v.startr.b&&(r.b=v.end,a.b=f)}t._setReductions(t.drawingArea,r,a)}(t):t.setCenterPoint(0,0,0,0)},n._setReductions=function(t,e,n){var i=this,r=e.l/Math.sin(n.l),a=Math.max(e.r-i.width,0)/Math.sin(n.r),o=-e.t/Math.cos(n.t),s=-Math.max(e.b-(i.height-i.paddingTop),0)/Math.cos(n.b);r=fa(r),a=fa(a),o=fa(o),s=fa(s),i.drawingArea=Math.min(Math.floor(t-(r+a)/2),Math.floor(t-(o+s)/2)),i.setCenterPoint(r,a,o,s)},n.setCenterPoint=function(t,e,n,i){var r=this,a=r.width-e-r.drawingArea,o=t+r.drawingArea,s=n+r.drawingArea,l=r.height-r.paddingTop-i-r.drawingArea;r.xCenter=Math.floor((o+a)/2+r.left),r.yCenter=Math.floor((s+l)/2+r.top+r.paddingTop)},n.getIndexAngle=function(t){var e=this.chart;return Ln(t*(2*Math.PI/e.data.labels.length)+Sn((e.options||{}).startAngle||0))},n.getDistanceFromCenterForValue=function(t){var e=this;if(h(t))return NaN;var n=e.drawingArea/(e.max-e.min);return e.options.reverse?(e.max-t)*n:(t-e.min)*n},n.getValueForDistanceFromCenter=function(t){if(h(t))return NaN;var e=this,n=t/(e.drawingArea/(e.max-e.min));return e.options.reverse?e.max-n:e.min+n},n.getPointPosition=function(t,e){var n=this,i=n.getIndexAngle(t)-Math.PI/2;return{x:Math.cos(i)*e+n.xCenter,y:Math.sin(i)*e+n.yCenter,angle:i}},n.getPointPositionForValue=function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},n.getBasePosition=function(t){return this.getPointPositionForValue(t||0,this.getBaseValue())},n.drawGrid=function(){var t,e,n,i=this,r=i.ctx,a=i.options,o=a.gridLines,s=a.angleLines;if(a.pointLabels.display&&function(t){var e=t.ctx,n=t.options,i=n.pointLabels,r=la(n),a=t.getDistanceFromCenterForValue(n.ticks.reverse?t.min:t.max);e.save(),e.textBaseline="middle";for(var o=t.chart.data.labels.length-1;o>=0;o--){var s=0===o?r/2:0,l=t.getPointPosition(o,a+s+5),c={chart:t.chart,scale:t,index:o,label:t.pointLabels[o]},u=wt(Mt([i.font],c,o),t.chart.options.font);e.font=u.string,e.fillStyle=u.color;var h=Dn(t.getIndexAngle(o));e.textAlign=ua(h),da(h,t._pointLabelSizes[o],l),ha(e,t.pointLabels[o],l,u.lineHeight)}e.restore()}(i),o.display&&i.ticks.forEach((function(t,n){0!==n&&(e=i.getDistanceFromCenterForValue(i.ticks[n].value),function(t,e,n,i){var r,a=t.ctx,o=e.circular,s=t.chart.data.labels.length,l={chart:t.chart,scale:t,index:i,tick:t.ticks[i]},c=Mt([e.color],l,i-1),u=Mt([e.lineWidth],l,i-1);if((o||s)&&c&&u){if(a.save(),a.strokeStyle=c,a.lineWidth=u,a.setLineDash&&(a.setLineDash(Mt([e.borderDash,[]],l)),a.lineDashOffset=Mt([e.borderDashOffset],l,i-1)),a.beginPath(),o)a.arc(t.xCenter,t.yCenter,n,0,2*Math.PI);else{r=t.getPointPosition(0,n),a.moveTo(r.x,r.y);for(var h=1;h=0;t--){var l={chart:i.chart,scale:i,index:t,label:i.pointLabels[t]},c=Mt([s.lineWidth,o.lineWidth],l,t),u=Mt([s.color,o.color],l,t);c&&u&&(r.lineWidth=c,r.strokeStyle=u,r.setLineDash&&(r.setLineDash(Mt([s.borderDash,o.borderDash,[]],l)),r.lineDashOffset=Mt([s.borderDashOffset,o.borderDashOffset,0],l,t)),e=i.getDistanceFromCenterForValue(a.ticks.reverse?i.min:i.max),n=i.getPointPosition(t,e),r.beginPath(),r.moveTo(i.xCenter,i.yCenter),r.lineTo(n.x,n.y),r.stroke())}r.restore()}},n.drawLabels=function(){var t=this,e=t.ctx,n=t.options,i=n.ticks;if(i.display){var r,a,o=t.getIndexAngle(0);e.save(),e.translate(t.xCenter,t.yCenter),e.rotate(o),e.textAlign="center",e.textBaseline="middle",t.ticks.forEach((function(o,s){var l={chart:t.chart,scale:t,index:s,tick:o};if(0!==s||n.reverse){var c=t._resolveTickFontOptions(s);e.font=c.string,r=t.getDistanceFromCenterForValue(t.ticks[s].value),Mt([i.showLabelBackdrop],l,s)&&(a=e.measureText(o.label).width,e.fillStyle=Mt([i.backdropColor],l,s),e.fillRect(-a/2-i.backdropPaddingX,-r-c.size/2-i.backdropPaddingY,a+2*i.backdropPaddingX,c.size+2*i.backdropPaddingY)),e.fillStyle=c.color,e.fillText(o.label,0,-r)}})),e.restore()}},n.drawTitle=function(){},e}(ia);pa.id="radialLinear",pa.defaults={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0,0,0,0.1)",lineWidth:1,borderDash:[],borderDashOffset:0},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:$n.formatters.numeric},pointLabels:{display:!0,font:{size:10},callback:function(t){return t}}};var ga=Number.MAX_SAFE_INTEGER||9007199254740991,va={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ma=Object.keys(va);function ba(t,e){return t-e}function xa(t,e){if(h(e))return null;var n=t._adapter,i=t.options.time,r=i.parser,a=i.round,o=i.isoWeekday,s=e;return"function"==typeof r&&(s=r(s)),p(s)||(s="string"==typeof r?n.parse(s,r):n.parse(s)),null===s?s:(a&&(s="week"!==a||!_n(o)&&!0!==o?t._adapter.startOf(s,a):t._adapter.startOf(s,"isoWeek",o)),+s)}function ya(t,e,n,i){for(var r=ma.length,a=ma.indexOf(t);a=e?n[r]:n[a]]=!0}}else t[e]=!0}function wa(t,e,n){var i,r,a=[],o={},s=e.length;for(i=0;i=0&&(e[a].major=!0);return e}(t,a,o,n):a}var Ma=function(t){function e(e){var n;return(n=t.call(this,e)||this)._cache={data:[],labels:[],all:[]},n._unit="day",n._majorUnit=void 0,n._offsets={},n._normalized=!1,n}i(e,t);var n=e.prototype;return n.init=function(e,n){var i=e.time||(e.time={}),r=this._adapter=new Ii._date(e.adapters.date);w(i.displayFormats,r.formats()),t.prototype.init.call(this,e),this._normalized=n.normalized},n.parse=function(t,e){return void 0===t?NaN:xa(this,t)},n.invalidateCaches=function(){this._cache={data:[],labels:[],all:[]}},n.determineDataLimits=function(){var t=this,e=t.options,n=t._adapter,i=e.time.unit||"day",r=t.getUserBounds(),a=r.min,o=r.max,s=r.minDefined,l=r.maxDefined;function c(t){s||isNaN(t.min)||(a=Math.min(a,t.min)),l||isNaN(t.max)||(o=Math.max(o,t.max))}s&&l||(c(t._getLabelBounds()),"ticks"===e.bounds&&"labels"===e.ticks.source||c(t.getMinMax(!1))),a=p(a)&&!isNaN(a)?a:+n.startOf(Date.now(),i),o=p(o)&&!isNaN(o)?o:+n.endOf(Date.now(),i)+1,t.min=Math.min(a,o),t.max=Math.max(a+1,o)},n._getLabelBounds=function(){var t=this.getLabelTimestamps(),e=Number.POSITIVE_INFINITY,n=Number.NEGATIVE_INFINITY;return t.length&&(e=t[0],n=t[t.length-1]),{min:e,max:n}},n.buildTicks=function(){var t=this,e=t.options,n=e.time,i=e.ticks,r="labels"===i.source?t.getLabelTimestamps():t._generate();"ticks"===e.bounds&&r.length&&(t.min=t._userMin||r[0],t.max=t._userMax||r[r.length-1]);var a=t.min,o=q(r,a,t.max);return t._unit=n.unit||(i.autoSkip?ya(n.minUnit,t.min,t.max,t._getLabelCapacity(a)):function(t,e,n,i,r){for(var a=ma.length-1;a>=ma.indexOf(n);a--){var o=ma[a];if(va[o].common&&t._adapter.diff(r,i,o)>=e-1)return o}return ma[n?ma.indexOf(n):0]}(t,o.length,n.minUnit,t.min,t.max)),t._majorUnit=i.major.enabled&&"year"!==t._unit?function(t){for(var e=ma.indexOf(t)+1,n=ma.length;e1e5*l)throw new Error(i+" and "+r+" are too far apart with stepSize of "+l+" "+s);var f="data"===a.ticks.source&&e.getDataTimestamps();for(t=d;t0?s:1},n.getDataTimestamps=function(){var t,e,n=this,i=n._cache.data||[];if(i.length)return i;var r=n.getMatchingVisibleMetas();if(n._normalized&&r.length)return n._cache.data=r[0].controller.getAllParsedValues(n);for(t=0,e=r.length;te&&a0&&!h(e)?e/n._maxIndex:n.getDecimalForValue(t);return n.getPixelForDecimal((i.start+r)*i.factor)},n.getDecimalForValue=function(t){return ka(this._table,t)/this._maxIndex},n.getValueForPixel=function(t){var e=this,n=e._offsets,i=e.getDecimalForPixel(t)/n.factor-n.end;return ka(e._table,i*this._maxIndex,!0)},e}(Ma);Pa.id="timeseries",Pa.defaults=Ma.defaults;var Sa=Object.freeze({__proto__:null,CategoryScale:ea,LinearScale:ra,LogarithmicScale:sa,RadialLinearScale:pa,TimeScale:Ma,TimeSeriesScale:Pa});return gi.register(Zi,Sa,mr,ta),gi.helpers=n({},Ci),gi._adapters=Ii,gi.Animation=fn,gi.Animations=gn,gi.animator=s,gi.controllers=ii.controllers.items,gi.DatasetController=Un,gi.Element=Xn,gi.elements=mr,gi.Interaction=mt,gi.layouts=Ct,gi.platforms=me,gi.Scale=ei,gi.Ticks=$n,n(gi,Zi,Sa,mr,ta,me),gi.Chart=gi,"undefined"!=typeof window&&(window.Chart=gi),gi})); diff --git a/dist/helpers.esm.js b/dist/helpers.esm.js new file mode 100644 index 00000000000..0e2eaef593d --- /dev/null +++ b/dist/helpers.esm.js @@ -0,0 +1,7 @@ +/*! + * Chart.js v3.0.0-beta.2 + * https://www.chartjs.org + * (c) 2020 Chart.js Contributors + * Released under the MIT License + */ +export { O as _alignPixel, W as _angleBetween, at as _angleDiff, ai as _arrayUnique, a3 as _bezierCurveTo, a0 as _bezierInterpolation, a7 as _boundSegment, Z as _boundSegments, _ as _capitalize, Y as _computeSegments, ad as _decimalPlaces, an as _deprecated, U as _elementsEqual, Q as _factorize, ah as _filterBetween, E as _getParentNode, N as _int32Range, z as _isPointInArea, k as _limitValue, ag as _longestText, aj as _lookup, w as _lookupByKey, M as _measureText, j as _merger, am as _mergerIf, a6 as _normalizeAngle, a1 as _pointInLine, A as _rlookupByKey, ac as _setMinAndMaxByKey, $ as _steppedInterpolation, a2 as _steppedLineTo, X as _updateBezierControlPoints, ae as almostEquals, af as almostWhole, K as callback, T as clear, o as clipArea, al as clone, c as color, ab as distanceBetweenPoints, a4 as drawPoint, C as each, e as easingEffects, ak as fontString, V as getAngleFromPoint, g as getHoverColor, D as getMaximumSize, y as getRelativePosition, a8 as getRtlAdapter, ar as getStyle, b as isArray, J as isFinite, q as isNullOrUndef, t as isNumber, i as isObject, l as listenArrayEvents, I as log10, m as merge, h as mergeIf, n as noop, a9 as overrideTextDirection, F as readUsedSize, r as requestAnimFrame, a as resolve, f as resolveObjectKey, aa as restoreTextDirection, S as retinaScale, s as sign, ap as splineCurve, aq as splineCurveMonotone, H as supportsEventListenerOptions, L as toDegrees, P as toFont, ao as toFontString, as as toLineHeight, B as toPadding, x as toRadians, a5 as toTRBL, R as uid, p as unclipArea, u as unlistenArrayEvents, v as valueOrDefault } from './chunks/helpers.rtl.js';