diff --git a/release/3.10.1/dist-esm/billboard.js b/release/3.10.1/dist-esm/billboard.js new file mode 100644 index 000000000..69541a576 --- /dev/null +++ b/release/3.10.1/dist-esm/billboard.js @@ -0,0 +1,23163 @@ +/*! +* Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + * + * billboard.js, JavaScript chart library + * https://naver.github.io/billboard.js/ + * + * @version 3.10.1 +*/ +import { timeParse, utcParse, timeFormat, utcFormat } from 'd3-time-format'; +import { pointer, select, namespaces, selectAll } from 'd3-selection'; +import { brushSelection, brushY, brushX } from 'd3-brush'; +import { csvParseRows, csvParse, tsvParseRows, tsvParse } from 'd3-dsv'; +import { drag as drag$1 } from 'd3-drag'; +import { scaleOrdinal, scaleLinear, scaleSymlog, scaleLog, scaleTime, scaleUtc } from 'd3-scale'; +import { transition } from 'd3-transition'; +import { curveBasis, curveBasisClosed, curveBasisOpen, curveBundle, curveCardinal, curveCardinalClosed, curveCardinalOpen, curveCatmullRom, curveCatmullRomClosed, curveCatmullRomOpen, curveMonotoneX, curveMonotoneY, curveNatural, curveLinearClosed, curveLinear, curveStep, curveStepAfter, curveStepBefore, pie as pie$1, arc, area as area$1, line as line$1 } from 'd3-shape'; +import { axisLeft, axisBottom, axisTop, axisRight } from 'd3-axis'; +import { easeLinear } from 'd3-ease'; +import { interpolate } from 'd3-interpolate'; +import { treemap as treemap$1, hierarchy, treemapBinary, treemapDice, treemapSlice, treemapSliceDice, treemapSquarify, treemapResquarify } from 'd3-hierarchy'; +import { zoomIdentity, zoomTransform, zoom as zoom$2 } from 'd3-zoom'; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Window object + * @private + */ +/* eslint-disable no-new-func, no-undef */ +/** + * Get global object + * @returns {object} window object + * @private + */ +function getGlobal() { + return (typeof globalThis === "object" && globalThis !== null && globalThis.Object === Object && globalThis) || + (typeof global === "object" && global !== null && global.Object === Object && global) || + (typeof self === "object" && self !== null && self.Object === Object && self) || + Function("return this")(); +} +/** + * Get fallback object + * @param {object} w global object + * @returns {Array} fallback object array + * @private + */ +function getFallback(w) { + var hasRAF = typeof (w === null || w === void 0 ? void 0 : w.requestAnimationFrame) === "function"; + var hasRIC = typeof (w === null || w === void 0 ? void 0 : w.requestIdleCallback) === "function"; + return [ + hasRAF ? w.requestAnimationFrame : (function (cb) { return setTimeout(cb, 1); }), + hasRAF ? w.cancelAnimationFrame : (function (id) { return clearTimeout(id); }), + hasRIC ? w.requestIdleCallback : requestAnimationFrame, + hasRIC ? w.cancelIdleCallback : cancelAnimationFrame + ]; +} +var win = getGlobal(); +var doc = win === null || win === void 0 ? void 0 : win.document; +var _a = getFallback(win), requestAnimationFrame = _a[0], cancelAnimationFrame = _a[1], requestIdleCallback = _a[2]; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Chart type constant + * @private + */ +var TYPE = { + AREA: "area", + AREA_LINE_RANGE: "area-line-range", + AREA_SPLINE: "area-spline", + AREA_SPLINE_RANGE: "area-spline-range", + AREA_STEP: "area-step", + BAR: "bar", + BUBBLE: "bubble", + CANDLESTICK: "candlestick", + DONUT: "donut", + GAUGE: "gauge", + LINE: "line", + PIE: "pie", + POLAR: "polar", + RADAR: "radar", + SCATTER: "scatter", + SPLINE: "spline", + STEP: "step", + TREEMAP: "treemap" +}; +/** + * Chart type module and its method from ChartInternal class, needed to be initialized. + * @private + */ +var TYPE_METHOD_NEEDED = { + AREA: "initArea", + AREA_LINE_RANGE: "initArea", + AREA_SPLINE: "initArea", + AREA_SPLINE_RANGE: "initArea", + AREA_STEP: "initArea", + BAR: "initBar", + BUBBLE: "initCircle", + CANDLESTICK: "initCandlestick", + DONUT: "initArc", + GAUGE: "initArc", + LINE: "initLine", + PIE: "initArc", + POLAR: "initPolar", + RADAR: "initCircle", + SCATTER: "initCircle", + SPLINE: "initLine", + STEP: "initLine", + TREEMAP: "initTreemap" +}; +/** + * chart types by category + * @private + */ +var TYPE_BY_CATEGORY = { + Area: [ + TYPE.AREA, + TYPE.AREA_SPLINE, + TYPE.AREA_SPLINE_RANGE, + TYPE.AREA_LINE_RANGE, + TYPE.AREA_STEP + ], + AreaRange: [ + TYPE.AREA_SPLINE_RANGE, + TYPE.AREA_LINE_RANGE + ], + Arc: [ + TYPE.PIE, + TYPE.DONUT, + TYPE.GAUGE, + TYPE.POLAR, + TYPE.RADAR + ], + Line: [ + TYPE.LINE, + TYPE.SPLINE, + TYPE.AREA, + TYPE.AREA_SPLINE, + TYPE.AREA_SPLINE_RANGE, + TYPE.AREA_LINE_RANGE, + TYPE.STEP, + TYPE.AREA_STEP + ], + Step: [ + TYPE.STEP, + TYPE.AREA_STEP + ], + Spline: [ + TYPE.SPLINE, + TYPE.AREA_SPLINE, + TYPE.AREA_SPLINE_RANGE + ] +}; + +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ +/* global Reflect, Promise, SuppressedError, Symbol */ + +var _assign = function __assign() { + _assign = Object.assign || function (t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; + } + return t; + }; + return _assign.apply(this, arguments); +}; +function __spreadArray(to, from, pack) { + if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { + if (ar || !(i in from)) { + if (!ar) ar = Array.prototype.slice.call(from, 0, i); + ar[i] = from[i]; + } + } + return to.concat(ar || Array.prototype.slice.call(from)); +} +typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) { + var e = new Error(message); + return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e; +}; + +var isValue = function (v) { return v || v === 0; }; +var isFunction = function (v) { return typeof v === "function"; }; +var isString = function (v) { return typeof v === "string"; }; +var isNumber = function (v) { return typeof v === "number"; }; +var isUndefined = function (v) { return typeof v === "undefined"; }; +var isDefined = function (v) { return typeof v !== "undefined"; }; +var isboolean = function (v) { return typeof v === "boolean"; }; +var ceil10 = function (v) { return Math.ceil(v / 10) * 10; }; +var asHalfPixel = function (n) { return Math.ceil(n) + 0.5; }; +var diffDomain = function (d) { return d[1] - d[0]; }; +var isObjectType = function (v) { return typeof v === "object"; }; +var isEmpty = function (o) { return (isUndefined(o) || o === null || + (isString(o) && o.length === 0) || + (isObjectType(o) && !(o instanceof Date) && Object.keys(o).length === 0) || + (isNumber(o) && isNaN(o))); }; +var notEmpty = function (o) { return !isEmpty(o); }; +/** + * Check if is array + * @param {Array} arr Data to be checked + * @returns {boolean} + * @private + */ +var isArray = function (arr) { return Array.isArray(arr); }; +/** + * Check if is object + * @param {object} obj Data to be checked + * @returns {boolean} + * @private + */ +var isObject = function (obj) { return obj && !(obj === null || obj === void 0 ? void 0 : obj.nodeType) && isObjectType(obj) && !isArray(obj); }; +/** + * Get specified key value from object + * If default value is given, will return if given key value not found + * @param {object} options Source object + * @param {string} key Key value + * @param {*} defaultValue Default value + * @returns {*} + * @private + */ +function getOption(options, key, defaultValue) { + return isDefined(options[key]) ? options[key] : defaultValue; +} +/** + * Check if value exist in the given object + * @param {object} dict Target object to be checked + * @param {*} value Value to be checked + * @returns {boolean} + * @private + */ +function hasValue(dict, value) { + var found = false; + Object.keys(dict).forEach(function (key) { return (dict[key] === value) && (found = true); }); + return found; +} +/** + * Call function with arguments + * @param {Function} fn Function to be called + * @param {*} thisArg "this" value for fn + * @param {*} args Arguments for fn + * @returns {boolean} true: fn is function, false: fn is not function + * @private + */ +function callFn(fn, thisArg) { + var args = []; + for (var _i = 2; _i < arguments.length; _i++) { + args[_i - 2] = arguments[_i]; + } + var isFn = isFunction(fn); + isFn && fn.call.apply(fn, __spreadArray([thisArg], args, false)); + return isFn; +} +/** + * Call function after all transitions ends + * @param {d3.transition} transition Transition + * @param {Fucntion} cb Callback function + * @private + */ +function endall(transition, cb) { + var n = 0; + var end = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + !--n && cb.apply.apply(cb, __spreadArray([this], args, false)); + }; + // if is transition selection + if ("duration" in transition) { + transition + .each(function () { return ++n; }) + .on("end", end); + } + else { + ++n; + transition.call(end); + } +} +/** + * Replace tag sign to html entity + * @param {string} str Target string value + * @returns {string} + * @private + */ +function sanitize(str) { + return isString(str) ? + str.replace(/<(script|img)?/ig, "<").replace(/(script)?>/ig, ">") : str; +} +/** + * Set text value. If there's multiline add nodes. + * @param {d3Selection} node Text node + * @param {string} text Text value string + * @param {Array} dy dy value for multilined text + * @param {boolean} toMiddle To be alingned vertically middle + * @private + */ +function setTextValue(node, text, dy, toMiddle) { + if (dy === void 0) { dy = [-1, 1]; } + if (toMiddle === void 0) { toMiddle = false; } + if (!node || !isString(text)) { + return; + } + if (text.indexOf("\n") === -1) { + node.text(text); + } + else { + var diff = [node.text(), text].map(function (v) { return v.replace(/[\s\n]/g, ""); }); + if (diff[0] !== diff[1]) { + var multiline = text.split("\n"); + var len_1 = toMiddle ? multiline.length - 1 : 1; + // reset possible text + node.html(""); + multiline.forEach(function (v, i) { + node.append("tspan") + .attr("x", 0) + .attr("dy", "".concat(i === 0 ? dy[0] * len_1 : dy[1], "em")) + .text(v); + }); + } + } +} +/** + * Substitution of SVGPathSeg API polyfill + * @param {SVGGraphicsElement} path Target svg element + * @returns {Array} + * @private + */ +function getRectSegList(path) { + /* + * seg1 ---------- seg2 + * | | + * | | + * | | + * seg0 ---------- seg3 + * */ + var _a = path.getBBox(), x = _a.x, y = _a.y, width = _a.width, height = _a.height; + return [ + { x: x, y: y + height }, + { x: x, y: y }, + { x: x + width, y: y }, + { x: x + width, y: y + height } // seg3 + ]; +} +/** + * Get svg bounding path box dimension + * @param {SVGGraphicsElement} path Target svg element + * @returns {object} + * @private + */ +function getPathBox(path) { + var _a = path.getBoundingClientRect(), width = _a.width, height = _a.height; + var items = getRectSegList(path); + var x = items[0].x; + var y = Math.min(items[0].y, items[1].y); + return { + x: x, + y: y, + width: width, + height: height + }; +} +/** + * Get event's current position coordinates + * @param {object} event Event object + * @param {SVGElement|HTMLElement} element Target element + * @returns {Array} [x, y] Coordinates x, y array + * @private + */ +function getPointer(event, element) { + var _a; + var touches = event && ((_a = (event.touches || (event.sourceEvent && event.sourceEvent.touches))) === null || _a === void 0 ? void 0 : _a[0]); + var pointer$1 = [0, 0]; + try { + pointer$1 = pointer(touches || event, element); + } + catch (e) { } + return pointer$1.map(function (v) { return (isNaN(v) ? 0 : v); }); +} +/** + * Return brush selection array + * @param {object} ctx Current instance + * @returns {d3.brushSelection} + * @private + */ +function getBrushSelection(ctx) { + var event = ctx.event, $el = ctx.$el; + var main = $el.subchart.main || $el.main; + var selection; + // check from event + if (event && event.type === "brush") { + selection = event.selection; + // check from brush area selection + } + else if (main && (selection = main.select(".bb-brush").node())) { + selection = brushSelection(selection); + } + return selection; +} +/** + * Get boundingClientRect. + * Cache the evaluated value once it was called. + * @param {HTMLElement} node Target element + * @returns {object} + * @private + */ +function getBoundingRect(node) { + var needEvaluate = !("rect" in node) || ("rect" in node && node.hasAttribute("width") && node.rect.width !== +node.getAttribute("width")); + return needEvaluate ? + (node.rect = node.getBoundingClientRect()) : node.rect; +} +/** + * Retrun random number + * @param {boolean} asStr Convert returned value as string + * @param {number} min Minimum value + * @param {number} max Maximum value + * @returns {number|string} + * @private + */ +function getRandom(asStr, min, max) { + if (asStr === void 0) { asStr = true; } + if (min === void 0) { min = 0; } + if (max === void 0) { max = 10000; } + var crpt = win.crypto || win.msCrypto; + var rand = crpt ? + min + crpt.getRandomValues(new Uint32Array(1))[0] % (max - min + 1) : + Math.floor(Math.random() * (max - min) + min); + return asStr ? String(rand) : rand; +} +/** + * Find index based on binary search + * @param {Array} arr Data array + * @param {number} v Target number to find + * @param {number} start Start index of data array + * @param {number} end End index of data arr + * @param {boolean} isRotated Weather is roted axis + * @returns {number} Index number + * @private + */ +function findIndex(arr, v, start, end, isRotated) { + if (start > end) { + return -1; + } + var mid = Math.floor((start + end) / 2); + var _a = arr[mid], x = _a.x, _b = _a.w, w = _b === void 0 ? 0 : _b; + if (isRotated) { + x = arr[mid].y; + w = arr[mid].h; + } + if (v >= x && v <= x + w) { + return mid; + } + return v < x ? + findIndex(arr, v, start, mid - 1, isRotated) : + findIndex(arr, v, mid + 1, end, isRotated); +} +/** + * Check if brush is empty + * @param {object} ctx Bursh context + * @returns {boolean} + * @private + */ +function brushEmpty(ctx) { + var selection = getBrushSelection(ctx); + if (selection) { + // brush selected area + // two-dimensional: [[x0, y0], [x1, y1]] + // one-dimensional: [x0, x1] or [y0, y1] + return selection[0] === selection[1]; + } + return true; +} +/** + * Deep copy object + * @param {object} objectN Source object + * @returns {object} Cloned object + * @private + */ +function deepClone() { + var objectN = []; + for (var _i = 0; _i < arguments.length; _i++) { + objectN[_i] = arguments[_i]; + } + var clone = function (v) { + if (isObject(v) && v.constructor) { + var r = new v.constructor(); + for (var k in v) { + r[k] = clone(v[k]); + } + return r; + } + return v; + }; + return objectN.map(function (v) { return clone(v); }) + .reduce(function (a, c) { return (_assign(_assign({}, a), c)); }); +} +/** + * Extend target from source object + * @param {object} target Target object + * @param {object|Array} source Source object + * @returns {object} + * @private + */ +function extend(target, source) { + if (target === void 0) { target = {}; } + if (isArray(source)) { + source.forEach(function (v) { return extend(target, v); }); + } + // exclude name with only numbers + for (var p in source) { + if (/^\d+$/.test(p) || p in target) { + continue; + } + target[p] = source[p]; + } + return target; +} +/** + * Return first letter capitalized + * @param {string} str Target string + * @returns {string} capitalized string + * @private + */ +var capitalize = function (str) { return str.charAt(0).toUpperCase() + str.slice(1); }; +/** + * Camelize from kebob style string + * @param {string} str Target string + * @param {string} separator Separator string + * @returns {string} camelized string + * @private + */ +function camelize(str, separator) { + if (separator === void 0) { separator = "-"; } + return str.split(separator) + .map(function (v, i) { return (i ? v.charAt(0).toUpperCase() + v.slice(1).toLowerCase() : v.toLowerCase()); }) + .join(""); +} +/** + * Convert to array + * @param {object} v Target to be converted + * @returns {Array} + * @private + */ +var toArray = function (v) { return [].slice.call(v); }; +/** + * Add CSS rules + * @param {object} style Style object + * @param {string} selector Selector string + * @param {Array} prop Prps arrary + * @returns {number} Newely added rule index + * @private + */ +function addCssRules(style, selector, prop) { + var rootSelctor = style.rootSelctor, sheet = style.sheet; + var getSelector = function (s) { return s + .replace(/\s?(bb-)/g, ".$1") + .replace(/\.+/g, "."); }; + var rule = "".concat(rootSelctor, " ").concat(getSelector(selector), " {").concat(prop.join(";"), "}"); + return sheet[sheet.insertRule ? "insertRule" : "addRule"](rule, sheet.cssRules.length); +} +/** + * Get css rules for specified stylesheets + * @param {Array} styleSheets The stylesheets to get the rules from + * @returns {Array} + * @private + */ +function getCssRules(styleSheets) { + var rules = []; + styleSheets.forEach(function (sheet) { + var _a; + try { + if (sheet.cssRules && sheet.cssRules.length) { + rules = rules.concat(toArray(sheet.cssRules)); + } + } + catch (e) { + (_a = win.console) === null || _a === void 0 ? void 0 : _a.warn("Error while reading rules from ".concat(sheet.href, ": ").concat(e.toString())); + } + }); + return rules; +} +/** + * Gets the SVGMatrix of an SVGGElement + * @param {SVGElement} node Node element + * @returns {SVGMatrix} matrix + * @private + */ +function getTranslation(node) { + var transform = node ? node.transform : null; + var baseVal = transform && transform.baseVal; + return baseVal && baseVal.numberOfItems ? + baseVal.getItem(0).matrix : + { a: 0, b: 0, c: 0, d: 0, e: 0, f: 0 }; +} +/** + * Get unique value from array + * @param {Array} data Source data + * @returns {Array} Unique array value + * @private + */ +function getUnique(data) { + var isDate = data[0] instanceof Date; + var d = (isDate ? data.map(Number) : data) + .filter(function (v, i, self) { return self.indexOf(v) === i; }); + return isDate ? d.map(function (v) { return new Date(v); }) : d; +} +/** + * Merge array + * @param {Array} arr Source array + * @returns {Array} + * @private + */ +function mergeArray(arr) { + return arr && arr.length ? arr.reduce(function (p, c) { return p.concat(c); }) : []; +} +/** + * Merge object returning new object + * @param {object} target Target object + * @param {object} objectN Source object + * @returns {object} merged target object + * @private + */ +function mergeObj(target) { + var objectN = []; + for (var _i = 1; _i < arguments.length; _i++) { + objectN[_i - 1] = arguments[_i]; + } + if (!objectN.length || (objectN.length === 1 && !objectN[0])) { + return target; + } + var source = objectN.shift(); + if (isObject(target) && isObject(source)) { + Object.keys(source).forEach(function (key) { + var value = source[key]; + if (isObject(value)) { + !target[key] && (target[key] = {}); + target[key] = mergeObj(target[key], value); + } + else { + target[key] = isArray(value) ? + value.concat() : value; + } + }); + } + return mergeObj.apply(void 0, __spreadArray([target], objectN, false)); +} +/** + * Sort value + * @param {Array} data value to be sorted + * @param {boolean} isAsc true: asc, false: desc + * @returns {number|string|Date} sorted date + * @private + */ +function sortValue(data, isAsc) { + if (isAsc === void 0) { isAsc = true; } + var fn; + if (data[0] instanceof Date) { + fn = isAsc ? function (a, b) { return a - b; } : function (a, b) { return b - a; }; + } + else { + if (isAsc && !data.every(isNaN)) { + fn = function (a, b) { return a - b; }; + } + else if (!isAsc) { + fn = function (a, b) { return (a > b && -1) || (a < b && 1) || (a === b && 0); }; + } + } + return data.concat().sort(fn); +} +/** + * Get min/max value + * @param {string} type 'min' or 'max' + * @param {Array} data Array data value + * @returns {number|Date|undefined} + * @private + */ +function getMinMax$1(type, data) { + var res = data.filter(function (v) { return notEmpty(v); }); + if (res.length) { + if (isNumber(res[0])) { + res = Math[type].apply(Math, res); + } + else if (res[0] instanceof Date) { + res = sortValue(res, type === "min")[0]; + } + } + else { + res = undefined; + } + return res; +} +/** + * Get range + * @param {number} start Start number + * @param {number} end End number + * @param {number} step Step number + * @returns {Array} + * @private + */ +var getRange = function (start, end, step) { + if (step === void 0) { step = 1; } + var res = []; + var n = Math.max(0, Math.ceil((end - start) / step)) | 0; + for (var i = start; i < n; i++) { + res.push(start + i * step); + } + return res; +}; +// emulate event +var emulateEvent = { + mouse: (function () { + var getParams = function () { return ({ + bubbles: false, cancelable: false, screenX: 0, screenY: 0, clientX: 0, clientY: 0 + }); }; + try { + // eslint-disable-next-line no-new + new MouseEvent("t"); + return function (el, eventType, params) { + if (params === void 0) { params = getParams(); } + el.dispatchEvent(new MouseEvent(eventType, params)); + }; + } + catch (e) { + // Polyfills DOM4 MouseEvent + return function (el, eventType, params) { + if (params === void 0) { params = getParams(); } + var mouseEvent = doc.createEvent("MouseEvent"); + // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent + mouseEvent.initMouseEvent(eventType, params.bubbles, params.cancelable, win, 0, // the event's mouse click count + params.screenX, params.screenY, params.clientX, params.clientY, false, false, false, false, 0, null); + el.dispatchEvent(mouseEvent); + }; + } + })(), + touch: function (el, eventType, params) { + var touchObj = new Touch(mergeObj({ + identifier: Date.now(), + target: el, + radiusX: 2.5, + radiusY: 2.5, + rotationAngle: 10, + force: 0.5 + }, params)); + el.dispatchEvent(new TouchEvent(eventType, { + cancelable: true, + bubbles: true, + shiftKey: true, + touches: [touchObj], + targetTouches: [], + changedTouches: [touchObj] + })); + } +}; +/** + * Process the template & return bound string + * @param {string} tpl Template string + * @param {object} data Data value to be replaced + * @returns {string} + * @private + */ +function tplProcess(tpl, data) { + var res = tpl; + for (var x in data) { + res = res.replace(new RegExp("{=".concat(x, "}"), "g"), data[x]); + } + return res; +} +/** + * Get parsed date value + * (It must be called in 'ChartInternal' context) + * @param {Date|string|number} date Value of date to be parsed + * @returns {Date} + * @private + */ +function parseDate(date) { + var _a; + var parsedDate; + if (date instanceof Date) { + parsedDate = date; + } + else if (isString(date)) { + var _b = this, config = _b.config, format = _b.format; + // if fails to parse, try by new Date() + // https://github.com/naver/billboard.js/issues/1714 + parsedDate = (_a = format.dataTime(config.data_xFormat)(date)) !== null && _a !== void 0 ? _a : new Date(date); + } + else if (isNumber(date) && !isNaN(date)) { + parsedDate = new Date(+date); + } + if (!parsedDate || isNaN(+parsedDate)) { + console && console.error && + console.error("Failed to parse x '".concat(date, "' to Date object")); + } + return parsedDate; +} +/** + * Return if the current doc is visible or not + * @returns {boolean} + * @private + */ +function isTabVisible() { + return (doc === null || doc === void 0 ? void 0 : doc.hidden) === false || (doc === null || doc === void 0 ? void 0 : doc.visibilityState) === "visible"; +} +/** + * Get the current input type + * @param {boolean} mouse Config value: interaction.inputType.mouse + * @param {boolean} touch Config value: interaction.inputType.touch + * @returns {string} "mouse" | "touch" | null + * @private + */ +function convertInputType(mouse, touch) { + var DocumentTouch = win.DocumentTouch, matchMedia = win.matchMedia, navigator = win.navigator; + var hasTouch = false; + if (touch) { + // Some Edge desktop return true: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/20417074/ + if (navigator && "maxTouchPoints" in navigator) { + hasTouch = navigator.maxTouchPoints > 0; + // Ref: https://github.com/Modernizr/Modernizr/blob/master/feature-detects/touchevents.js + // On IE11 with IE9 emulation mode, ('ontouchstart' in window) is returning true + } + else if ("ontouchmove" in win || (DocumentTouch && doc instanceof DocumentTouch)) { + hasTouch = true; + } + else { + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#avoiding_user_agent_detection + if (matchMedia === null || matchMedia === void 0 ? void 0 : matchMedia("(pointer:coarse)").matches) { + hasTouch = true; + } + else { + // Only as a last resort, fall back to user agent sniffing + var UA = navigator.userAgent; + hasTouch = (/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) || + /\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA)); + } + } + } + // Check if agent has mouse using any-hover, touch devices (e.g iPad) with external mouse will return true as long as mouse is connected + // https://css-tricks.com/interaction-media-features-and-their-potential-for-incorrect-assumptions/#aa-testing-the-capabilities-of-all-inputs + // Demo: https://patrickhlauke.github.io/touch/pointer-hover-any-pointer-any-hover/ + var hasMouse = mouse && ["any-hover:hover", "any-pointer:fine"] + .some(function (v) { return matchMedia === null || matchMedia === void 0 ? void 0 : matchMedia("(".concat(v, ")")).matches; }); + // fallback to 'mouse' if no input type is detected. + return (hasMouse && "mouse") || (hasTouch && "touch") || "mouse"; +} +/** + * Run function until given condition function return true + * @param {Function} fn Function to be executed when condition is true + * @param {Function} conditionFn Condition function to check if condition is true + * @private + */ +function runUntil(fn, conditionFn) { + if (conditionFn() === false) { + requestAnimationFrame(function () { return runUntil(fn, conditionFn); }); + } + else { + fn(); + } +} + +/** + * Check chart type module imports. + * @param {ChartInternal} ctx Context + * @private + */ +function checkModuleImport(ctx) { + var $$ = ctx; + var config = $$.config; + var type = ""; + if (isEmpty(config.data_type || config.data_types) && !$$[TYPE_METHOD_NEEDED.LINE]) { + type = "line"; + } + else { + for (var x in TYPE_METHOD_NEEDED) { + var t = TYPE[x]; + if ($$.hasType(t) && !$$[TYPE_METHOD_NEEDED[x]]) { + type = t; + break; + } + } + } + type && logError("Please, make sure if %c".concat(camelize(type)), "module has been imported and specified correctly."); +} +/** + * Log error and throw error + * @param {string} head Message header + * @param {string} tail Message tail + * @private + */ +function logError(head, tail) { + var _a; + var prefix = "[billboard.js]"; + var info = "https://github.com/naver/billboard.js/wiki/CHANGELOG-v2#modularization-by-its-functionality"; + var hasConsole = (_a = win.console) === null || _a === void 0 ? void 0 : _a.error; + if (hasConsole) { + console.error("\u274C ".concat(prefix, " ").concat(head), "background:red;color:white;display:block;font-size:15px", tail); + console.info("%cℹ️", "font-size:15px", info); + } + throw Error("".concat(prefix, " ").concat(head.replace(/\%c([a-z-]+)/i, "'$1' "), " ").concat(tail)); +} + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * CSS class names definition + * @private + */ +var $COMMON = { + button: "bb-button", + chart: "bb-chart", + empty: "bb-empty", + main: "bb-main", + target: "bb-target", + EXPANDED: "_expanded_" +}; +var $ARC = { + arc: "bb-arc", + arcLabelLine: "bb-arc-label-line", + arcs: "bb-arcs", + chartArc: "bb-chart-arc", + chartArcs: "bb-chart-arcs", + chartArcsBackground: "bb-chart-arcs-background", + chartArcsTitle: "bb-chart-arcs-title", + needle: "bb-needle" +}; +var $AREA = { + area: "bb-area", + areas: "bb-areas" +}; +var $AXIS = { + axis: "bb-axis", + axisX: "bb-axis-x", + axisXLabel: "bb-axis-x-label", + axisY: "bb-axis-y", + axisY2: "bb-axis-y2", + axisY2Label: "bb-axis-y2-label", + axisYLabel: "bb-axis-y-label" +}; +var $BAR = { + bar: "bb-bar", + bars: "bb-bars", + chartBar: "bb-chart-bar", + chartBars: "bb-chart-bars" +}; +var $CANDLESTICK = { + candlestick: "bb-candlestick", + candlesticks: "bb-candlesticks", + chartCandlestick: "bb-chart-candlestick", + chartCandlesticks: "bb-chart-candlesticks", + valueDown: "bb-value-down", + valueUp: "bb-value-up" +}; +var $CIRCLE = { + chartCircles: "bb-chart-circles", + circle: "bb-circle", + circles: "bb-circles" +}; +var $COLOR = { + colorPattern: "bb-color-pattern", + colorScale: "bb-colorscale" +}; +var $DRAG = { + dragarea: "bb-dragarea", + INCLUDED: "_included_" +}; +var $GAUGE = { + chartArcsGaugeMax: "bb-chart-arcs-gauge-max", + chartArcsGaugeMin: "bb-chart-arcs-gauge-min", + chartArcsGaugeUnit: "bb-chart-arcs-gauge-unit", + chartArcsGaugeTitle: "bb-chart-arcs-gauge-title", + gaugeValue: "bb-gauge-value" +}; +var $LEGEND = { + legend: "bb-legend", + legendBackground: "bb-legend-background", + legendItem: "bb-legend-item", + legendItemEvent: "bb-legend-item-event", + legendItemHidden: "bb-legend-item-hidden", + legendItemPoint: "bb-legend-item-point", + legendItemTile: "bb-legend-item-tile" +}; +var $LINE = { + chartLine: "bb-chart-line", + chartLines: "bb-chart-lines", + line: "bb-line", + lines: "bb-lines" +}; +var $EVENT = { + eventRect: "bb-event-rect", + eventRects: "bb-event-rects", + eventRectsMultiple: "bb-event-rects-multiple", + eventRectsSingle: "bb-event-rects-single", +}; +var $FOCUS = { + focused: "bb-focused", + defocused: "bb-defocused", + legendItemFocused: "bb-legend-item-focused", + xgridFocus: "bb-xgrid-focus", + ygridFocus: "bb-ygrid-focus" +}; +var $GRID = { + grid: "bb-grid", + gridLines: "bb-grid-lines", + xgrid: "bb-xgrid", + xgridLine: "bb-xgrid-line", + xgridLines: "bb-xgrid-lines", + xgrids: "bb-xgrids", + ygrid: "bb-ygrid", + ygridLine: "bb-ygrid-line", + ygridLines: "bb-ygrid-lines", + ygrids: "bb-ygrids" +}; +var $LEVEL = { + level: "bb-level", + levels: "bb-levels" +}; +var $RADAR = { + chartRadar: "bb-chart-radar", + chartRadars: "bb-chart-radars" +}; +var $REGION = { + region: "bb-region", + regions: "bb-regions" +}; +var $SELECT = { + selectedCircle: "bb-selected-circle", + selectedCircles: "bb-selected-circles", + SELECTED: "_selected_" +}; +var $SHAPE = { + shape: "bb-shape", + shapes: "bb-shapes", +}; +var $SUBCHART = { + brush: "bb-brush", + subchart: "bb-subchart" +}; +var $TEXT = { + chartText: "bb-chart-text", + chartTexts: "bb-chart-texts", + text: "bb-text", + texts: "bb-texts", + title: "bb-title", + TextOverlapping: "text-overlapping" +}; +var $TOOLTIP = { + tooltip: "bb-tooltip", + tooltipContainer: "bb-tooltip-container", + tooltipName: "bb-tooltip-name" +}; +var $TREEMAP = { + treemap: "bb-treemap", + chartTreemap: "bb-chart-treemap", + chartTreemaps: "bb-chart-treemaps" +}; +var $ZOOM = { + buttonZoomReset: "bb-zoom-reset", + zoomBrush: "bb-zoom-brush" +}; +var CLASS = _assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign(_assign({}, $COMMON), $ARC), $AREA), $AXIS), $BAR), $CANDLESTICK), $CIRCLE), $COLOR), $DRAG), $GAUGE), $LEGEND), $LINE), $EVENT), $FOCUS), $GRID), $RADAR), $REGION), $SELECT), $SHAPE), $SUBCHART), $TEXT), $TOOLTIP), $TREEMAP), $ZOOM); + +/** + * Elements class. + * @class Elements + * @ignore + * @private + */ +var Element = /** @class */ (function () { + function Element() { + var element = { + chart: null, + main: null, + svg: null, + axis: { + x: null, + y: null, + y2: null, + subX: null + }, + defs: null, + tooltip: null, + legend: null, + title: null, + subchart: { + main: null, + bar: null, + line: null, + area: null // $$.contextArea + }, + arcs: null, + bar: null, + candlestick: null, + line: null, + area: null, + circle: null, + radar: null, + text: null, + grid: { + main: null, + x: null, + y: null, // ygrid, + }, + gridLines: { + main: null, + x: null, + y: null, // ygridLines + }, + region: { + main: null, + list: null // mainRegion + }, + eventRect: null, + zoomResetBtn: null // drag zoom reset button + }; + return element; + } + return Element; +}()); + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * State class. + * @class State + * @ignore + * @private + */ +var State = /** @class */ (function () { + function State() { + return { + // chart drawn area dimension, excluding axes + width: 0, + width2: 0, + height: 0, + height2: 0, + margin: { + top: 0, + bottom: 0, + left: 0, + right: 0 + }, + margin2: { + top: 0, + bottom: 0, + left: 0, + right: 0 + }, + margin3: { + top: 0, + bottom: 0, + left: 0, + right: 0 + }, + arcWidth: 0, + arcHeight: 0, + xAxisHeight: 0, + hasAxis: false, + hasRadar: false, + hasTreemap: false, + // for data CSS rule index (used when boost.useCssRule is true) + cssRule: {}, + current: { + // current domain value. Assigned when is zoom is called + domain: undefined, + // chart whole dimension + width: 0, + height: 0, + dataMax: 0, + maxTickSize: { + x: { width: 0, height: 0, ticks: [], clipPath: 0, domain: "" }, + y: { width: 0, height: 0, domain: "" }, + y2: { width: 0, height: 0, domain: "" } + }, + // current used chart type list + types: [], + needle: undefined, // arc needle current value + }, + // legend + isLegendRight: false, + isLegendInset: false, + isLegendTop: false, + isLegendLeft: false, + legendStep: 0, + legendItemWidth: 0, + legendItemHeight: 0, + legendHasRendered: false, + eventReceiver: { + currentIdx: -1, + rect: {}, + data: [], + coords: [] // coordination value of previous eventRect + }, + axis: { + x: { + padding: { left: 0, right: 0 }, + tickCount: 0 + } + }, + rotatedPadding: { + left: 30, + right: 0, + top: 5 + }, + withoutFadeIn: {}, + inputType: "", + datetimeId: "", + // clip id string + clip: { + id: "", + idXAxis: "", + idYAxis: "", + idXAxisTickTexts: "", + idGrid: "", + idSubchart: "", + path: "", + pathXAxis: "", + pathYAxis: "", + pathXAxisTickTexts: "", + pathGrid: "" + }, + // state + event: null, + dragStart: null, + dragging: false, + flowing: false, + cancelClick: false, + mouseover: false, + rendered: false, + transiting: false, + redrawing: false, + resizing: false, + toggling: false, + zooming: false, + hasNegativeValue: false, + hasPositiveValue: true, + orgAreaOpacity: "0.2", + orgConfig: {}, + // ID strings + hiddenTargetIds: [], + hiddenLegendIds: [], + focusedTargetIds: [], + defocusedTargetIds: [], + // value for Arc + radius: 0, + innerRadius: 0, + outerRadius: undefined, + innerRadiusRatio: 0, + gaugeArcWidth: 0, + radiusExpanded: 0, + // xgrid attribute + xgridAttr: { + x1: null, + x2: null, + y1: null, + y2: null + } + }; + } + return State; +}()); + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +// mapping +var classes = { + element: Element, + state: State +}; +/** + * Internal store class. + * @class Store + * @ignore + * @private + */ +var Store = /** @class */ (function () { + function Store() { + var _this = this; + Object.keys(classes).forEach(function (v) { + _this[v] = new classes[v](); + }); + } + Store.prototype.getStore = function (name) { + return this[name]; + }; + return Store; +}()); + +/** + * main config options + */ +var main = { + /** + * Specify the CSS selector or the element which the chart will be set to. D3 selection object can be specified also.
+ * If other chart is set already, it will be replaced with the new one (only one chart can be set in one element). + * - **NOTE:** In case of element doesn't exist or not specified, will add a `
` element to the body. + * @name bindto + * @memberof Options + * @property {string|HTMLElement|d3.selection|object} [bindto="#chart"] Specify the element where chart will be drawn. + * @property {string|HTMLElement|d3.selection} bindto.element="#chart" Specify the element where chart will be drawn. + * @property {string} [bindto.classname=bb] Specify the class name of bind element.
+ * **NOTE:** When class name isn't `bb`, then you also need to update the default CSS to be rendered correctly. + * @default #chart + * @example + * bindto: "#myContainer" + * + * // or HTMLElement + * bindto: document.getElementById("myContainer") + * + * // or D3 selection object + * bindto: d3.select("#myContainer") + * + * // or to change default classname + * bindto: { + * element: "#chart", + * classname: "bill-board" // ex)
+ * } + */ + bindto: "#chart", + /** + * Set chart background. + * @name background + * @memberof Options + * @property {object} background background object + * @property {string} background.class Specify the class name for background element. + * @property {string} background.color Specify the fill color for background element.
**NOTE:** Will be ignored if `imgUrl` option is set. + * @property {string} background.imgUrl Specify the image url string for background. + * @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.Background) + * @example + * background: { + * class: "myClass", + * color: "red", + * + * // Set image url for background. + * // If specified, 'color' option will be ignored. + * imgUrl: "https://naver.github.io/billboard.js/img/logo/billboard.js.svg", + * } + */ + background: {}, + /** + * Set 'clip-path' attribute for chart element + * - **NOTE:** + * > When is false, chart node element is positioned after the axis node in DOM tree hierarchy. + * > Is to make chart element positioned over axis element. + * @name clipPath + * @memberof Options + * @type {boolean} + * @default true + * @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.clipPath) + * @example + * // don't set 'clip-path' attribute + * clipPath: false + */ + clipPath: true, + /** + * Set svg element's class name + * @name svg + * @memberof Options + * @type {object} + * @property {object} [svg] svg object + * @property {string} [svg.classname] class name for svg element + * @example + * svg: { + * classname: "test_class" + * } + */ + svg_classname: undefined, + /** + * The desired size of the chart element. + * If value is not specified, the width of the chart will be calculated by the size of the parent element it's appended to. + * @name size + * @memberof Options + * @type {object} + * @property {object} [size] size object + * @property {number} [size.width] width of the chart element + * @property {number} [size.height] height of the chart element + * @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.ChartSize) + * @example + * size: { + * width: 640, + * height: 480 + * } + */ + size_width: undefined, + size_height: undefined, + /** + * The padding of the chart element. + * - **NOTE:** for more information, see the "[`Understanding padding`](https://github.com/naver/billboard.js/wiki/Understanding-padding)"" wiki documentaion. + * @name padding + * @memberof Options + * @type {object} + * @property {object|boolean} [padding=true] Set padding of chart, and accepts object or boolean type. + * - `Object`: Specify each side's padding. + * - `false`: Remove padding completely and make shape to fully occupy the container element. + * - In this case, axes and subchart will be hidden. + * - To adjust some padding from this state, use `axis.[x|y].padding` option. + * @property {string} [padding.mode] padding mode + * - `"fit"`: Reduce padding as much as possible to make chart fit to the container element for chart types w/axis.
When specified, all padding values will be relative from fitted value. + * @property {number} [padding.top] padding on the top of chart + * @property {number} [padding.right] padding on the right of chart + * @property {number} [padding.bottom] padding on the bottom of chart + * @property {number} [padding.left] padding on the left of chart + * @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.Padding) + * @see [Demo: Fit padding](https://naver.github.io/billboard.js/demo/#ChartOptions.FitPadding) + * @example + * // remove padding completely. + * padding: false, + * + * padding: { + * // specifying mode value, will reduce padding and make fit to the container element. + * mode: "fit" + * + * // when mode is "fit", all padding values will be relative from fitted value. + * // so, 0 will be initial fitted value. + * top: 20, + * right: 20, + * bottom: 20, + * left: 20 + * } + * + * // or specify padding value for each side + * padding: { + * top: 20, + * right: 20, + * bottom: 20, + * left: 20 + * } + */ + padding: true, + padding_mode: undefined, + padding_left: undefined, + padding_right: undefined, + padding_top: undefined, + padding_bottom: undefined, + /** + * Set chart resize options + * @name resize + * @memberof Options + * @type {object} + * @property {object} [resize] resize object + * @property {boolean} [resize.auto=true] Set chart resize automatically on viewport changes. + * @property {boolean|number} [resize.timer=true] Set resize timer option. + * - **NOTE:** + * - The resize function will be called using: + * - true: `setTimeout()` + * - false: `requestIdleCallback()` + * - Given number(delay in ms) value, resize function will be triggered using `setTimer()` with given delay. + * @example + * resize: { + * auto: false, + * + * // set resize function will be triggered using `setTimer()` + * timer: true, + * + * // set resize function will be triggered using `requestIdleCallback()` + * timer: false, + * + * // set resize function will be triggered using `setTimer()` with a delay of `100ms`. + * timer: 100 + * } + */ + resize_auto: true, + resize_timer: true, + /** + * Set a callback to execute when the chart is clicked. + * @name onclick + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onclick: function(event) { + * this; // chart instance itself + * event; // native event object + * ... + * } + */ + onclick: undefined, + /** + * Set a callback to execute when mouse/touch enters the chart. + * @name onover + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onover: function(event) { + * this; // chart instance itself + * event; // native event object + * ... + * } + */ + onover: undefined, + /** + * Set a callback to execute when mouse/touch leaves the chart. + * @name onout + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onout: function(event) { + * this; // chart instance itself + * event; // native event object + * ... + * } + */ + onout: undefined, + /** + * Set a callback to execute when user resizes the screen. + * @name onresize + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onresize: function() { + * this; // chart instance itself + * ... + * } + */ + onresize: undefined, + /** + * Set a callback to execute when screen resize finished. + * @name onresized + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onresized: function() { + * this; // chart instance itself + * ... + * } + */ + onresized: undefined, + /** + * Set a callback to execute before the chart is initialized + * @name onbeforeinit + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onbeforeinit: function() { + * this; // chart instance itself + * ... + * } + */ + onbeforeinit: undefined, + /** + * Set a callback to execute when the chart is initialized. + * @name oninit + * @memberof Options + * @type {Function} + * @default undefined + * @example + * oninit: function() { + * this; // chart instance itself + * ... + * } + */ + oninit: undefined, + /** + * Set a callback to execute after the chart is initialized + * @name onafterinit + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onafterinit: function() { + * this; // chart instance itself + * ... + * } + */ + onafterinit: undefined, + /** + * Set a callback which is executed when the chart is rendered. Basically, this callback will be called in each time when the chart is redrawed. + * @name onrendered + * @memberof Options + * @type {Function} + * @default undefined + * @example + * onrendered: function() { + * this; // chart instance itself + * ... + * } + */ + onrendered: undefined, + /** + * Set duration of transition (in milliseconds) for chart animation.

+ * - **NOTE:** If `0 `or `null` set, transition will be skipped. So, this makes initial rendering faster especially in case you have a lot of data. + * @name transition + * @memberof Options + * @type {object} + * @property {object} [transition] transition object + * @property {number} [transition.duration=350] duration in milliseconds + * @example + * transition: { + * duration: 500 + * } + */ + transition_duration: 250, + /** + * Set plugins + * @name plugins + * @memberof Options + * @type {Array} + * @example + * plugins: [ + * new bb.plugin.stanford({ ... }), + * new PluginA(), + * ... + * ] + */ + plugins: [], + /** + * Control the render timing + * @name render + * @memberof Options + * @type {object} + * @property {object} [render] render object + * @property {boolean} [render.lazy=true] Make to not render at initialization (enabled by default when bind element's visibility is hidden). + * @property {boolean} [render.observe=true] Observe bind element's visibility(`display` or `visiblity` inline css property or class value) & render when is visible automatically (for IEs, only works IE11+). When set to **false**, call [`.flush()`](./Chart.html#flush) to render. + * @see [Demo](https://naver.github.io/billboard.js/demo/#ChartOptions.LazyRender) + * @example + * render: { + * lazy: true, + * observe: true + * } + * + * @example + * // + * // (a)
+ * // (b) + * + * // render.lazy enabled by default when element is hidden + * var chart = bb.generate({ ... }); + * + * // chart will be rendered automatically when element's visibility changes + * // Note: works only for inlined css property or class attribute changes + * document.getElementById('chart').classList.remove('hide') // (a) + * document.getElementById('chart').style.display = 'block'; // (b) + * + * @example + * // chart won't be rendered and not observing bind element's visiblity changes + * var chart = bb.generate({ + * render: { + * lazy: true, + * observe: false + * } + * }); + * + * // call at any point when you want to render + * chart.flush(); + */ + render: {}, + /** + * Show rectangles inside the chart.

+ * This option accepts array including object that has axis, start, end and class. + * The keys start, end and class are optional. + * axis must be x, y or y2. start and end should be the value where regions start and end. + * If not specified, the edge values will be used. + * If timeseries x axis, date string, Date object and unixtime integer can be used. + * If class is set, the region element will have it as class. + * @name regions + * @memberof Options + * @type {Array} + * @default [] + * @see [Demo](https://naver.github.io/billboard.js/demo/#Region.RegionLabel) + * @example + * regions: [ + * { + * axis: "x", + * start: 1, + * end: 4, + * class: "region-1-4", + * label: { + * text: "Region Text", + * x: 5, // position relative of the initial x coordinate + * y: 5, // position relative of the initial y coordinate + * color: "red", // color string + * rotated: true // make text to show in vertical or horizontal + * } + * } + * ] + */ + regions: [] +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * boost config options + */ +var boost = { + /** + * Set boost options + * @name boost + * @memberof Options + * @type {object} + * @property {object} boost boost object + * @property {boolean} [boost.useCssRule=false] Avoid setting inline styles for each shape elements. + * - **NOTE:** + * - Will append <style> to the head tag and will add shpes' CSS rules dynamically. + * - For now, covers colors related properties (fill, stroke, etc.) only. + * @property {boolean} [boost.useWorker=false] Use Web Worker as possible for processing. + * - **NOTE:** + * - For now, only applies for data conversion at the initial time. + * - As of Web Worker's async nature, handling chart instance synchrously is not recommended. + * @example + * boost: { + * useCssRule: true, + * useWorker: false + * } + */ + boost_useCssRule: false, + boost_useWorker: false +}; + +/** + * data config options + */ +var data$2 = { + /** + * Specify the key of x values in the data.

+ * We can show the data with non-index x values by this option. This option is required when the type of x axis is timeseries. If this option is set on category axis, the values of the data on the key will be used for category names. + * @name data․x + * @memberof Options + * @type {string} + * @default undefined + * @example + * data: { + * x: "date" + * } + */ + data_x: undefined, + /** + * Converts data id value + * @name data․idConverter + * @memberof Options + * @type {Function} + * @default function(id) { return id; } + * @example + * data: { + * idConverter: function(id) { + * // when id is 'data1', converts to be 'data2' + * // 'data2' should be given as the initial data value + * if (id === "data1") { + * return "data2"; + * } else { + * return id; + * } + * } + * } + */ + data_idConverter: function (id) { return id; }, + /** + * Set custom data name. + * If a name is set to `null`, the series is omitted from the legend. + * @name data․names + * @memberof Options + * @type {object} + * @default {} + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.DataName) + * @example + * data: { + * names: { + * data1: "Data Name 1", + * data2: "Data Name 2" + * } + * } + */ + data_names: {}, + /** + * Set custom data class.

+ * If this option is specified, the element g for the data has an additional class that has the prefix 'bb-target-' (eg. bb-target-additional-data1-class). + * @name data․classes + * @memberof Options + * @type {object} + * @default {} + * @example + * data: { + * classes: { + * data1: "additional-data1-class", + * data2: "additional-data2-class" + * } + * } + */ + data_classes: {}, + /** + * Set chart type at once.

+ * If this option is specified, the type will be applied to every data. This setting can be overwritten by data.types.

+ * **Available Values:** + * - area + * - area-line-range + * - area-spline + * - area-spline-range + * - area-step + * - bar + * - bubble + * - candlestick + * - donut + * - gauge + * - line + * - pie + * - polar + * - radar + * - scatter + * - spline + * - step + * - treemap + * @name data․type + * @memberof Options + * @type {string} + * @default "line"
NOTE: When importing shapes by ESM, `line()` should be specified for type. + * @example + * data: { + * type: "bar" + * } + * @example + * // Generate chart by importing ESM + * // Import types to be used only, where this will make smaller bundle size. + * import bb, { + * area, + * areaLineRange, + * areaSpline, + * areaSplineRange, + * areaStep, + * bar, + * bubble, + * candlestick, + * donut, + * gauge, + * line, + * pie, + * polar, + * radar, + * scatter, + * spline, + * step, + * treemap + * } + * + * bb.generate({ + * ..., + * data: { + * type: bar() + * } + * }); + */ + data_type: undefined, + /** + * Set chart type for each data.
+ * This setting overwrites data.type setting. + * - **NOTE:** `radar` and `treemap` type can't be combined with other types. + * @name data․types + * @memberof Options + * @type {object} + * @default {} + * @example + * data: { + * types: { + * data1: "bar", + * data2: "spline" + * } + * } + * @example + * // Generate chart by importing ESM + * // Import types to be used only, where this will make smaller bundle size. + * import bb, { + * area, + * areaLineRange, + * areaSpline, + * areaSplineRange, + * areaStep, + * bar, + * bubble, + * candlestick, + * donut, + * gauge, + * line, + * pie, + * polar, + * radar, + * scatter, + * spline, + * step, + * treemap + * } + * + * bb.generate({ + * ..., + * data: { + * types: { + * data1: bar(), + * data1: spline() + * } + * } + * }); + */ + data_types: {}, + /** + * This option changes the order of stacking data and pieces of pie/donut. + * - If `null` specified, it will be the order the data loaded. + * - If function specified, it will be used as [Array.sort compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters)

+ * + * **Available Values:** + * - `desc`: In descending order + * - `asc`: In ascending order + * - `null`: It keeps the data load order + * - `function(data1, data2) { ... }`: Array.sort compareFunction + * + * **NOTE**: order function, only works for Axis based types & Arc types, except `Radar` type. + * @name data․order + * @memberof Options + * @type {string|Function|null} + * @default desc + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.DataOrder) + * @example + * data: { + * // in descending order (default) + * order: "desc" + * + * // in ascending order + * order: "asc" + * + * // keeps data input order + * order: null + * + * // specifying sort function + * order: function(a, b) { + * // param data passed format + * // { + * // id: "data1", id_org: "data1", values: [ + * // {x: 5, value: 250, id: "data1", index: 5, name: "data1"}, + * // ... + * // ] + * // } + * + * const reducer = (p, c) => p + Math.abs(c.value); + * const aSum = a.values.reduce(reducer, 0); + * const bSum = b.values.reduce(reducer, 0); + * + * // ascending order + * return aSum - bSum; + * + * // descending order + * // return bSum - aSum; + * } + * } + */ + data_order: "desc", + /** + * Set groups for the data for stacking. + * @name data․groups + * @memberof Options + * @type {Array} + * @default [] + * @example + * data: { + * groups: [ + * ["data1", "data2"], + * ["data3"] + * ] + * } + */ + data_groups: [], + /** + * Set how zero value will be treated on groups.
+ * Possible values: + * - `zero`: 0 will be positioned at absolute axis zero point. + * - `positive`: 0 will be positioned at the top of a stack. + * - `negative`: 0 will be positioned at the bottom of a stack. + * @name data․groupsZeroAs + * @memberof Options + * @type {string} + * @default "positive" + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.Groups) + * @example + * data: { + * groupsZeroAs: "zero" // "positive" or "negative" + * } + */ + data_groupsZeroAs: "positive", + /** + * Set color converter function.

+ * This option should a function and the specified function receives color (e.g. '#ff0000') and d that has data parameters like id, value, index, etc. And it must return a string that represents color (e.g. '#00ff00'). + * @name data․color + * @memberof Options + * @type {Function} + * @default undefined + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.DataColor) + * @example + * data: { + * color: function(color, d) { ... } + * } + */ + data_color: undefined, + /** + * Set color for each data. + * @name data․colors + * @memberof Options + * @type {object} + * @default {} + * @example + * data: { + * colors: { + * data1: "#ff0000", + * data2: function(d) { + * return "#000"; + * } + * ... + * } + * } + */ + data_colors: {}, + /** + * Set labels options + * @name data․labels + * @memberof Options + * @type {object} + * @property {object} data Data object + * @property {boolean} [data.labels=false] Show or hide labels on each data points + * @property {boolean} [data.labels.centered=false] Centerize labels on `bar` shape. (**NOTE:** works only for 'bar' type) + * @property {Function} [data.labels.format] Set formatter function for data labels.
+ * The formatter function receives 4 arguments such as `v, id, i, texts` and it **must return a string** (`\n` character will be used as line break) that will be shown as the label.

+ * The arguments are:
+ * - `v` is the value of the data point where the label is shown. + * - `id` is the id of the data where the label is shown. + * - `i` is the index of the data series point where the label is shown. + * - `texts` is the array of whole corresponding data series' text labels.

+ * Formatter function can be defined for each data by specifying as an object and D3 formatter function can be set (ex. d3.format('$')) + * @property {string|object} [data.labels.backgroundColors] Set label text background colors. + * @property {string|object|Function} [data.labels.colors] Set label text colors. + * @property {object|Function} [data.labels.position] Set each dataset position, relative the original.

+ * When function is specified, will receives 5 arguments such as `type, v, id, i, texts` and it must return a position number.

+ * The arguments are:
+ * - `type` coordinate type string, which will be 'x' or 'y'. + * - `v` is the value of the data point where the label is shown. + * - `id` is the id of the data where the label is shown. + * - `i` is the index of the data series point where the label is shown. + * - `texts` is the array of whole corresponding data series' text labels.

+ * @property {number} [data.labels.position.x=0] x coordinate position, relative the original. + * @property {number} [data.labels.position.y=0] y coordinate position, relative the original. + * @property {object} [data.labels.rotate] Rotate label text. Specify degree value in a range of `0 ~ 360`. + * - **NOTE:** Depend on rotate value, text position need to be adjusted manually(using `data.labels.position` option) to be shown nicely. + * @memberof Options + * @type {object} + * @default {} + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.DataLabel) + * @see [Demo: label colors](https://naver.github.io/billboard.js/demo/#Data.DataLabelColors) + * @see [Demo: label format](https://naver.github.io/billboard.js/demo/#Data.DataLabelFormat) + * @see [Demo: label multiline](https://naver.github.io/billboard.js/demo/#Data.DataLabelMultiline) + * @see [Demo: label overlap](https://naver.github.io/billboard.js/demo/#Data.DataLabelOverlap) + * @see [Demo: label position](https://naver.github.io/billboard.js/demo/#Data.DataLabelPosition) + * @see [Demo: label rotate](https://naver.github.io/billboard.js/demo/#Data.DataLabelRotate) + * @example + * data: { + * labels: true, + * + * // or set specific options + * labels: { + * format: function(v, id, i, texts) { + * ... + * // to multiline, return with '\n' character + * return "Line1\nLine2"; + * }, + * + * // it's possible to set for each data + * format: { + * data1: function(v, id, i, texts) { ... }, + * ... + * }, + * + * // align text to center of the 'bar' shape (works only for 'bar' type) + * centered: true, + * + * // apply backgound color for label texts + * backgroundColors: "red", + * + * // set differenct backround colors per dataset + * backgroundColors: { + * data1: "green", + * data2: "yellow" + * } + * + * // apply for all label texts + * colors: "red", + * + * // set different colors per dataset + * // for not specified dataset, will have the default color value + * colors: { + * data1: "yellow", + * data3: "green" + * }, + * + * // call back for label text color + * colors: function(color, d) { + * // color: the default data label color string + * // data: ex) {x: 0, value: 200, id: "data3", index: 0} + * .... + * return d.value > 200 ? "cyan" : color; + * }, + * + * // return x, y coordinate position + * // apt to handle each text position manually + * position: function(type, v, id, i, texts) { + * ... + * return type == "x" ? 10 : 20; + * }, + * + * // set x, y coordinate position + * position: { + * x: -10, + * y: 10 + * }, + * + * // or set x, y coordinate position by each dataset + * position: { + * data1: {x: 5, y: 5}, + * data2: {x: 10, y: -20} + * }, + * + * // rotate degree for label text + * rotate: 90 + * } + * } + */ + data_labels: {}, + data_labels_backgroundColors: undefined, + data_labels_colors: undefined, + data_labels_position: {}, + /** + * Hide each data when the chart appears.

+ * If true specified, all of data will be hidden. If multiple ids specified as an array, those will be hidden. + * @name data․hide + * @memberof Options + * @type {boolean|Array} + * @default false + * @example + * data: { + * // all of data will be hidden + * hide: true + * + * // specified data will be hidden + * hide: ["data1", ...] + * } + */ + data_hide: false, + /** + * Filter values to be shown + * The data value is the same as the returned by `.data()`. + * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter + * @name data․filter + * @memberof Options + * @type {Function} + * @default undefined + * @example + * data: { + * // filter for id value + * filter: function(v) { + * // v: [{id: "data1", id_org: "data1", values: [ + * // {x: 0, value: 130, id: "data2", index: 0}, ...] + * // }, ...] + * return v.id !== "data1"; + * } + */ + data_filter: undefined, + /** + * Set a callback for click event on each data point.

+ * This callback will be called when each data point clicked and will receive `d` and element as the arguments. + * - `d` is the data clicked and element is the element clicked. + * - `element` is the current interacting svg element. + * - In this callback, `this` will be the Chart object. + * @name data․onclick + * @memberof Options + * @type {Function} + * @default function() {} + * @example + * data: { + * onclick: function(d, element) { + * // d - ex) {x: 4, value: 150, id: "data1", index: 4, name: "data1"} + * // element - + * ... + * } + * } + */ + data_onclick: function () { }, + /** + * Set a callback for mouse/touch over event on each data point.

+ * This callback will be called when mouse cursor or via touch moves onto each data point and will receive `d` and `element` as the argument. + * - `d` is the data where mouse cursor moves onto. + * - `element` is the current interacting svg element. + * - In this callback, `this` will be the Chart object. + * @name data․onover + * @memberof Options + * @type {Function} + * @default function() {} + * @example + * data: { + * onover: function(d, element) { + * // d - ex) {x: 4, value: 150, id: "data1", index: 4} + * // element - + * ... + * } + * } + */ + data_onover: function () { }, + /** + * Set a callback for mouse/touch out event on each data point.

+ * This callback will be called when mouse cursor or via touch moves out each data point and will receive `d` as the argument. + * - `d` is the data where mouse cursor moves out. + * - `element` is the current interacting svg element. + * - In this callback, `this` will be the Chart object. + * @name data․onout + * @memberof Options + * @type {Function} + * @default function() {} + * @example + * data: { + * onout: function(d, element) { + * // d - ex) {x: 4, value: 150, id: "data1", index: 4} + * // element - + * ... + * } + * } + */ + data_onout: function () { }, + /** + * Set a callback for when data is shown.
+ * The callback will receive shown data ids in array. + * @name data․onshown + * @memberof Options + * @type {Function} + * @default undefined + * @example + * data: { + * onshown: function(ids) { + * // ids - ["data1", "data2", ...] + * ... + * } + * } + */ + data_onshown: undefined, + /** + * Set a callback for when data is hidden.
+ * The callback will receive hidden data ids in array. + * @name data․onhidden + * @memberof Options + * @type {Function} + * @default undefined + * @example + * data: { + * onhidden: function(ids) { + * // ids - ["data1", "data2", ...] + * ... + * } + * } + */ + data_onhidden: undefined, + /** + * Set a callback for minimum data + * - **NOTE:** For 'area-line-range' and 'area-spline-range', `mid` data will be taken for the comparison + * @name data․onmin + * @memberof Options + * @type {Function} + * @default undefined + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.OnMinMaxCallback) + * @example + * onmin: function(data) { + * // data - ex) [{x: 3, value: 400, id: "data1", index: 3}, ... ] + * ... + * } + */ + data_onmin: undefined, + /** + * Set a callback for maximum data + * - **NOTE:** For 'area-line-range' and 'area-spline-range', `mid` data will be taken for the comparison + * @name data․onmax + * @memberof Options + * @type {Function} + * @default undefined + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.OnMinMaxCallback) + * @example + * onmax: function(data) { + * // data - ex) [{x: 3, value: 400, id: "data1", index: 3}, ... ] + * ... + * } + */ + data_onmax: undefined, + /** + * Load a CSV or JSON file from a URL. NOTE that this will not work if loading via the "file://" protocol as the most browsers will block XMLHTTPRequests. + * @name data․url + * @memberof Options + * @type {string} + * @default undefined + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.LoadData) + * @example + * data: { + * url: "/data/test.csv" + * } + */ + data_url: undefined, + /** + * XHR header value + * - **NOTE:** Should be used with `data.url` option + * @name data․headers + * @memberof Options + * @type {string} + * @default undefined + * @see https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/setRequestHeader + * @example + * data: { + * url: "/data/test.csv", + * headers: { + * "Content-Type": "text/xml", + * ... + * } + * } + */ + data_headers: undefined, + /** + * Parse a JSON object for data. See also data.keys. + * @name data․json + * @memberof Options + * @type {Array} + * @default undefined + * @see [data․keys](#.data%25E2%2580%25A4keys) + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.JSONData) + * @example + * data: { + * json: [ + * {name: "www.site1.com", upload: 200, download: 200, total: 400}, + * {name: "www.site2.com", upload: 100, download: 300, total: 400}, + * {name: "www.site3.com", upload: 300, download: 200, total: 500}, + * {name: "www.site4.com", upload: 400, download: 100, total: 500} + * ], + * keys: { + * // case 1: specify 'x' key for category axis + * x: "name", // 'name' key will be used as category x axis values + * value: ["upload", "download"] + * + * // case 2: without 'x' key for non-category axis + * value: ["upload", "download"] + * } + * } + */ + data_json: undefined, + /** + * Load data from a multidimensional array, with the first element containing the data names, the following containing related data in that order. + * @name data․rows + * @memberof Options + * @type {Array} + * @default undefined + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.RowOrientedData) + * @example + * data: { + * rows: [ + * ["A", "B", "C"], + * [90, 120, 300], + * [40, 160, 240], + * [50, 200, 290], + * [120, 160, 230], + * [80, 130, 300], + * [90, 220, 320] + * ] + * } + * + * // for 'bar' type, data can contain: + * // - an array of [start, end] data following the order + * data: { + * rows: [ + * ["data1", "data2"], + * [[100, 150], 120], + * [[200, 300], 55], + * [[-400, 500], 60] + * ], + * type: "bar" + * } + * + * // for 'range' types('area-line-range' or 'area-spline-range'), data should contain: + * // - an array of [high, mid, low] data following the order + * // - or an object with 'high', 'mid' and 'low' key value + * data: { + * rows: [ + * ["data1", "data2"], + * [ + * // or {high:150, mid: 140, low: 110}, 120 + * [150, 140, 110], 120 + * ], + * [[155, 130, 115], 55], + * [[160, 135, 120], 60] + * ], + * types: { + * data1: "area-line-range", + * data2: "line" + * } + * } + * + * // for 'bubble' type, data can contain dimension value: + * // - an array of [y, z] data following the order + * // - or an object with 'y' and 'z' key value + * // 'y' is for y axis coordination and 'z' is the bubble radius value + * data: { + * rows: [ + * ["data1", "data2"], + * [ + * // or {y:10, z: 140}, 120 + * [10, 140], 120 + * ], + * [[100, 30], 55], + * [[50, 100], 60] + * ], + * types: { + * data1: "bubble", + * data2: "line" + * } + * } + * + * // for 'canlestick' type, data should contain: + * // - an array of [open, high, low, close, volume(optional)] data following the order + * // - or an object with 'open', 'high', 'low', 'close' and 'value'(optional) key value + * data: { + * rows: [ + * ["data1", "data2"], + * [ + * // open, high, low, close, volume (optional) + * {open: 1300, high: 1369, low: 1200, close: 1339, volume: 100}, + * [1000, 1100, 850, 870] + * ], + * [ + * {open: 1348, high: 1371, low: 1271, close: 1320}, + * [870, 1250, 830, 1200, 50] + * ] + * ], + * type: "candlestick" + * } + */ + data_rows: undefined, + /** + * Load data from a multidimensional array, with each element containing an array consisting of a datum name and associated data values. + * @name data․columns + * @memberof Options + * @type {Array} + * @default undefined + * @see [Demo](https://naver.github.io/billboard.js/demo/#Data.ColumnOrientedData) + * @example + * data: { + * columns: [ + * ["data1", 30, 20, 50, 40, 60, 50], + * ["data2", 200, 130, 90, 240, 130, 220], + * ["data3", 300, 200, 160, 400, 250, 250] + * ] + * } + * + * // for 'bar' type, data can contain: + * // - an array of [start, end] data following the order + * data: { + * columns: [ + * ["data1", -100, 50, [100, 200], [200, 300]], + * ["data2", -200, 300, [-100, 100], [-50, -30]], + * ], + * type: "bar" + * } + * + * // for 'range' types('area-line-range' or 'area-spline-range'), data should contain: + * // - an array of [high, mid, low] data following the order + * // - or an object with 'high', 'mid' and 'low' key value + * data: { + * columns: [ + * ["data1", + * [150, 140, 110], // or {high:150, mid: 140, low: 110} + * [150, 140, 110], + * [150, 140, 110] + * ] + * ], + * type: "area-line-range" + * } + * + * // for 'bubble' type, data can contain dimension value: + * // - an array of [y, z] data following the order + * // - or an object with 'y' and 'z' key value + * // 'y' is for y axis coordination and 'z' is the bubble radius value + * data: { + * columns: [ + * ["data1", + * [10, 140], // or {y:10, z: 140} + * [100, 30], + * [50, 100] + * ] + * ], + * type: "bubble" + * } + * + * // for 'canlestick' type, data should contain: + * // - an array of [open, high, low, close, volume(optional)] data following the order + * // - or an object with 'open', 'high', 'low', 'close' and 'value'(optional) key value + * data: { + * columns: [ + * ["data1", + * [1000, 1100, 850, 870, 100], // or {open:1000, high: 1100, low: 870, volume: 100} + * [870, 1250, 830, 1200] // 'volume' can be omitted + * ] + * ], + * type: "candlestick" + * } + */ + data_columns: undefined, + /** + * Used if loading JSON via data.url. + * - **Available Values:** + * - json + * - csv + * - tsv + * @name data․mimeType + * @memberof Options + * @type {string} + * @default csv + * @example + * data: { + * mimeType: "json" + * } + */ + data_mimeType: "csv", + /** + * Choose which JSON object keys correspond to desired data. + * - **NOTE:** Only for JSON object given as array. + * @name data․keys + * @memberof Options + * @type {string} + * @default undefined + * @example + * data: { + * json: [ + * {name: "www.site1.com", upload: 200, download: 200, total: 400}, + * {name: "www.site2.com", upload: 100, download: 300, total: 400}, + * {name: "www.site3.com", upload: 300, download: 200, total: 500}, + * {name: "www.site4.com", upload: 400, download: 100, total: 500} + * ], + * keys: { + * // case 1: specify 'x' key for category axis + * x: "name", // 'name' key will be used as category x axis values + * value: ["upload", "download"] + * + * // case 2: without 'x' key for non-category axis + * value: ["upload", "download"] + * } + * } + */ + data_keys: undefined, + /** + * Set text label to be displayed when there's no data to show. + * - ex. Toggling all visible data to not be shown, unloading all current data, etc. + * @name data․empty․label․text + * @memberof Options + * @type {string} + * @default "" + * @example + * data: { + * empty: { + * label: { + * text: "No Data" + * } + * } + * } + */ + data_empty_label_text: "" +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * color config options + */ +var color$1 = { + /** + * Set color of the data values + * @name color + * @memberof Options + * @type {object} + * @property {object} color color object + * @property {string|object|Function} [color.onover] Set the color value for each data point when mouse/touch onover event occurs. + * @property {Array|null} [color.pattern=[]] Set custom color pattern. Passing `null` will not set a color for these elements, which requires the usage of custom CSS-based theming to work. + * @property {Function} [color.tiles] if defined, allows use svg's patterns to fill data area. It should return an array of [SVGPatternElement](https://developer.mozilla.org/en-US/docs/Web/API/SVGPatternElement). + * - **NOTE:** The pattern element's id will be defined as `bb-colorize-pattern-$COLOR-VALUE`.
+ * ex. When color pattern value is `['red', '#fff']` and defined 2 patterns,then ids for pattern elements are:
+ * - `bb-colorize-pattern-red` + * - `bb-colorize-pattern-fff` + * @property {object} [color.threshold] color threshold for gauge and tooltip color + * @property {string} [color.threshold.unit] If set to `value`, the threshold will be based on the data value. Otherwise it'll be based on equation of the `threshold.max` option value. + * @property {Array} [color.threshold.values] Threshold values for each steps + * @property {number} [color.threshold.max=100] The base value to determine threshold step value condition. When the given value is 15 and max 10, then the value for threshold is `15*100/10`. + * @example + * color: { + * pattern: ["#1f77b4", "#aec7e8", ...], + * + * // Set colors' patterns + * // it should return an array of SVGPatternElement + * tiles: function() { + * var pattern = document.createElementNS("http://www.w3.org/2000/svg", "pattern"); + * var g = document.createElementNS("http://www.w3.org/2000/svg", "g"); + * var circle1 = document.createElementNS("http://www.w3.org/2000/svg", "circle"); + * + * pattern.setAttribute("patternUnits", "userSpaceOnUse"); + * pattern.setAttribute("width", "32"); + * pattern.setAttribute("height", "32"); + * + * g.style.fill = "#000"; + * g.style.opacity = "0.2"; + * + * circle1.setAttribute("cx", "3"); + * circle1.setAttribute("cy", "3"); + * circle1.setAttribute("r", "3"); + * + * g.appendChild(circle1); + * pattern.appendChild(g); + * + * return [pattern]; + * }, + * + * // for threshold usage, pattern values should be set for each steps + * pattern: ["grey", "green", "yellow", "orange", "red"], + * threshold: { + * unit: "value", + * + * // when value is 20 => 'green', value is 40 => 'orange' will be set. + * values: [10, 20, 30, 40, 50], + * + * // the equation for max: + * // - unit == 'value': max => 30 + * // - unit != 'value': max => value*100/30 + * max: 30 + * }, + * + * // set all data to 'red' + * onover: "red", + * + * // set different color for data + * onover: { + * data1: "red", + * data2: "yellow" + * }, + * + * // will pass data object to the callback + * onover: function(d) { + * return d.id === "data1" ? "red" : "green"; + * } + * } + */ + color_pattern: [], + color_tiles: undefined, + color_threshold: {}, + color_onover: undefined +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * interaction config options + */ +var interaction$1 = { + /** + * Interaction options + * @name interaction + * @memberof Options + * @type {object} + * @property {object} interaction Intersection object + * @property {boolean} [interaction.enabled=true] Indicate if the chart should have interactions.
+ * If `false` is set, all of interactions (showing/hiding tooltip, selection, mouse events, etc) will be disabled. + * @property {boolean} [interaction.brighten=true] Make brighter for the selected area (ex. 'pie' type data selected area) + * @property {boolean} [interaction.inputType.mouse=true] enable or disable mouse interaction + * @property {boolean} [interaction.inputType.touch=true] enable or disable touch interaction + * @property {boolean|number} [interaction.inputType.touch.preventDefault=false] enable or disable to call event.preventDefault on touchstart & touchmove event. It's usually used to prevent document scrolling. + * @see [Demo: touch.preventDefault](https://naver.github.io/billboard.js/demo/#Interaction.PreventScrollOnTouch) + * @example + * interaction: { + * enabled: false, + * brighten: false, + * inputType: { + * mouse: true, + * touch: false + * + * // or declare preventDefault explicitly. + * // In this case touch inputType is enabled by default + * touch: { + * preventDefault: true + * + * // or threshold pixel value (pixel moved from touchstart to touchmove) + * preventDefault: 5 + * } + * } + * } + */ + interaction_enabled: true, + interaction_brighten: true, + interaction_inputType_mouse: true, + interaction_inputType_touch: {} +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * legend config options + */ +var legend$2 = { + /** + * Legend options + * @name legend + * @memberof Options + * @type {object} + * @property {object} legend Legend object + * @property {boolean} [legend.show=true] Show or hide legend. + * @property {boolean} [legend.hide=false] Hide legend + * If true given, all legend will be hidden. If string or array given, only the legend that has the id will be hidden. + * @property {string|HTMLElement} [legend.contents.bindto=undefined] Set CSS selector or element reference to bind legend items. + * - **NOTE:** Should be used along with `legend.contents.template`. + * @property {string|Function} [legend.contents.template="{=TITLE}"] Set item's template.
+ * - If set `string` value, within template the 'color' and 'title' can be replaced using template-like syntax string: + * - {=COLOR}: data color value + * - {=TITLE}: data title value + * - If set `function` value, will pass following arguments to the given function: + * - title {string}: data's id value + * - color {string}: color string + * - data {Array}: data array + * @property {string} [legend.position=bottom] Change the position of legend.
+ * Available values are: `bottom`, `right` and `inset` are supported. + * @property {object} [legend.inset={anchor: 'top-left',x: 10,y: 0,step: undefined}] Change inset legend attributes.
+ * This option accepts object that has the keys `anchor`, `x`, `y` and `step`. + * - **anchor** decides the position of the legend: + * - top-left + * - top-right + * - bottom-left + * - bottom-right + * - **x** and **y**: + * - set the position of the legend based on the anchor. + * - **step**: + * - defines the max step the legend has (e.g. If 2 set and legend has 3 legend item, the legend 2 columns). + * @property {boolean} [legend.equally=false] Set to all items have same width size. + * @property {number} [legend.padding=0] Set padding value + * @property {boolean} [legend.item.interaction=true] Set legend item interaction. + * - **NOTE:** + * - This setting will not have effect on `.toggle()` method. + * - `legend.item.onXXX` listener options will work if set, regardless of this option value. + * @property {boolean} [legend.item.interaction.dblclick=false] Set legend item to interact on double click. + * - **NOTE:** + * - Double clicking will make focused clicked dataseries only, hiding all others. + * - for single click case, `click + altKey(Win)/optionKey(Mac OS)` to have same effect. + * - To return initial state(which all dataseries are showing), double click current focused legend item again. + * - for single click case, `click + altKey(Win)/optionKey(Mac OS)` to have same effect. + * - In this case, default `click` interaction will be disabled. + * @property {Function} [legend.item.onclick=undefined] Set click event handler to the legend item. + * - **NOTE:** + * - When set, default `click` interaction will be disabled. + * - When `interaction.dblclick=true` is set, will be called on double click. + * @property {Function} [legend.item.onover=undefined] Set mouse/touch over event handler to the legend item. + * - **NOTE:** When set, default `mouseover` interaction will be disabled. + * @property {Function} [legend.item.onout=undefined] Set mouse/touch out event handler to the legend item. + * - **NOTE:** When set, default `mouseout` interaction will be disabled. + * @property {number} [legend.item.tile.width=10] Set width for 'rectangle' legend item tile element. + * @property {number} [legend.item.tile.height=10] Set height for 'rectangle' legend item tile element. + * @property {number} [legend.item.tile.r=5] Set the radius for 'circle' legend item tile type. + * @property {string} [legend.item.tile.type="rectangle"] Set legend item shape type.
+ * - **Available Values:** + * - circle + * - rectangle + * @property {boolean} [legend.usePoint=false] Whether to use custom points in legend. + * @see [Demo: item.interaction](https://naver.github.io/billboard.js/demo/#Legend.LegendItemInteraction) + * @see [Demo: item.tile.type](https://naver.github.io/billboard.js/demo/#Legend.LegendItemTileType) + * @see [Demo: position](https://naver.github.io/billboard.js/demo/#Legend.LegendPosition) + * @see [Demo: contents.template](https://naver.github.io/billboard.js/demo/#Legend.LegendTemplate1) + * @see [Demo: usePoint](https://naver.github.io/billboard.js/demo/#Legend.usePoint) + * @example + * legend: { + * show: true, + * hide: true, + * //or hide: "data1" + * //or hide: ["data1", "data2"] + * contents: { + * bindto: "#legend", //
    + * + * // will be as:
  • data1
  • + * template: "
  • {=TITLE}
  • " + * + * // or using function + * template: function(id, color, data) { + * // if you want omit some legend, return falsy value + * if (id !== "data1") { + * return "
  • {=TITLE}", + legend_equally: false, + legend_hide: false, + legend_inset_anchor: "top-left", + legend_inset_x: 10, + legend_inset_y: 0, + legend_inset_step: undefined, + legend_item_interaction: true, + legend_item_dblclick: false, + legend_item_onclick: undefined, + legend_item_onover: undefined, + legend_item_onout: undefined, + legend_item_tile_width: 10, + legend_item_tile_height: 10, + legend_item_tile_r: 5, + legend_item_tile_type: "rectangle", + legend_padding: 0, + legend_position: "bottom", + legend_show: true, + legend_usePoint: false +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * title config options + */ +var title$1 = { + /** + * Set title options + * @name title + * @memberof Options + * @type {object} + * @property {object} title Title object + * @property {string} [title.text] Title text. If contains `\n`, it's used as line break allowing multiline title. + * @property {number} [title.padding.top=0] Top padding value. + * @property {number} [title.padding.right=0] Right padding value. + * @property {number} [title.padding.bottom=0] Bottom padding value. + * @property {number} [title.padding.left=0] Left padding value. + * @property {string} [title.position=center] Available values are: 'center', 'right' and 'left'. + * @see [Demo](https://naver.github.io/billboard.js/demo/#Title.MultilinedTitle) + * @example + * title: { + * text: "Title Text", + * + * // or Multiline title text + * text: "Main title text\nSub title text", + * + * padding: { + * top: 10, + * right: 10, + * bottom: 10, + * left: 10 + * }, + * position: "center" + * } + */ + title_text: undefined, + title_padding: { + top: 0, + right: 0, + bottom: 0, + left: 0 + }, + title_position: "center" +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * tooltip config options + */ +var tooltip$2 = { + /** + * Tooltip options + * @name tooltip + * @memberof Options + * @type {object} + * @property {object} tooltip Tooltip object + * @property {boolean} [tooltip.show=true] Show or hide tooltip. + * @property {boolean} [tooltip.doNotHide=false] Make tooltip keep showing not hiding on interaction. + * @property {boolean} [tooltip.grouped=true] Set if tooltip is grouped or not for the data points. + * - **NOTE:** The overlapped data points will be displayed as grouped even if set false. + * @property {boolean} [tooltip.linked=false] Set if tooltips on all visible charts with like x points are shown together when one is shown. + * @property {string} [tooltip.linked.name=""] Groping name for linked tooltip.
    If specified, linked tooltip will be groped interacting to be worked only with the same name. + * @property {Function} [tooltip.format.title] Set format for the title of tooltip.
    + * Specified function receives x of the data point to show. + * @property {Function} [tooltip.format.name] Set format for the name of each data in tooltip.
    + * Specified function receives name, ratio, id and index of the data point to show. ratio will be undefined if the chart is not donut/pie/gauge. + * @property {Function} [tooltip.format.value] Set format for the value of each data value in tooltip. If undefined returned, the row of that value will be skipped to be called. + * - Will pass following arguments to the given function: + * - `value {string}`: Value of the data point. If data row contains multiple or ranged(ex. candlestick, area range, etc.) value, formatter will be called as value length. + * - `ratio {number}`: Ratio of the data point in the `pie/donut/gauge` and `area/bar` when contains grouped data. Otherwise is `undefined`. + * - `id {string}`: id of the data point + * - `index {number}`: Index of the data point + * @property {Function} [tooltip.position] Set custom position function for the tooltip.
    + * This option can be used to modify the tooltip position by returning object that has top and left. + * - Will pass following arguments to the given function: + * - `data {Array}`: Current selected data array object. + * - `width {number}`: Width of tooltip. + * - `height {number}`: Height of tooltip. + * - `element {SVGElement}`: Tooltip event bound element + * - `pos {object}`: Current position of the tooltip. + * @property {Function|object} [tooltip.contents] Set custom HTML for the tooltip.
    + * If tooltip.grouped is true, data includes multiple data points.

    + * Specified function receives `data` array and `defaultTitleFormat`, `defaultValueFormat` and `color` functions of the data point to show. + * - **Note:** + * - defaultTitleFormat: + * - if `axis.x.tick.format` option will be used if set. + * - otherwise, will return function based on tick format type(category, timeseries). + * - defaultValueFormat: + * - for Arc type (except gauge, radar), the function will return value from `(ratio * 100).toFixed(1)`. + * - for Axis based types, will be used `axis.[y|y2].tick.format` option value if is set. + * - otherwise, will parse value and return as number. + * @property {string|HTMLElement} [tooltip.contents.bindto=undefined] Set CSS selector or element reference to bind tooltip. + * - **NOTE:** When is specified, will not be updating tooltip's position. + * @property {string} [tooltip.contents.template=undefined] Set tooltip's template.

    + * Within template, below syntax will be replaced using template-like syntax string: + * - **{{ ... }}**: the doubly curly brackets indicate loop block for data rows. + * - **{=CLASS_TOOLTIP}**: default tooltip class name `bb-tooltip`. + * - **{=CLASS_TOOLTIP_NAME}**: default tooltip data class name (ex. `bb-tooltip-name-data1`) + * - **{=TITLE}**: title value. + * - **{=COLOR}**: data color. + * - **{=VALUE}**: data value. + * @property {object} [tooltip.contents.text=undefined] Set additional text content within data loop, using template syntax. + * - **NOTE:** It should contain `{ key: Array, ... }` value + * - 'key' name is used as substitution within template as '{=KEY}' + * - The value array length should match with the data length + * @property {boolean} [tooltip.init.show=false] Show tooltip at the initialization. + * @property {number} [tooltip.init.x=0] Set x Axis index(or index for Arc(donut, gauge, pie) types) to be shown at the initialization. + * @property {object} [tooltip.init.position] Set the position of tooltip at the initialization. + * @property {Function} [tooltip.onshow] Set a callback that will be invoked before the tooltip is shown. + * @property {Function} [tooltip.onhide] Set a callback that will be invoked before the tooltip is hidden. + * @property {Function} [tooltip.onshown] Set a callback that will be invoked after the tooltip is shown + * @property {Function} [tooltip.onhidden] Set a callback that will be invoked after the tooltip is hidden. + * @property {string|Function|null} [tooltip.order=null] Set tooltip data display order.

    + * **Available Values:** + * - `desc`: In descending data value order + * - `asc`: In ascending data value order + * - `null`: It keeps the data display order
    + * **NOTE:** When `data.groups` is set, the order will follow as the stacked graph order.
    + * If want to order as data bound, set any value rather than asc, desc or null. (ex. empty string "") + * - `function(data1, data2) { ... }`: [Array.sort compareFunction](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort#Parameters) + * @see [Demo: Hide Tooltip](https://naver.github.io/billboard.js/demo/#Tooltip.HideTooltip) + * @see [Demo: Tooltip Grouping](https://naver.github.io/billboard.js/demo/#Tooltip.TooltipGrouping) + * @see [Demo: Tooltip Format](https://naver.github.io/billboard.js/demo/#Tooltip.TooltipFormat) + * @see [Demo: Linked Tooltip](https://naver.github.io/billboard.js/demo/#Tooltip.LinkedTooltips) + * @see [Demo: Tooltip Position](https://naver.github.io/billboard.js/demo/#Tooltip.TooltipPosition) + * @see [Demo: Tooltip Template](https://naver.github.io/billboard.js/demo/#Tooltip.TooltipTemplate) + * @example + * tooltip: { + * show: true, + * doNotHide: true, + * grouped: false, + * format: { + * title: function(x) { return "Data " + x; }, + * name: function(name, ratio, id, index) { return name; }, + * + * // If data row contains multiple or ranged(ex. candlestick, area range, etc.) value, + * // formatter will be called as value length times. + * value: function(value, ratio, id, index) { return ratio; } + * }, + * position: function(data, width, height, element, pos) { + * // data: [{x, index, id, name, value}, ...] + * // width: Tooltip width + * // height: Tooltip height + * // element: Tooltip event bound element + * // pos: { + * // x: Current mouse event x position, + * // y: Current mouse event y position, + * // xAxis: Current x Axis position (the value is given for axis based chart type only) + * // yAxis: Current y Axis position value or function(the value is given for axis based chart type only) + * // } + * + * // yAxis will work differently per data lenghts + * // - a) Single data: `yAxis` will return `number` value + * // - b) Multiple data: `yAxis` will return a function with property value + * + * // a) Single data: + * // Get y coordinate + * pos.yAxis; // y axis coordinate value of current data point + * + * // b) Multiple data: + * // Get y coordinate of value 500, where 'data1' scales(y or y2). + * // When 'data.axes' option is used, data can bound to different axes. + * // - when "data.axes={data1: 'y'}", wil return y value from y axis scale. + * // - when "data.axes={data1: 'y2'}", wil return y value from y2 axis scale. + * pos.yAxis(500, "data1"); // will return y coordinate value of data1 + * + * pos.yAxis(500); // get y coordinate with value of 500, using y axis scale + * pos.yAxis(500, null, "y2"); // get y coordinate with value of 500, using y2 axis scale + * + * return { + * top: 0, + * left: 0 + * } + * }, + * + * contents: function(d, defaultTitleFormat, defaultValueFormat, color) { + * return ... // formatted html as you want + * }, + * + * // specify tooltip contents using template + * // - example of HTML returned: + * //
      + * //
    • 250
      data1
    • + * //
    • 50
      data2
    • + * //
    + * contents: { + * bindto: "#tooltip", + * template: '
      {{' + + * '
    • {=VALUE}
      ' + + * '{=NAME}
    • ' + + * '}}
    ' + * } + * + * // with additional text value + * // - example of HTML returned: + * //
      + * //
    • 250
      comment1data1text1
    • + * //
    • 50
      comment2data2text2
    • + * //
    + * contents: { + * bindto: "#tooltip", + * text: { + * // a) 'key' name is used as substitution within template as '{=KEY}' + * // b) the length should match with the data length + * VAR1: ["text1", "text2"], + * VAR2: ["comment1", "comment2"], + * }, + * template: '
      {{' + + * '
    • {=VALUE}{=VAR2}
      ' + + * '{=NAME}{=VAR1}
    • ' + + * '}}
    ' + * } + * + * // sort tooltip data value display in ascending order + * order: "asc", + * + * // specifying sort function + * order: function(a, b) { + * // param data passed format + * {x: 5, value: 250, id: "data1", index: 5, name: "data1"} + * ... + * }, + * + * // show at the initialization + * init: { + * show: true, + * x: 2, // x Axis index (or index for Arc(donut, gauge, pie) types) + * position: { + * top: "150px", // specify as number or as string with 'px' unit string + * left: 250 // specify as number or as string with 'px' unit string + * } + * }, + * + * // fires prior tooltip is shown + * onshow: function(selectedData) { + * // current dataset selected + * // ==> [{x: 4, value: 150, id: "data2", index: 4, name: "data2"}, ...] + * selectedData; + * }, + * + * // fires prior tooltip is hidden + * onhide: function(selectedData) { + * // current dataset selected + * // ==> [{x: 4, value: 150, id: "data2", index: 4, name: "data2"}, ...] + * selectedData; + * }, + * + * // fires after tooltip is shown + * onshown: function(selectedData) { + * // current dataset selected + * // ==> [{x: 4, value: 150, id: "data2", index: 4, name: "data2"}, ...] + * selectedData; + * }, + * + * // fires after tooltip is hidden + * onhidden: function(selectedData) { + * // current dataset selected + * // ==> [{x: 4, value: 150, id: "data2", index: 4, name: "data2"}, ...] + * selectedData; + * }, + * + * // Link any tooltips when multiple charts are on the screen where same x coordinates are available + * // Useful for timeseries correlation + * linked: true, + * + * // Specify name to interact those with the same name only. + * linked: { + * name: "some-group" + * } + * } + */ + tooltip_show: true, + tooltip_doNotHide: false, + tooltip_grouped: true, + tooltip_format_title: undefined, + tooltip_format_name: undefined, + tooltip_format_value: undefined, + tooltip_position: undefined, + tooltip_contents: {}, + tooltip_init_show: false, + tooltip_init_x: 0, + tooltip_init_position: undefined, + tooltip_linked: false, + tooltip_linked_name: "", + tooltip_onshow: function () { }, + tooltip_onhide: function () { }, + tooltip_onshown: function () { }, + tooltip_onhidden: function () { }, + tooltip_order: null +}; + +/** + * Class to set options on generating chart. + * - It's instantiated internally, not exposed for public. + * @class Options + * @see {@link bb.generate} to use these options on generating the chart + */ +var Options = /** @class */ (function () { + function Options() { + return deepClone(main, boost, data$2, color$1, interaction$1, legend$2, title$1, tooltip$2, Options.data); + } + Options.setOptions = function (options) { + this.data = options + .reduce(function (a, c) { return (_assign(_assign({}, a), c)); }, this.data); + }; + Options.data = {}; + return Options; +}()); + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Constant for cache key + * - NOTE: Prefixed with '$', will be resetted when .load() is called + * @private + */ +var KEY = { + bubbleBaseLength: "$baseLength", + colorPattern: "__colorPattern__", + dataMinMax: "$dataMinMax", + dataTotalSum: "$dataTotalSum", + dataTotalPerIndex: "$totalPerIndex", + legendItemTextBox: "legendItemTextBox", + radarPoints: "$radarPoints", + setOverOut: "setOverOut", + callOverOutForTouch: "callOverOutForTouch", + textRect: "textRect" +}; +var Cache = /** @class */ (function () { + function Cache() { + this.cache = {}; + } + /** + * Add cache + * @param {string} key Cache key + * @param {*} value Value to be stored + * @param {boolean} isDataType Weather the cache is data typed '{id:'data', id_org: 'data', values: [{x:0, index:0,...}, ...]}' + * @returns {*} Added data value + * @private + */ + Cache.prototype.add = function (key, value, isDataType) { + if (isDataType === void 0) { isDataType = false; } + this.cache[key] = isDataType ? this.cloneTarget(value) : value; + return this.cache[key]; + }; + /** + * Remove cache + * @param {string|Array} key Cache key + * @private + */ + Cache.prototype.remove = function (key) { + var _this = this; + (isString(key) ? [key] : key) + .forEach(function (v) { return delete _this.cache[v]; }); + }; + /** + * Get cahce + * @param {string|Array} key Cache key + * @param {boolean} isDataType Weather the cache is data typed '{id:'data', id_org: 'data', values: [{x:0, index:0,...}, ...]}' + * @returns {*} + * @private + */ + Cache.prototype.get = function (key, isDataType) { + if (isDataType === void 0) { isDataType = false; } + // when is isDataType, key should be string array + if (isDataType && Array.isArray(key)) { + var targets = []; + for (var i = 0, id = void 0; (id = key[i]); i++) { + if (id in this.cache) { + targets.push(this.cloneTarget(this.cache[id])); + } + } + return targets; + } + else { + var value = this.cache[key]; + return isValue(value) ? value : null; + } + }; + /** + * Reset cached data + * @param {boolean} all true: reset all data, false: reset only '$' prefixed key data + * @private + */ + Cache.prototype.reset = function (all) { + var $$ = this; + for (var x in $$.cache) { + // reset the prefixed '$' key(which is internal use data) only. + if (all || /^\$/.test(x)) { + $$.cache[x] = null; + } + } + }; + /** + * Clone data target object + * @param {object} target Data object + * @returns {object} + * @private + */ + // eslint-disable-next-line camelcase + Cache.prototype.cloneTarget = function (target) { + return { + id: target.id, + id_org: target.id_org, + values: target.values.map(function (d) { return ({ x: d.x, value: d.value, id: d.id }); }) + }; + }; + return Cache; +}()); + +var setTimeout$1 = win.setTimeout, clearTimeout$1 = win.clearTimeout; +/** + * Generate resize queue function + * @param {boolean|number} option Resize option + * @returns {Fucntion} + * @private + */ +function generateResize(option) { + var fn = []; + var timeout; + var callResizeFn = function () { + // Delay all resize functions call, to prevent unintended excessive call from resize event + callResizeFn.clear(); + if (option === false) { + requestIdleCallback(function () { + fn.forEach(function (f) { return f(); }); + }, { timeout: 200 }); + } + else { + timeout = setTimeout$1(function () { + fn.forEach(function (f) { return f(); }); + }, isNumber(option) ? option : 200); + } + }; + callResizeFn.clear = function () { + if (timeout) { + clearTimeout$1(timeout); + timeout = null; + } + }; + callResizeFn.add = function (f) { return fn.push(f); }; + callResizeFn.remove = function (f) { return fn.splice(fn.indexOf(f), 1); }; + return callResizeFn; +} +/** + * Generate transition queue function + * @returns {Function} + * @private + */ +function generateWait() { + var transitionsToWait = []; + // 'f' is called as selection.call(f, ...); + var f = function (selection, callback) { + /** + * Check if transition is complete + * @returns {boolean} Whether transition is complete + * @private + */ + function loop() { + var _a; + var done = 0; + for (var i = 0, t = void 0; (t = transitionsToWait[i]); i++) { + if (t === true || ((_a = t.empty) === null || _a === void 0 ? void 0 : _a.call(t))) { + done++; + continue; + } + // when tab isn't visible exit loop + if (isTabVisible() === false) { + done = transitionsToWait.length; + break; + } + try { + t.transition(); + } + catch (e) { + done++; + } + } + return done === transitionsToWait.length; + } + runUntil(function () { + callback === null || callback === void 0 ? void 0 : callback(); + }, loop); + }; + f.add = function (t) { + isArray(t) ? + (transitionsToWait = transitionsToWait.concat(t)) : + transitionsToWait.push(t); + }; + return f; +} + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +// Store blob in memory +var blob = {}; +/** + * Get Object URL + * @param {Function} fn Function to be executed in worker + * @param {Array} depsFn Dependency functions to run given function(fn). + * @returns {string} + * @private + */ +function getObjectURL(fn, depsFn) { + var _a; + var fnString = fn.toString(); + var key = fnString.replace(/(function|[\s\W\n])/g, "").substring(0, 15); + if (!(key in blob)) { + // Web Worker body + blob[key] = new win.Blob([ + "".concat((_a = depsFn === null || depsFn === void 0 ? void 0 : depsFn.map(String).join(";")) !== null && _a !== void 0 ? _a : "", "\n\n\t\t\tself.onmessage=function({data}) {\n\t\t\t\tconst result = (").concat(fnString, ").apply(null, data);\n\t\t\t\tself.postMessage(result);\n\t\t\t};") + ], { + type: "text/javascript" + }); + } + return win.URL.createObjectURL(blob[key]); +} +/** + * Get WebWorker instance + * @param {string} src URL object as string + * @returns {object} WebWorker instance + * @private + */ +function getWorker(src) { + var worker = new win.Worker(src); + // handle error + worker.onerror = function (e) { + // eslint-disable-next-line no-console + console.error ? console.error(e) : console.log(e); + }; + return worker; +} +/** + * Create and run on Web Worker + * @param {boolean} useWorker Use Web Worker + * @param {Function} fn Function to be executed in worker + * @param {Function} callback Callback function to receive result from worker + * @param {Array} depsFn Dependency functions to run given function(fn). + * @returns {object} + * @example + * const worker = runWorker(function(arg) { + * // do some tasks... + * console.log("param:", A(arg)); + * + * return 1234; + * }, function(data) { + * // callback after worker is done + * console.log("result:", data); + * }, + * [function A(){}] + * ); + * + * worker(11111); + * @private + */ +function runWorker(useWorker, fn, callback, depsFn) { + if (useWorker === void 0) { useWorker = true; } + var runFn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var res = fn.apply(void 0, args); + callback(res); + }; + if (win.Worker && useWorker) { + var src_1 = getObjectURL(fn, depsFn); + var worker_1 = getWorker(src_1); + runFn = function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + // trigger worker + worker_1.postMessage(args); + // listen worker + worker_1.onmessage = function (e) { + // release object URL from memory + win.URL.revokeObjectURL(src_1); + return callback(e.data); + }; + // return new Promise((resolve, reject) => { + // worker.onmessage = ({data}) => resolve(data); + // worker.onerror = reject; + // }); + }; + } + return runFn; +} + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/* eslint-disable */ +/***** Functions to be executed on Web Worker ***** + * NOTE: Don't allowed to use + * - arrow function syntax + * - Utils functions + */ +/** + * Convert Columns data + * @param {object} columns + * @returns {Array} + * @private + */ +function columns(columns) { + var newRows = []; + columns.forEach(function (col, i) { + var key = col[0]; + col.forEach(function (v, j) { + if (j > 0) { + if (typeof newRows[j - 1] === "undefined") { + newRows[j - 1] = {}; + } + if (typeof v === "undefined") { + throw new Error("Source data is missing a component at (".concat(i, ", ").concat(j, ")!")); + } + newRows[j - 1][key] = v; + } + }); + }); + return newRows; +} +/** + * Convert Rows data + * @param {object} columns + * @returns {Array} + * @private + */ +function rows(rows) { + var keys = rows[0]; + var newRows = []; + rows.forEach(function (row, i) { + if (i > 0) { + var newRow_1 = {}; + row.forEach(function (v, j) { + if (typeof v === "undefined") { + throw new Error("Source data is missing a component at (".concat(i, ", ").concat(j, ")!")); + } + newRow_1[keys[j]] = v; + }); + newRows.push(newRow_1); + } + }); + return newRows; +} +/** + * Convert JSON data + * @param {object} columns + * @returns {Array} + * @private + */ +function json(json, keysParam) { + var newRows = []; + var targetKeys; + var data; + if (Array.isArray(json)) { + var findValueInJson_1 = function (object, path) { + if (object[path] !== undefined) { + return object[path]; + } + var convertedPath = path.replace(/\[(\w+)\]/g, ".$1"); // convert indexes to properties (replace [] with .) + var pathArray = convertedPath.replace(/^\./, "").split("."); // strip a leading dot + var target = object; + pathArray.some(function (k) { + return !(target = target && k in target ? + target[k] : undefined); + }); + return target; + }; + if (keysParam.x) { + targetKeys = keysParam.value.concat(keysParam.x); + } + else { + targetKeys = keysParam.value; + } + newRows.push(targetKeys); + json.forEach(function (o) { + var newRow = targetKeys.map(function (key) { + // convert undefined to null because undefined data will be removed in convertDataToTargets() + var v = findValueInJson_1(o, key); + if (typeof v === "undefined") { + v = null; + } + return v; + }); + newRows.push(newRow); + }); + data = rows(newRows); + } + else { + Object.keys(json).forEach(function (key) { + var _a; + var tmp = json[key].concat(); + (_a = tmp.unshift) === null || _a === void 0 ? void 0 : _a.call(tmp, key); + newRows.push(tmp); + }); + data = columns(newRows); + } + return data; +} +/***** Functions can't be executed on Web Worker *****/ +/** + * Convert URL data + * @param {string} url Remote URL + * @param {string} mimeType MIME type string: json | csv | tsv + * @param {object} headers Header object + * @param {object} keys Key object + * @param {Function} done Callback function + * @private + */ +function url(url, mimeType, headers, keys, done) { + if (mimeType === void 0) { mimeType = "csv"; } + var req = new XMLHttpRequest(); + var converter = { csv: csv, tsv: tsv, json: json }; + req.open("GET", url); + if (headers) { + Object.keys(headers).forEach(function (key) { + req.setRequestHeader(key, headers[key]); + }); + } + req.onreadystatechange = function () { + if (req.readyState === 4) { + if (req.status === 200) { + var response = req.responseText; + response && done.call(this, converter[mimeType](mimeType === "json" ? JSON.parse(response) : response, keys)); + } + else { + throw new Error("".concat(url, ": Something went wrong loading!")); + } + } + }; + req.send(); +} +/** + * Convert CSV/TSV data + * @param {object} parser Parser object + * @param {object} xsv Data + * @returns {object} + * @private + */ +function convertCsvTsvToData(parser, xsv) { + var rows = parser.rows(xsv); + var d; + if (rows.length === 1) { + d = [{}]; + rows[0].forEach(function (id) { + d[0][id] = null; + }); + } + else { + d = parser.parse(xsv); + } + return d; +} +function csv(xsv) { + return convertCsvTsvToData({ + rows: csvParseRows, + parse: csvParse + }, xsv); +} +function tsv(tsv) { + return convertCsvTsvToData({ + rows: tsvParseRows, + parse: tsvParse + }, tsv); +} + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get data key for JSON + * @param {string|object} keysParam Key params + * @param {object} config Config object + * @returns {string} Data key + * @private + */ +function getDataKeyForJson(keysParam, config) { + var keys = keysParam || (config === null || config === void 0 ? void 0 : config.data_keys); + if (keys === null || keys === void 0 ? void 0 : keys.x) { + config.data_x = keys.x; + } + return keys; +} +/** + * Data convert + * @memberof ChartInternal + * @private + */ +var dataConvert = { + /** + * Convert data according its type + * @param {object} args data object + * @param {Function} [callback] callback for url(XHR) type loading + * @private + */ + convertData: function (args, callback) { + var config = this.config; + var useWorker = config.boost_useWorker; + var data = args; + if (args.bindto) { + data = {}; + ["url", "mimeType", "headers", "keys", "json", "keys", "rows", "columns"] + .forEach(function (v) { + var key = "data_".concat(v); + if (key in args) { + data[v] = args[key]; + } + }); + } + if (data.url && callback) { + url(data.url, data.mimeType, data.headers, getDataKeyForJson(data.keys, config), callback); + } + else if (data.json) { + runWorker(useWorker, json, callback, [columns, rows])(data.json, getDataKeyForJson(data.keys, config)); + } + else if (data.rows) { + runWorker(useWorker, rows, callback)(data.rows); + } + else if (data.columns) { + runWorker(useWorker, columns, callback)(data.columns); + } + else if (args.bindto) { + throw Error("url or json or rows or columns is required."); + } + }, + convertDataToTargets: function (data, appendXs) { + var _this = this; + var $$ = this; + var axis = $$.axis, config = $$.config, state = $$.state; + var chartType = config.data_type; + var isCategorized = false; + var isTimeSeries = false; + var isCustomX = false; + if (axis) { + isCategorized = axis.isCategorized(); + isTimeSeries = axis.isTimeSeries(); + isCustomX = axis.isCustomX(); + } + var dataKeys = Object.keys(data[0] || {}); + var ids = dataKeys.length ? dataKeys.filter($$.isNotX, $$) : []; + var xs = dataKeys.length ? dataKeys.filter($$.isX, $$) : []; + var xsData; + // save x for update data by load when custom x and bb.x API + ids.forEach(function (id) { + var xKey = _this.getXKey(id); + if (isCustomX || isTimeSeries) { + // if included in input data + if (xs.indexOf(xKey) >= 0) { + xsData = ((appendXs && $$.data.xs[id]) || []) + .concat(data.map(function (d) { return d[xKey]; }) + .filter(isValue) + .map(function (rawX, i) { return $$.generateTargetX(rawX, id, i); })); + } + else if (config.data_x) { + // if not included in input data, find from preloaded data of other id's x + xsData = _this.getOtherTargetXs(); + } + else if (notEmpty(config.data_xs)) { + // if not included in input data, find from preloaded data + xsData = $$.getXValuesOfXKey(xKey, $$.data.targets); + } + // MEMO: if no x included, use same x of current will be used + } + else { + xsData = data.map(function (d, i) { return i; }); + } + xsData && (_this.data.xs[id] = xsData); + }); + // check x is defined + ids.forEach(function (id) { + if (!_this.data.xs[id]) { + throw new Error("x is not defined for id = \"".concat(id, "\".")); + } + }); + // convert to target + var targets = ids.map(function (id, index) { + var convertedId = config.data_idConverter.bind($$.api)(id); + var xKey = $$.getXKey(id); + var isCategory = isCustomX && isCategorized; + var hasCategory = isCategory && data.map(function (v) { return v.x; }) + .every(function (v) { return config.axis_x_categories.indexOf(v) > -1; }); + // when .load() with 'append' option is used for indexed axis + // @ts-ignore + var isDataAppend = data.__append__; + var xIndex = xKey === null && isDataAppend ? + $$.api.data.values(id).length : 0; + return { + id: convertedId, + id_org: id, + values: data.map(function (d, i) { + var rawX = d[xKey]; + var value = d[id]; + var x; + value = value !== null && !isNaN(value) && !isObject(value) ? + +value : (isArray(value) || isObject(value) ? value : null); + // use x as categories if custom x and categorized + if ((isCategory || state.hasRadar) && index === 0 && !isUndefined(rawX)) { + if (!hasCategory && index === 0 && i === 0 && !isDataAppend) { + config.axis_x_categories = []; + } + x = config.axis_x_categories.indexOf(rawX); + if (x === -1) { + x = config.axis_x_categories.length; + config.axis_x_categories.push(rawX); + } + } + else { + x = $$.generateTargetX(rawX, id, xIndex + i); + } + // mark as x = undefined if value is undefined and filter to remove after mapped + if (isUndefined(value) || $$.data.xs[id].length <= i) { + x = undefined; + } + return { + x: x, + value: value, + id: convertedId, + index: -1 + }; + }).filter(function (v) { return isDefined(v.x); }) + }; + }); + // finish targets + targets.forEach(function (t) { + var _a; + // sort values by its x + if (config.data_xSort) { + t.values = t.values.sort(function (v1, v2) { + var x1 = v1.x || v1.x === 0 ? v1.x : Infinity; + var x2 = v2.x || v2.x === 0 ? v2.x : Infinity; + return x1 - x2; + }); + } + // indexing each value + t.values.forEach(function (v, i) { return (v.index = i); }); + // this needs to be sorted because its index and value.index is identical + (_a = $$.data.xs[t.id]) === null || _a === void 0 ? void 0 : _a.sort(function (v1, v2) { return v1 - v2; }); + }); + // cache information about values + state.hasNegativeValue = $$.hasNegativeValueInTargets(targets); + state.hasPositiveValue = $$.hasPositiveValueInTargets(targets); + // set target types + if (chartType && $$.isValidChartType(chartType)) { + var targetIds = $$.mapToIds(targets) + .filter(function (id) { return !(id in config.data_types) || !$$.isValidChartType(config.data_types[id]); }); + $$.setTargetType(targetIds, chartType); + } + // cache as original id keyed + targets.forEach(function (d) { return $$.cache.add(d.id_org, d, true); }); + return targets; + } +}; + +var data$1 = { + isX: function (key) { + var $$ = this; + var config = $$.config; + var dataKey = config.data_x && key === config.data_x; + var existValue = notEmpty(config.data_xs) && hasValue(config.data_xs, key); + return dataKey || existValue; + }, + isNotX: function (key) { + return !this.isX(key); + }, + isStackNormalized: function () { + var config = this.config; + return !!(config.data_stack_normalize && config.data_groups.length); + }, + /** + * Check if given id is grouped data or has grouped data + * @param {string} id Data id value + * @returns {boolean} is grouped data or has grouped data + * @private + */ + isGrouped: function (id) { + var groups = this.config.data_groups; + return id ? + groups.some(function (v) { return v.indexOf(id) >= 0 && v.length > 1; }) : + groups.length > 0; + }, + getXKey: function (id) { + var $$ = this; + var config = $$.config; + return config.data_x ? + config.data_x : (notEmpty(config.data_xs) ? config.data_xs[id] : null); + }, + getXValuesOfXKey: function (key, targets) { + var $$ = this; + var ids = targets && notEmpty(targets) ? $$.mapToIds(targets) : []; + var xValues; + ids.forEach(function (id) { + if ($$.getXKey(id) === key) { + xValues = $$.data.xs[id]; + } + }); + return xValues; + }, + /** + * Get index number based on given x Axis value + * @param {Date|number|string} x x Axis to be compared + * @param {Array} basedX x Axis list to be based on + * @returns {number} index number + * @private + */ + getIndexByX: function (x, basedX) { + var $$ = this; + return basedX ? + basedX.indexOf(isString(x) ? x : +x) : + ($$.filterByX($$.data.targets, x)[0] || { index: null }).index; + }, + getXValue: function (id, i) { + var $$ = this; + return id in $$.data.xs && + $$.data.xs[id] && + isValue($$.data.xs[id][i]) ? $$.data.xs[id][i] : i; + }, + getOtherTargetXs: function () { + var $$ = this; + var idsForX = Object.keys($$.data.xs); + return idsForX.length ? $$.data.xs[idsForX[0]] : null; + }, + getOtherTargetX: function (index) { + var xs = this.getOtherTargetXs(); + return xs && index < xs.length ? xs[index] : null; + }, + addXs: function (xs) { + var $$ = this; + var config = $$.config; + Object.keys(xs).forEach(function (id) { + config.data_xs[id] = xs[id]; + }); + }, + isMultipleX: function () { + return notEmpty(this.config.data_xs) || + this.hasType("bubble") || + this.hasType("scatter"); + }, + addName: function (data) { + var $$ = this; + var config = $$.config; + var name; + if (data) { + name = config.data_names[data.id]; + data.name = name !== undefined ? name : data.id; + } + return data; + }, + /** + * Get all values on given index + * @param {number} index Index + * @param {boolean} filterNull Filter nullish value + * @returns {Array} + * @private + */ + getAllValuesOnIndex: function (index, filterNull) { + if (filterNull === void 0) { filterNull = false; } + var $$ = this; + var value = $$.filterTargetsToShow($$.data.targets) + .map(function (t) { return $$.addName($$.getValueOnIndex(t.values, index)); }); + if (filterNull) { + value = value.filter(function (v) { return v && "value" in v && isValue(v.value); }); + } + return value; + }, + getValueOnIndex: function (values, index) { + var valueOnIndex = values.filter(function (v) { return v.index === index; }); + return valueOnIndex.length ? valueOnIndex[0] : null; + }, + updateTargetX: function (targets, x) { + var $$ = this; + targets.forEach(function (t) { + t.values.forEach(function (v, i) { + v.x = $$.generateTargetX(x[i], t.id, i); + }); + $$.data.xs[t.id] = x; + }); + }, + updateTargetXs: function (targets, xs) { + var $$ = this; + targets.forEach(function (t) { + xs[t.id] && $$.updateTargetX([t], xs[t.id]); + }); + }, + generateTargetX: function (rawX, id, index) { + var $$ = this; + var axis = $$.axis; + var x = (axis === null || axis === void 0 ? void 0 : axis.isCategorized()) ? index : (rawX || index); + if (axis === null || axis === void 0 ? void 0 : axis.isTimeSeries()) { + var fn = parseDate.bind($$); + x = rawX ? fn(rawX) : fn($$.getXValue(id, index)); + } + else if ((axis === null || axis === void 0 ? void 0 : axis.isCustomX()) && !(axis === null || axis === void 0 ? void 0 : axis.isCategorized())) { + x = isValue(rawX) ? +rawX : $$.getXValue(id, index); + } + return x; + }, + updateXs: function (values) { + if (values.length) { + this.axis.xs = values.map(function (v) { return v.x; }); + } + }, + getPrevX: function (i) { + var x = this.axis.xs[i - 1]; + return isDefined(x) ? x : null; + }, + getNextX: function (i) { + var x = this.axis.xs[i + 1]; + return isDefined(x) ? x : null; + }, + /** + * Get base value isAreaRangeType + * @param {object} data Data object + * @returns {number} + * @private + */ + getBaseValue: function (data) { + var $$ = this; + var hasAxis = $$.state.hasAxis; + var value = data.value; + // In case of area-range, data is given as: [low, mid, high] or {low, mid, high} + // will take the 'mid' as the base value + if (value && hasAxis) { + if ($$.isAreaRangeType(data)) { + value = $$.getRangedData(data, "mid"); + } + else if ($$.isBubbleZType(data)) { + value = $$.getBubbleZData(value, "y"); + } + } + return value; + }, + /** + * Get min/max value from the data + * @private + * @param {Array} data array data to be evaluated + * @returns {{min: {number}, max: {number}}} + */ + getMinMaxValue: function (data) { + var getBaseValue = this.getBaseValue.bind(this); + var min; + var max; + (data || this.data.targets.map(function (t) { return t.values; })) + .forEach(function (v, i) { + var value = v.map(getBaseValue).filter(isNumber); + min = Math.min.apply(Math, __spreadArray([i ? min : Infinity], value, false)); + max = Math.max.apply(Math, __spreadArray([i ? max : -Infinity], value, false)); + }); + return { min: min, max: max }; + }, + /** + * Get the min/max data + * @private + * @returns {{min: Array, max: Array}} + */ + getMinMaxData: function () { + var $$ = this; + var cacheKey = KEY.dataMinMax; + var minMaxData = $$.cache.get(cacheKey); + if (!minMaxData) { + var data = $$.data.targets.map(function (t) { return t.values; }); + var minMax_1 = $$.getMinMaxValue(data); + var min_1 = []; + var max_1 = []; + data.forEach(function (v) { + var minData = $$.getFilteredDataByValue(v, minMax_1.min); + var maxData = $$.getFilteredDataByValue(v, minMax_1.max); + if (minData.length) { + min_1 = min_1.concat(minData); + } + if (maxData.length) { + max_1 = max_1.concat(maxData); + } + }); + // update the cached data + $$.cache.add(cacheKey, minMaxData = { min: min_1, max: max_1 }); + } + return minMaxData; + }, + /** + * Get sum of data per index + * @private + * @returns {Array} + */ + getTotalPerIndex: function () { + var $$ = this; + var cacheKey = KEY.dataTotalPerIndex; + var sum = $$.cache.get(cacheKey); + if (($$.config.data_groups.length || $$.isStackNormalized()) && !sum) { + sum = []; + $$.data.targets.forEach(function (row) { + row.values.forEach(function (v, i) { + if (!sum[i]) { + sum[i] = 0; + } + sum[i] += isNumber(v.value) ? v.value : 0; + }); + }); + } + return sum; + }, + /** + * Get total data sum + * @param {boolean} subtractHidden Subtract hidden data from total + * @returns {number} + * @private + */ + getTotalDataSum: function (subtractHidden) { + var $$ = this; + var cacheKey = KEY.dataTotalSum; + var total = $$.cache.get(cacheKey); + if (!isNumber(total)) { + var sum = mergeArray($$.data.targets.map(function (t) { return t.values; })) + .map(function (v) { return v.value; }); + total = sum.length ? sum.reduce(function (p, c) { return p + c; }) : 0; + $$.cache.add(cacheKey, total); + } + if (subtractHidden) { + total -= $$.getHiddenTotalDataSum(); + } + return total; + }, + /** + * Get total hidden data sum + * @returns {number} + * @private + */ + getHiddenTotalDataSum: function () { + var $$ = this; + var api = $$.api, hiddenTargetIds = $$.state.hiddenTargetIds; + var total = 0; + if (hiddenTargetIds.length) { + total = api.data.values.bind(api)(hiddenTargetIds) + .reduce(function (p, c) { return p + c; }); + } + return total; + }, + /** + * Get filtered data by value + * @param {object} data Data + * @param {number} value Value to be filtered + * @returns {Array} filtered array data + * @private + */ + getFilteredDataByValue: function (data, value) { + var _this = this; + return data.filter(function (t) { return _this.getBaseValue(t) === value; }); + }, + /** + * Return the max length of the data + * @returns {number} max data length + * @private + */ + getMaxDataCount: function () { + return Math.max.apply(Math, __spreadArray(__spreadArray([], this.data.targets.map(function (t) { return t.values.length; }), false), [0], false)); + }, + getMaxDataCountTarget: function () { + var target = this.filterTargetsToShow() || []; + var length = target.length; + var isInverted = this.config.axis_x_inverted; + if (length > 1) { + target = target.map(function (t) { return t.values; }) + .reduce(function (a, b) { return a.concat(b); }) + .map(function (v) { return v.x; }); + target = sortValue(getUnique(target)) + .map(function (x, index, array) { return ({ x: x, index: isInverted ? array.length - index - 1 : index }); }); + } + else if (length) { + target = target[0].values.concat(); + } + return target; + }, + mapToIds: function (targets) { + return targets.map(function (d) { return d.id; }); + }, + mapToTargetIds: function (ids) { + var $$ = this; + return ids ? (isArray(ids) ? ids.concat() : [ids]) : $$.mapToIds($$.data.targets); + }, + hasTarget: function (targets, id) { + var ids = this.mapToIds(targets); + for (var i = 0, val = void 0; (val = ids[i]); i++) { + if (val === id) { + return true; + } + } + return false; + }, + isTargetToShow: function (targetId) { + return this.state.hiddenTargetIds.indexOf(targetId) < 0; + }, + isLegendToShow: function (targetId) { + return this.state.hiddenLegendIds.indexOf(targetId) < 0; + }, + filterTargetsToShow: function (targets) { + var $$ = this; + return (targets || $$.data.targets).filter(function (t) { return $$.isTargetToShow(t.id); }); + }, + mapTargetsToUniqueXs: function (targets) { + var $$ = this; + var axis = $$.axis; + var xs = []; + if (targets === null || targets === void 0 ? void 0 : targets.length) { + xs = getUnique(mergeArray(targets.map(function (t) { return t.values.map(function (v) { return +v.x; }); }))); + xs = (axis === null || axis === void 0 ? void 0 : axis.isTimeSeries()) ? xs.map(function (x) { return new Date(+x); }) : xs.map(Number); + } + return sortValue(xs); + }, + /** + * Add to the state target Ids + * @param {string} type State's prop name + * @param {Array|string} targetIds Target ids array + * @private + */ + addTargetIds: function (type, targetIds) { + var state = this.state; + var ids = (isArray(targetIds) ? targetIds : [targetIds]); + ids.forEach(function (v) { + state[type].indexOf(v) < 0 && + state[type].push(v); + }); + }, + /** + * Remove from the state target Ids + * @param {string} type State's prop name + * @param {Array|string} targetIds Target ids array + * @private + */ + removeTargetIds: function (type, targetIds) { + var state = this.state; + var ids = (isArray(targetIds) ? targetIds : [targetIds]); + ids.forEach(function (v) { + var index = state[type].indexOf(v); + index >= 0 && state[type].splice(index, 1); + }); + }, + addHiddenTargetIds: function (targetIds) { + this.addTargetIds("hiddenTargetIds", targetIds); + }, + removeHiddenTargetIds: function (targetIds) { + this.removeTargetIds("hiddenTargetIds", targetIds); + }, + addHiddenLegendIds: function (targetIds) { + this.addTargetIds("hiddenLegendIds", targetIds); + }, + removeHiddenLegendIds: function (targetIds) { + this.removeTargetIds("hiddenLegendIds", targetIds); + }, + getValuesAsIdKeyed: function (targets) { + var $$ = this; + var hasAxis = $$.state.hasAxis; + var ys = {}; + var isMultipleX = $$.isMultipleX(); + var xs = isMultipleX ? $$.mapTargetsToUniqueXs(targets) + .map(function (v) { return (isString(v) ? v : +v); }) : null; + targets.forEach(function (t) { + var data = []; + t.values + .filter(function (_a) { + var value = _a.value; + return isValue(value) || value === null; + }) + .forEach(function (v) { + var value = v.value; + // exclude 'volume' value to correct mis domain calculation + if (value !== null && $$.isCandlestickType(v)) { + value = isArray(value) ? value.slice(0, 4) : [value.open, value.high, value.low, value.close]; + } + if (isArray(value)) { + data.push.apply(data, value); + } + else if (isObject(value) && "high" in value) { + data.push.apply(data, Object.values(value)); + } + else if ($$.isBubbleZType(v)) { + data.push(hasAxis && $$.getBubbleZData(value, "y")); + } + else { + if (isMultipleX) { + data[$$.getIndexByX(v.x, xs)] = value; + } + else { + data.push(value); + } + } + }); + ys[t.id] = data; + }); + return ys; + }, + checkValueInTargets: function (targets, checker) { + var ids = Object.keys(targets); + var values; + for (var i = 0; i < ids.length; i++) { + values = targets[ids[i]].values; + for (var j = 0; j < values.length; j++) { + if (checker(values[j].value)) { + return true; + } + } + } + return false; + }, + hasMultiTargets: function () { + return this.filterTargetsToShow().length > 1; + }, + hasNegativeValueInTargets: function (targets) { + return this.checkValueInTargets(targets, function (v) { return v < 0; }); + }, + hasPositiveValueInTargets: function (targets) { + return this.checkValueInTargets(targets, function (v) { return v > 0; }); + }, + /** + * Sort targets data + * Note: For stacked bar, will sort from the total sum of data series, not for each stacked bar + * @param {Array} targetsValue Target value + * @returns {Array} + * @private + */ + orderTargets: function (targetsValue) { + var $$ = this; + var targets = __spreadArray([], targetsValue, true); + var fn = $$.getSortCompareFn(); + fn && targets.sort(fn); + return targets; + }, + /** + * Get data.order compare function + * @param {boolean} isReversed for Arc & Treemap type sort order needs to be reversed + * @returns {Function} compare function + * @private + */ + getSortCompareFn: function (isReversed) { + if (isReversed === void 0) { isReversed = false; } + var $$ = this; + var config = $$.config; + var order = config.data_order; + var orderAsc = /asc/i.test(order); + var orderDesc = /desc/i.test(order); + var fn; + if (orderAsc || orderDesc) { + var reducer_1 = function (p, c) { return p + Math.abs(c.value); }; + fn = function (t1, t2) { + var t1Sum = "values" in t1 ? t1.values.reduce(reducer_1, 0) : t1.value; + var t2Sum = "values" in t2 ? t2.values.reduce(reducer_1, 0) : t2.value; + return isReversed ? + (orderAsc ? t1Sum - t2Sum : t2Sum - t1Sum) : + (orderAsc ? t2Sum - t1Sum : t1Sum - t2Sum); + }; + } + else if (isFunction(order)) { + fn = order.bind($$.api); + } + return fn || null; + }, + filterByX: function (targets, x) { + return mergeArray(targets.map(function (t) { return t.values; })).filter(function (v) { return v.x - x === 0; }); + }, + filterRemoveNull: function (data) { + var _this = this; + return data.filter(function (d) { return isValue(_this.getBaseValue(d)); }); + }, + filterByXDomain: function (targets, xDomain) { + return targets.map(function (t) { return ({ + id: t.id, + id_org: t.id_org, + values: t.values.filter(function (v) { return xDomain[0] <= v.x && v.x <= xDomain[1]; }) + }); }); + }, + hasDataLabel: function () { + var dataLabels = this.config.data_labels; + return (isboolean(dataLabels) && dataLabels) || + (isObjectType(dataLabels) && notEmpty(dataLabels)); + }, + /** + * Get data index from the event coodinates + * @param {Event} event Event object + * @returns {number} + */ + getDataIndexFromEvent: function (event) { + var $$ = this; + var config = $$.config, _a = $$.state, hasRadar = _a.hasRadar, inputType = _a.inputType, _b = _a.eventReceiver, coords = _b.coords, rect = _b.rect; + var index; + if (hasRadar) { + var target = event.target; + // in case of multilined axis text + if (/tspan/i.test(target.tagName)) { + target = target.parentNode; + } + var d = select(target).datum(); + index = d && Object.keys(d).length === 1 ? d.index : undefined; + } + else { + var isRotated = config.axis_rotated; + // get data based on the mouse coords + var e = inputType === "touch" && event.changedTouches ? event.changedTouches[0] : event; + index = findIndex(coords, isRotated ? e.clientY - rect.top : e.clientX - rect.left, 0, coords.length - 1, isRotated); + } + return index; + }, + getDataLabelLength: function (min, max, key) { + var $$ = this; + var lengths = [0, 0]; + var paddingCoef = 1.3; + $$.$el.chart.select("svg").selectAll(".dummy") + .data([min, max]) + .enter() + .append("text") + .text(function (d) { return $$.dataLabelFormat(d.id)(d); }) + .each(function (d, i) { + lengths[i] = this.getBoundingClientRect()[key] * paddingCoef; + }) + .remove(); + return lengths; + }, + isNoneArc: function (d) { + return this.hasTarget(this.data.targets, d.id); + }, + isArc: function (d) { + return "data" in d && this.hasTarget(this.data.targets, d.data.id); + }, + findSameXOfValues: function (values, index) { + var targetX = values[index].x; + var sames = []; + var i; + for (i = index - 1; i >= 0; i--) { + if (targetX !== values[i].x) { + break; + } + sames.push(values[i]); + } + for (i = index; i < values.length; i++) { + if (targetX !== values[i].x) { + break; + } + sames.push(values[i]); + } + return sames; + }, + findClosestFromTargets: function (targets, pos) { + var $$ = this; + var candidates = targets.map(function (target) { return $$.findClosest(target.values, pos); }); // map to array of closest points of each target + // decide closest point and return + return $$.findClosest(candidates, pos); + }, + findClosest: function (values, pos) { + var $$ = this; + var main = $$.$el.main; + var data = values.filter(function (v) { return v && isValue(v.value); }); + var minDist; + var closest; + // find mouseovering bar/candlestick + // https://github.com/naver/billboard.js/issues/2434 + data + .filter(function (v) { return $$.isBarType(v.id) || $$.isCandlestickType(v.id); }) + .forEach(function (v) { + var selector = $$.isBarType(v.id) ? + ".".concat($BAR.chartBar, ".").concat($COMMON.target).concat($$.getTargetSelectorSuffix(v.id), " .").concat($BAR.bar, "-").concat(v.index) : + ".".concat($CANDLESTICK.chartCandlestick, ".").concat($COMMON.target).concat($$.getTargetSelectorSuffix(v.id), " .").concat($CANDLESTICK.candlestick, "-").concat(v.index, " path"); + if (!closest && $$.isWithinBar(main.select(selector).node())) { + closest = v; + } + }); + // find closest point from non-bar/candlestick + data + .filter(function (v) { return !$$.isBarType(v.id) && !$$.isCandlestickType(v.id); }) + .forEach(function (v) { + var d = $$.dist(v, pos); + minDist = $$.getPointSensitivity(v); + if (d < minDist) { + minDist = d; + closest = v; + } + }); + return closest; + }, + dist: function (data, pos) { + var $$ = this; + var isRotated = $$.config.axis_rotated, scale = $$.scale; + var xIndex = +isRotated; // true: 1, false: 0 + var yIndex = +!isRotated; // true: 0, false: 1 + var y = $$.circleY(data, data.index); + var x = (scale.zoom || scale.x)(data.x); + return Math.sqrt(Math.pow(x - pos[xIndex], 2) + Math.pow(y - pos[yIndex], 2)); + }, + /** + * Convert data for step type + * @param {Array} values Object data values + * @returns {Array} + * @private + */ + convertValuesToStep: function (values) { + var $$ = this; + var axis = $$.axis, config = $$.config; + var stepType = config.line_step_type; + var isCategorized = axis ? axis.isCategorized() : false; + var converted = isArray(values) ? values.concat() : [values]; + if (!(isCategorized || /step\-(after|before)/.test(stepType))) { + return values; + } + // when all datas are null, return empty array + // https://github.com/naver/billboard.js/issues/3124 + if (converted.length) { + // insert & append cloning first/last value to be fully rendered covering on each gap sides + var head = converted[0]; + var tail = converted[converted.length - 1]; + var id = head.id; + var x = head.x; + // insert head + converted.unshift({ x: --x, value: head.value, id: id }); + isCategorized && stepType === "step-after" && + converted.unshift({ x: --x, value: head.value, id: id }); + // append tail + x = tail.x; + converted.push({ x: ++x, value: tail.value, id: id }); + isCategorized && stepType === "step-before" && + converted.push({ x: ++x, value: tail.value, id: id }); + } + return converted; + }, + convertValuesToRange: function (values) { + var converted = isArray(values) ? values.concat() : [values]; + var ranges = []; + converted.forEach(function (range) { + var x = range.x, id = range.id; + ranges.push({ + x: x, + id: id, + value: range.value[0] + }); + ranges.push({ + x: x, + id: id, + value: range.value[2] + }); + }); + return ranges; + }, + updateDataAttributes: function (name, attrs) { + var $$ = this; + var config = $$.config; + var current = config["data_".concat(name)]; + if (isUndefined(attrs)) { + return current; + } + Object.keys(attrs).forEach(function (id) { + current[id] = attrs[id]; + }); + $$.redraw({ withLegend: true }); + return current; + }, + getRangedData: function (d, key, type) { + if (key === void 0) { key = ""; } + if (type === void 0) { type = "areaRange"; } + var value = d === null || d === void 0 ? void 0 : d.value; + if (isArray(value)) { + // @ts-ignore + var index = { + areaRange: ["high", "mid", "low"], + candlestick: ["open", "high", "low", "close", "volume"] + }[type].indexOf(key); + return index >= 0 && value ? value[index] : undefined; + } + else if (value) { + return value[key]; + } + return value; + }, + /** + * Set ratio for grouped data + * @param {Array} data Data array + * @private + */ + setRatioForGroupedData: function (data) { + var $$ = this; + var config = $$.config; + // calculate ratio if grouped data exists + if (config.data_groups.length && data.some(function (d) { return $$.isGrouped(d.id); })) { + var setter_1 = function (d) { return $$.getRatio("index", d, true); }; + data.forEach(function (v) { + "values" in v ? v.values.forEach(setter_1) : setter_1(v); + }); + } + }, + /** + * Get ratio value + * @param {string} type Ratio for given type + * @param {object} d Data value object + * @param {boolean} asPercent Convert the return as percent or not + * @returns {number} Ratio value + * @private + */ + getRatio: function (type, d, asPercent) { + if (asPercent === void 0) { asPercent = false; } + var $$ = this; + var config = $$.config, state = $$.state; + var api = $$.api; + var ratio = 0; + if (d && api.data.shown().length) { + ratio = d.ratio || d.value; + if (type === "arc") { + // if has padAngle set, calculate rate based on value + if ($$.pie.padAngle()()) { + ratio = d.value / $$.getTotalDataSum(true); + // otherwise, based on the rendered angle value + } + else { + var gaugeArcLength = config.gauge_fullCircle ? + $$.getArcLength() : $$.getGaugeStartAngle() * -2; + var arcLength = $$.hasType("gauge") ? gaugeArcLength : Math.PI * 2; + ratio = (d.endAngle - d.startAngle) / arcLength; + } + } + else if (type === "index") { + var dataValues = api.data.values.bind(api); + var total = this.getTotalPerIndex(); + if (state.hiddenTargetIds.length) { + var hiddenSum_1 = dataValues(state.hiddenTargetIds, false); + if (hiddenSum_1.length) { + hiddenSum_1 = hiddenSum_1 + .reduce(function (acc, curr) { return acc.map(function (v, i) { return (isNumber(v) ? v : 0) + curr[i]; }); }); + total = total.map(function (v, i) { return v - hiddenSum_1[i]; }); + } + } + var divisor = total[d.index]; + d.ratio = isNumber(d.value) && total && divisor ? + d.value / divisor : 0; + ratio = d.ratio; + } + else if (type === "radar") { + ratio = (parseFloat(String(Math.max(d.value, 0))) / state.current.dataMax) * config.radar_size_ratio; + } + else if (type === "bar") { + var yScale = $$.getYScaleById.bind($$)(d.id); + var max = yScale.domain().reduce(function (a, c) { return c - a; }); + // when all data are 0, return 0 + ratio = max === 0 ? 0 : Math.abs(d.value) / max; + } + else if (type === "treemap") { + ratio /= $$.getTotalDataSum(true); + } + } + return asPercent && ratio ? ratio * 100 : ratio; + }, + /** + * Sort data index to be aligned with x axis. + * @param {Array} tickValues Tick array values + * @private + */ + updateDataIndexByX: function (tickValues) { + var $$ = this; + var tickValueMap = tickValues.reduce(function (out, tick, index) { + out[Number(tick.x)] = index; + return out; + }, {}); + $$.data.targets.forEach(function (t) { + t.values.forEach(function (value, valueIndex) { + var index = tickValueMap[Number(value.x)]; + if (index === undefined) { + index = valueIndex; + } + value.index = index; + }); + }); + }, + /** + * Determine if bubble has dimension data + * @param {object|Array} d data value + * @returns {boolean} + * @private + */ + isBubbleZType: function (d) { + var $$ = this; + return $$.isBubbleType(d) && ((isObject(d.value) && ("z" in d.value || "y" in d.value)) || + (isArray(d.value) && d.value.length >= 2)); + }, + /** + * Determine if bar has ranged data + * @param {Array} d data value + * @returns {boolean} + * @private + */ + isBarRangeType: function (d) { + var $$ = this; + var value = d.value; + return $$.isBarType(d) && isArray(value) && value.length >= 2 && value.every(function (v) { return isNumber(v); }); + }, + /** + * Get data object by id + * @param {string} id data id + * @returns {object} + * @private + */ + getDataById: function (id) { + var _a; + var d = this.cache.get(id) || this.api.data(id); + return (_a = d === null || d === void 0 ? void 0 : d[0]) !== null && _a !== void 0 ? _a : d; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Call done callback with resize after transition + * @param {Function} fn Callback function + * @param {boolean} resizeAfter Weather to resize chart after the load + * @private + */ +function callDone(fn, resizeAfter) { + if (resizeAfter === void 0) { resizeAfter = false; } + var $$ = this; + var api = $$.api; + resizeAfter && $$.api.flush(true); + fn === null || fn === void 0 ? void 0 : fn.call(api); +} +var dataLoad = { + load: function (rawTargets, args) { + var $$ = this; + var data = $$.data; + var append = args.append; + var targets = rawTargets; + if (targets) { + // filter loading targets if needed + if (args.filter) { + targets = targets.filter(args.filter); + } + // set type if args.types || args.type specified + if (args.type || args.types) { + targets.forEach(function (t) { + var _a; + var type = ((_a = args.types) === null || _a === void 0 ? void 0 : _a[t.id]) || args.type; + $$.setTargetType(t.id, type); + }); + } + // Update/Add data + data.targets.forEach(function (d) { + for (var i = 0; i < targets.length; i++) { + if (d.id === targets[i].id) { + d.values = append ? + d.values.concat(targets[i].values) : targets[i].values; + targets.splice(i, 1); + break; + } + } + }); + data.targets = data.targets.concat(targets); // add remained + } + // Set targets + $$.updateTargets(data.targets); + // Redraw with new targets + $$.redraw({ + withUpdateOrgXDomain: true, + withUpdateXDomain: true, + withLegend: true + }); + // Update current state chart type and elements list after redraw + $$.updateTypesElements(); + callDone.call($$, args.done, args.resizeAfter); + }, + loadFromArgs: function (args) { + var $$ = this; + // prevent load when chart is already destroyed + if (!$$.config) { + return; + } + // reset internally cached data + $$.cache.reset(); + $$.convertData(args, function (d) { + var data = args.data || d; + args.append && (data.__append__ = true); + data && $$.load($$.convertDataToTargets(data), args); + }); + }, + unload: function (rawTargetIds, customDoneCb) { + var $$ = this; + var state = $$.state, $el = $$.$el, $T = $$.$T; + var done = customDoneCb; + var targetIds = rawTargetIds; + // reset internally cached data + $$.cache.reset(); + if (!done) { + done = function () { }; + } + // filter existing target + targetIds = targetIds.filter(function (id) { return $$.hasTarget($$.data.targets, id); }); + // If no target, call done and return + if (!targetIds || targetIds.length === 0) { + done(); + return; + } + var targets = $el.svg.selectAll(targetIds.map(function (id) { return $$.selectorTarget(id); })); + $T(targets) + .style("opacity", "0") + .remove() + .call(endall, done); + targetIds.forEach(function (id) { + // Reset fadein for future load + state.withoutFadeIn[id] = false; + // Remove target's elements + if ($el.legend) { + $el.legend.selectAll(".".concat($LEGEND.legendItem).concat($$.getTargetSelectorSuffix(id))).remove(); + } + // Remove target + $$.data.targets = $$.data.targets.filter(function (t) { return t.id !== id; }); + }); + // since treemap uses different data types, it needs to be transformed + state.hasTreemap && $$.updateTargetsForTreemap($$.data.targets); + // Update current state chart type and elements list after redraw + $$.updateTypesElements(); + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var interaction = { + /** + * Expand data shape/point + * @param {number} index Index number + * @param {string} id Data id + * @param {boolean} reset Reset expand state + * @private + */ + setExpand: function (index, id, reset) { + var $$ = this; + var config = $$.config, circle = $$.$el.circle; + circle && config.point_focus_expand_enabled && + $$.expandCircles(index, id, reset); + // bar, candlestick + $$.expandBarTypeShapes(true, index, id, reset); + }, + /** + * Expand/Unexpand bar type shapes + * @param {boolean} expand Expand or unexpand + * @param {number} i Shape index + * @param {string} id Data id + * @param {boolean} reset Reset expand style + * @private + */ + expandBarTypeShapes: function (expand, i, id, reset) { + if (expand === void 0) { expand = true; } + var $$ = this; + ["bar", "candlestick"] + .filter(function (v) { return $$.$el[v]; }) + .forEach(function (v) { + reset && $$.$el[v].classed($COMMON.EXPANDED, false); + $$.getShapeByIndex(v, i, id).classed($COMMON.EXPANDED, expand); + }); + }, + /** + * Handle data.onover/out callback options + * @param {boolean} isOver Over or not + * @param {number|object} d data object + * @private + */ + setOverOut: function (isOver, d) { + var $$ = this; + var config = $$.config, _a = $$.state, hasRadar = _a.hasRadar, hasTreemap = _a.hasTreemap, main = $$.$el.main; + var isArcTreemap = isObject(d); + // Call event handler + if (isArcTreemap || d !== -1) { + var callback_1 = config[isOver ? "data_onover" : "data_onout"].bind($$.api); + config.color_onover && $$.setOverColor(isOver, d, isArcTreemap); + if (isArcTreemap && "id") { + var selector = hasTreemap ? $TREEMAP.treemap : $ARC.arc; + callback_1(d, main.select(".".concat(selector).concat($$.getTargetSelectorSuffix(d.id))).node()); + } + else if (!config.tooltip_grouped) { + var last_1 = $$.cache.get(KEY.setOverOut) || []; + // select based on the index + var shapesAtIndex = main.selectAll(".".concat($SHAPE.shape, "-").concat(d)) + .filter(function (d) { + return $$.isWithinShape(this, d); + }); + // filter if has new selection + var shape = shapesAtIndex.filter(function () { + var _this = this; + return last_1.every(function (v) { return v !== _this; }); + }); + // call onout callback + if (!isOver || shapesAtIndex.empty() || (last_1.length === shape.size() && shape.nodes().every((function (v, i) { return v !== last_1[i]; })))) { + while (last_1.length) { + var target = last_1.pop(); + config.data_onout.bind($$.api)(select(target).datum(), target); + } + } + // call onover callback + shape.each(function () { + if (isOver) { + callback_1(select(this).datum(), this); + last_1.push(this); + } + }); + $$.cache.add(KEY.setOverOut, last_1); + } + else { + if (isOver) { + hasRadar && $$.isPointFocusOnly() ? + $$.showCircleFocus($$.getAllValuesOnIndex(d, true)) : + $$.setExpand(d, null, true); + } + !$$.isMultipleX() && main.selectAll(".".concat($SHAPE.shape, "-").concat(d)) + .each(function (d) { + callback_1(d, this); + }); + } + } + }, + /** + * Call data.onover/out callback for touch event + * @param {number|object} d target index or data object for Arc type + * @private + */ + callOverOutForTouch: function (d) { + var $$ = this; + var last = $$.cache.get(KEY.callOverOutForTouch); + if (isObject(d) && last ? d.id !== last.id : (d !== last)) { + (last || isNumber(last)) && $$.setOverOut(false, last); + (d || isNumber(d)) && $$.setOverOut(true, d); + $$.cache.add(KEY.callOverOutForTouch, d); + } + }, + /** + * Return draggable selection function + * @returns {Function} + * @private + */ + getDraggableSelection: function () { + var $$ = this; + var config = $$.config, state = $$.state; + return config.interaction_enabled && config.data_selection_draggable && $$.drag ? + drag$1() + .on("drag", function (event) { + state.event = event; + $$.drag(getPointer(event, this)); + }) + .on("start", function (event) { + state.event = event; + $$.dragstart(getPointer(event, this)); + }) + .on("end", function (event) { + state.event = event; + $$.dragend(); + }) : function () { }; + }, + /** + * Dispatch a mouse event. + * @private + * @param {string} type event type + * @param {number} index Index of eventRect + * @param {Array} mouse x and y coordinate value + */ + dispatchEvent: function (type, index, mouse) { + var _a, _b; + var $$ = this; + var config = $$.config, _c = $$.state, eventReceiver = _c.eventReceiver, hasAxis = _c.hasAxis, hasRadar = _c.hasRadar, hasTreemap = _c.hasTreemap, _d = $$.$el, eventRect = _d.eventRect, radar = _d.radar, treemap = _d.treemap; + var element = (_b = ((hasTreemap && eventReceiver.rect) || + (hasRadar && radar.axes.select(".".concat($AXIS.axis, "-").concat(index, " text"))) || (eventRect || ((_a = $$.getArcElementByIdOrIndex) === null || _a === void 0 ? void 0 : _a.call($$, index))))) === null || _b === void 0 ? void 0 : _b.node(); + if (element) { + var isMultipleX = $$.isMultipleX(); + var isRotated = config.axis_rotated; + var _e = element.getBoundingClientRect(), width = _e.width, left = _e.left, top_1 = _e.top; + if (hasAxis && !hasRadar && !isMultipleX) { + var coords = eventReceiver.coords[index]; + if (coords) { + width = coords.w; + left += coords.x; + top_1 += coords.y; + } + else { + width = 0; + left = 0; + top_1 = 0; + } + } + var x = left + (mouse ? mouse[0] : 0) + (isMultipleX || isRotated ? 0 : (width / 2)); + // value 4, is to adjust coordinate value set from: scale.ts - updateScales(): $$.getResettedPadding(1) + var y = top_1 + (mouse ? mouse[1] : 0) + (isRotated ? 4 : 0); + var params = { + screenX: x, + screenY: y, + clientX: x, + clientY: y + }; + emulateEvent[/^(mouse|click)/.test(type) ? "mouse" : "touch"](hasTreemap ? treemap.node() : element, type, params); + } + }, + setDragStatus: function (isDragging) { + this.state.dragging = isDragging; + }, + /** + * Unbind zoom events + * @private + */ + unbindZoomEvent: function () { + var $$ = this; + var _a = $$.$el, eventRect = _a.eventRect, zoomResetBtn = _a.zoomResetBtn; + eventRect === null || eventRect === void 0 ? void 0 : eventRect.on(".zoom wheel.zoom .drag", null); + zoomResetBtn === null || zoomResetBtn === void 0 ? void 0 : zoomResetBtn.on("click", null).style("display", "none"); + }, + /** + * Unbind all attached events + * @private + */ + unbindAllEvents: function () { + var _a; + var $$ = this; + var _b = $$.$el, arcs = _b.arcs, eventRect = _b.eventRect, legend = _b.legend, region = _b.region, svg = _b.svg, treemap = _b.treemap, brush = $$.brush; + var list = [ + "wheel", + "click", + "mouseover", + "mousemove", + "mouseout", + "touchstart", + "touchmove", + "touchend", + "touchstart.eventRect", + "touchmove.eventRect", + "touchend.eventRect", + ".brush", + ".drag", + ".zoom", + "wheel.zoom", + "dblclick.zoom" + ].join(" "); + // detach all possible event types + [svg, eventRect, region === null || region === void 0 ? void 0 : region.list, brush === null || brush === void 0 ? void 0 : brush.getSelection(), arcs === null || arcs === void 0 ? void 0 : arcs.selectAll("path"), legend === null || legend === void 0 ? void 0 : legend.selectAll("g"), treemap] + .forEach(function (v) { return v === null || v === void 0 ? void 0 : v.on(list, null); }); + (_a = $$.unbindZoomEvent) === null || _a === void 0 ? void 0 : _a.call($$); + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var classModule = { + generateClass: function (prefix, targetId) { + return " ".concat(prefix, " ").concat(prefix + this.getTargetSelectorSuffix(targetId)); + }, + /** + * Get class string + * @param {string} type Shape type + * @param {boolean} withShape Get with shape prefix + * @returns {string} Class string + * @private + */ + getClass: function (type, withShape) { + var _this = this; + var isPlural = /s$/.test(type); + var useIdKey = /^(area|arc|line|treemap)s?$/.test(type); + var key = isPlural ? "id" : "index"; + return function (d) { + var data = d.data || d; + var result = (withShape ? _this.generateClass(CLASS[isPlural ? "shapes" : "shape"], data[key]) : "") + _this.generateClass(CLASS[type], data[useIdKey ? "id" : key]); + return result.trim(); + }; + }, + /** + * Get chart class string + * @param {string} type Shape type + * @returns {string} Class string + * @private + */ + getChartClass: function (type) { + var _this = this; + return function (d) { return CLASS["chart".concat(type)] + _this.classTarget((d.data ? d.data : d).id); }; + }, + generateExtraLineClass: function () { + var $$ = this; + var classes = $$.config.line_classes || []; + var ids = []; + return function (d) { + var _a; + var id = d.id || ((_a = d.data) === null || _a === void 0 ? void 0 : _a.id) || d; + if (ids.indexOf(id) < 0) { + ids.push(id); + } + return classes[ids.indexOf(id) % classes.length]; + }; + }, + classRegion: function (d, i) { + return "".concat(this.generateClass(CLASS.region, i), " ").concat("class" in d ? d.class : ""); + }, + classTarget: function (id) { + var additionalClassSuffix = this.config.data_classes[id]; + var additionalClass = ""; + if (additionalClassSuffix) { + additionalClass = " ".concat(CLASS.target, "-").concat(additionalClassSuffix); + } + return this.generateClass(CLASS.target, id) + additionalClass; + }, + classFocus: function (d) { + return this.classFocused(d) + this.classDefocused(d); + }, + classFocused: function (d) { + return " ".concat(this.state.focusedTargetIds.indexOf(d.id) >= 0 ? CLASS.focused : ""); + }, + classDefocused: function (d) { + return " ".concat(this.state.defocusedTargetIds.indexOf(d.id) >= 0 ? CLASS.defocused : ""); + }, + getTargetSelectorSuffix: function (targetId) { + var targetStr = targetId || targetId === 0 ? "-".concat(targetId) : ""; + return targetStr.replace(/([\s?!@#$%^&*()_=+,.<>'":;\[\]\/|~`{}\\])/g, "-"); + }, + selectorTarget: function (id, prefix, postfix) { + if (prefix === void 0) { prefix = ""; } + if (postfix === void 0) { postfix = ""; } + var target = this.getTargetSelectorSuffix(id); + // select target & circle + return "".concat(prefix, ".").concat(CLASS.target + target, " ").concat(postfix, ", ").concat(prefix, ".").concat(CLASS.circles + target, " ").concat(postfix); + }, + selectorTargets: function (idsValue, prefix) { + var _this = this; + var ids = idsValue || []; + return ids.length ? + ids.map(function (id) { return _this.selectorTarget(id, prefix); }) : null; + }, + selectorLegend: function (id) { + return ".".concat(CLASS.legendItem + this.getTargetSelectorSuffix(id)); + }, + selectorLegends: function (ids) { + var _this = this; + return (ids === null || ids === void 0 ? void 0 : ids.length) ? + ids.map(function (id) { return _this.selectorLegend(id); }) : null; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var category = { + /** + * Category Name + * @param {number} i Index number + * @returns {string} category Name + * @private + */ + categoryName: function (i) { + var _a; + var axis_x_categories = this.config.axis_x_categories; + return (_a = axis_x_categories === null || axis_x_categories === void 0 ? void 0 : axis_x_categories[i]) !== null && _a !== void 0 ? _a : i; + }, +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Set pattern's background color + * (it adds a element to simulate bg-color) + * @param {SVGPatternElement} pattern SVG pattern element + * @param {string} color Color string + * @param {string} id ID to be set + * @returns {{id: string, node: SVGPatternElement}} + * @private + */ +var colorizePattern = function (pattern, color, id) { + var node = select(pattern.cloneNode(true)); + node + .attr("id", id) + .insert("rect", ":first-child") + .attr("width", node.attr("width")) + .attr("height", node.attr("height")) + .style("fill", color); + return { + id: id, + node: node.node() + }; +}; +/** + * Get color pattern from CSS file + * CSS should be defined as: background-image: url("#00c73c;#fa7171; ..."); + * @param {d3Selection} element Chart element + * @returns {Array} + * @private + */ +function getColorFromCss(element) { + var cacheKey = KEY.colorPattern; + var body = doc.body; + var pattern = body[cacheKey]; + if (!pattern) { + var delimiter = ";"; + var content = element + .classed($COLOR.colorPattern, true) + .style("background-image"); + element.classed($COLOR.colorPattern, false); + if (content.indexOf(delimiter) > -1) { + pattern = content + .replace(/url[^#]*|["'()]|(\s|%20)/g, "") + .split(delimiter) + .map(function (v) { return v.trim().replace(/[\"'\s]/g, ""); }) + .filter(Boolean); + body[cacheKey] = pattern; + } + } + return pattern; +} +// Replacement of d3.schemeCategory10. +// Contained differently depend on d3 version: v4(d3-scale), v5(d3-scale-chromatic) +var schemeCategory10 = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728", "#9467bd", "#8c564b", "#e377c2", "#7f7f7f", "#bcbd22", "#17becf"]; +var color = { + generateColor: function () { + var $$ = this; + var $el = $$.$el, config = $$.config; + var colors = config.data_colors; + var callback = config.data_color; + var ids = []; + var pattern = notEmpty(config.color_pattern) ? config.color_pattern : + scaleOrdinal(getColorFromCss($el.chart) || schemeCategory10).range(); + var originalColorPattern = pattern; + if (isFunction(config.color_tiles)) { + var tiles_1 = config.color_tiles.bind($$.api)(); + // Add background color to patterns + var colorizedPatterns = pattern.map(function (p, index) { + var color = p.replace(/[#\(\)\s,]/g, ""); + var id = "".concat($$.state.datetimeId, "-pattern-").concat(color, "-").concat(index); + return colorizePattern(tiles_1[index % tiles_1.length], p, id); + }); + pattern = colorizedPatterns.map(function (p) { return "url(#".concat(p.id, ")"); }); + $$.patterns = colorizedPatterns; + } + return function (d) { + var _a; + var id = d.id || + ((_a = d.data) === null || _a === void 0 ? void 0 : _a.id) || + d; + var isLine = $$.isTypeOf(id, ["line", "spline", "step"]) || !config.data_types[id]; + var color; + // if callback function is provided + if (isFunction(colors[id])) { + color = colors[id].bind($$.api)(d); + // if specified, choose that color + } + else if (colors[id]) { + color = colors[id]; + // if not specified, choose from pattern + } + else { + if (ids.indexOf(id) < 0) { + ids.push(id); + } + color = isLine ? originalColorPattern[ids.indexOf(id) % originalColorPattern.length] : + pattern[ids.indexOf(id) % pattern.length]; + colors[id] = color; + } + return isFunction(callback) ? + callback.bind($$.api)(color, d) : color; + }; + }, + generateLevelColor: function () { + var $$ = this; + var config = $$.config; + var colors = config.color_pattern; + var threshold = config.color_threshold; + var asValue = threshold.unit === "value"; + var max = threshold.max || 100; + var values = threshold.values && + threshold.values.length ? threshold.values : []; + return notEmpty(threshold) ? function (value) { + var v = asValue ? value : (value * 100 / max); + var color = colors[colors.length - 1]; + for (var i = 0, l = values.length; i < l; i++) { + if (v <= values[i]) { + color = colors[i]; + break; + } + } + return color; + } : null; + }, + /** + * Append data backgound color filter definition + * @param {string} color Color string + * @private + */ + generateDataLabelBackgroundColorFilter: function (color) { + var $$ = this; + var $el = $$.$el, config = $$.config, state = $$.state; + var backgroundColors = color || config.data_labels_backgroundColors; + if (backgroundColors) { + var ids = []; + if (isString(backgroundColors)) { + ids.push(""); + } + else if (isObject(backgroundColors)) { + ids = Object.keys(backgroundColors); + } + ids.forEach(function (v) { + var id = "".concat(state.datetimeId, "-labels-bg").concat($$.getTargetSelectorSuffix(v)).concat(color ? $$.getTargetSelectorSuffix(color) : ""); + $el.defs.append("filter") + .attr("x", "0") + .attr("y", "0") + .attr("width", "1") + .attr("height", "1") + .attr("id", id) + .html("")); + }); + } + }, + /** + * Get data gradient color url + * @param {string} id Data id + * @returns {string} + * @private + */ + getGradienColortUrl: function (id) { + return "url(#".concat(this.state.datetimeId, "-gradient").concat(this.getTargetSelectorSuffix(id), ")"); + }, + /** + * Update linear/radial gradient definition + * - linear: area & bar only + * - radial: type which has data points only + * @private + */ + updateLinearGradient: function () { + var $$ = this; + var config = $$.config, targets = $$.data.targets, datetimeId = $$.state.datetimeId, defs = $$.$el.defs; + targets.forEach(function (d) { + var id = "".concat(datetimeId, "-gradient").concat($$.getTargetSelectorSuffix(d.id)); + var radialGradient = $$.hasPointType() && config.point_radialGradient; + var supportedType = ($$.isAreaType(d) && "area") || ($$.isBarType(d) && "bar"); + if ((radialGradient || supportedType) && defs.select("#".concat(id)).empty()) { + var color_1 = $$.color(d); + var gradient_1 = { + defs: null, + stops: [] + }; + if (radialGradient) { + var _a = radialGradient.cx, cx = _a === void 0 ? 0.3 : _a, _b = radialGradient.cy, cy = _b === void 0 ? 0.3 : _b, _c = radialGradient.r, r = _c === void 0 ? 0.7 : _c, _d = radialGradient.stops, stops = _d === void 0 ? [[0.1, color_1, 0], [0.9, color_1, 1]] : _d; + gradient_1.stops = stops; + gradient_1.defs = defs.append("radialGradient") + .attr("id", "".concat(id)) + .attr("cx", cx) + .attr("cy", cy) + .attr("r", r); + } + else { + var isRotated = config.axis_rotated; + var _e = config["".concat(supportedType, "_linearGradient")], _f = _e.x, x = _f === void 0 ? isRotated ? [1, 0] : [0, 0] : _f, _g = _e.y, y = _g === void 0 ? isRotated ? [0, 0] : [0, 1] : _g, _h = _e.stops, stops = _h === void 0 ? [[0, color_1, 1], [1, color_1, 0]] : _h; + gradient_1.stops = stops; + gradient_1.defs = defs.append("linearGradient") + .attr("id", "".concat(id)) + .attr("x1", x[0]) + .attr("x2", x[1]) + .attr("y1", y[0]) + .attr("y2", y[1]); + } + gradient_1.stops.forEach(function (v) { + var offset = v[0], stopColor = v[1], stopOpacity = v[2]; + var colorValue = isFunction(stopColor) ? stopColor.bind($$.api)(d.id) : stopColor; + gradient_1.defs && gradient_1.defs.append("stop") + .attr("offset", offset) + .attr("stop-color", colorValue || color_1) + .attr("stop-opacity", stopOpacity); + }); + } + }); + }, + /** + * Set the data over color. + * When is out, will restate in its previous color value + * @param {boolean} isOver true: set overed color, false: restore + * @param {number|object} d target index or data object for Arc type + * @private + */ + setOverColor: function (isOver, d) { + var $$ = this; + var config = $$.config, main = $$.$el.main; + var onover = config.color_onover; + var color = isOver ? onover : $$.color; + if (isObject(color)) { + color = function (_a) { + var id = _a.id; + return (id in onover ? onover[id] : $$.color(id)); + }; + } + else if (isString(color)) { + color = function () { return onover; }; + } + else if (isFunction(onover)) { + color = color.bind($$.api); + } + main.selectAll(isObject(d) ? + // when is Arc type + ".".concat($ARC.arc).concat($$.getTargetSelectorSuffix(d.id)) : + ".".concat($SHAPE.shape, "-").concat(d)).style("fill", color); + } +}; + +var domain = { + getYDomainMinMax: function (targets, type) { + var $$ = this; + var axis = $$.axis, config = $$.config; + var isMin = type === "min"; + var dataGroups = config.data_groups; + var ids = $$.mapToIds(targets); + var ys = $$.getValuesAsIdKeyed(targets); + if (dataGroups.length > 0) { + var hasValue_1 = $$["has".concat(isMin ? "Negative" : "Positive", "ValueInTargets")](targets); + dataGroups.forEach(function (groupIds) { + // Determine baseId + var idsInGroup = groupIds + .filter(function (v) { return ids.indexOf(v) >= 0; }); + if (idsInGroup.length) { + var baseId_1 = idsInGroup[0]; + var baseAxisId_1 = axis.getId(baseId_1); + // Initialize base value. Set to 0 if not match with the condition + if (hasValue_1 && ys[baseId_1]) { + ys[baseId_1] = ys[baseId_1] + .map(function (v) { return ((isMin ? v < 0 : v > 0) ? v : 0); }); + } + idsInGroup + .filter(function (v, i) { return i > 0; }) + .forEach(function (id) { + if (ys[id]) { + var axisId_1 = axis.getId(id); + ys[id].forEach(function (v, i) { + var val = +v; + var meetCondition = isMin ? val > 0 : val < 0; + if (axisId_1 === baseAxisId_1 && !(hasValue_1 && meetCondition)) { + ys[baseId_1][i] += val; + } + }); + } + }); + } + }); + } + return getMinMax$1(type, Object.keys(ys).map(function (key) { return getMinMax$1(type, ys[key]); })); + }, + /** + * Check if hidden targets bound to the given axis id + * @param {string} id ID to be checked + * @returns {boolean} + * @private + */ + isHiddenTargetWithYDomain: function (id) { + var $$ = this; + return $$.state.hiddenTargetIds + .some(function (v) { return $$.axis.getId(v) === id; }); + }, + getYDomain: function (targets, axisId, xDomain) { + var $$ = this; + var axis = $$.axis, config = $$.config, scale = $$.scale; + var pfx = "axis_".concat(axisId); + if ($$.isStackNormalized()) { + return [0, 100]; + } + var isLog = (scale === null || scale === void 0 ? void 0 : scale[axisId]) && scale[axisId].type === "log"; + var targetsByAxisId = targets.filter(function (t) { return axis.getId(t.id) === axisId; }); + var yTargets = xDomain ? $$.filterByXDomain(targetsByAxisId, xDomain) : targetsByAxisId; + if (yTargets.length === 0) { // use domain of the other axis if target of axisId is none + if ($$.isHiddenTargetWithYDomain(axisId)) { + return scale[axisId].domain(); + } + else { + return axisId === "y2" ? + scale.y.domain() : + // When all data bounds to y2, y Axis domain is called prior y2. + // So, it needs to call to get y2 domain here + $$.getYDomain(targets, "y2", xDomain); + } + } + var yMin = config["".concat(pfx, "_min")]; + var yMax = config["".concat(pfx, "_max")]; + var center = config["".concat(pfx, "_center")]; + var isInverted = config["".concat(pfx, "_inverted")]; + var showHorizontalDataLabel = $$.hasDataLabel() && config.axis_rotated; + var showVerticalDataLabel = $$.hasDataLabel() && !config.axis_rotated; + var yDomainMin = $$.getYDomainMinMax(yTargets, "min"); + var yDomainMax = $$.getYDomainMinMax(yTargets, "max"); + var isZeroBased = __spreadArray([TYPE.BAR, TYPE.BUBBLE, TYPE.SCATTER], TYPE_BY_CATEGORY.Line, true).some(function (v) { + var type = v.indexOf("area") > -1 ? "area" : v; + return $$.hasType(v, yTargets, true) && config["".concat(type, "_zerobased")]; + }); + // MEMO: avoid inverting domain unexpectedly + yDomainMin = isValue(yMin) ? yMin : (isValue(yMax) ? (yDomainMin <= yMax ? yDomainMin : yMax - 10) : yDomainMin); + yDomainMax = isValue(yMax) ? yMax : (isValue(yMin) ? (yMin <= yDomainMax ? yDomainMax : yMin + 10) : yDomainMax); + if (isNaN(yDomainMin)) { // set minimum to zero when not number + yDomainMin = 0; + } + if (isNaN(yDomainMax)) { // set maximum to have same value as yDomainMin + yDomainMax = yDomainMin; + } + if (yDomainMin === yDomainMax) { + yDomainMin < 0 ? yDomainMax = 0 : yDomainMin = 0; + } + var isAllPositive = yDomainMin >= 0 && yDomainMax >= 0; + var isAllNegative = yDomainMin <= 0 && yDomainMax <= 0; + // Cancel zerobased if axis_*_min / axis_*_max specified + if ((isValue(yMin) && isAllPositive) || (isValue(yMax) && isAllNegative)) { + isZeroBased = false; + } + // Bar/Area chart should be 0-based if all positive|negative + if (isZeroBased) { + isAllPositive && (yDomainMin = 0); + isAllNegative && (yDomainMax = 0); + } + var domainLength = Math.abs(yDomainMax - yDomainMin); + var padding = { top: domainLength * 0.1, bottom: domainLength * 0.1 }; + if (isDefined(center)) { + var yDomainAbs = Math.max(Math.abs(yDomainMin), Math.abs(yDomainMax)); + yDomainMax = center + yDomainAbs; + yDomainMin = center - yDomainAbs; + } + // add padding for data label + if (showHorizontalDataLabel) { + var diff_1 = diffDomain(scale.y.range()); + var ratio_1 = $$.getDataLabelLength(yDomainMin, yDomainMax, "width") + .map(function (v) { return v / diff_1; }); + ["bottom", "top"].forEach(function (v, i) { + padding[v] += domainLength * (ratio_1[i] / (1 - ratio_1[0] - ratio_1[1])); + }); + } + else if (showVerticalDataLabel) { + var lengths_1 = $$.getDataLabelLength(yDomainMin, yDomainMax, "height"); + ["bottom", "top"].forEach(function (v, i) { + padding[v] += $$.convertPixelToScale("y", lengths_1[i], domainLength); + }); + } + padding = $$.getResettedPadding(padding); + // if padding is set, the domain will be updated relative the current domain value + // ex) $$.height=300, padding.top=150, domainLength=4 --> domain=6 + var p = config["".concat(pfx, "_padding")]; + if (notEmpty(p)) { + ["bottom", "top"].forEach(function (v) { + padding[v] = axis.getPadding(p, v, padding[v], domainLength); + }); + } + // Bar/Area chart should be 0-based if all positive|negative + if (isZeroBased) { + isAllPositive && (padding.bottom = yDomainMin); + isAllNegative && (padding.top = -yDomainMax); + } + var domain = isLog ? [yDomainMin, yDomainMax].map(function (v) { return (v < 0 ? 0 : v); }) : + [yDomainMin - padding.bottom, yDomainMax + padding.top]; + return isInverted ? domain.reverse() : domain; + }, + getXDomainMinMax: function (targets, type) { + var _a; + var $$ = this; + var configValue = $$.config["axis_x_".concat(type)]; + var dataValue = getMinMax$1(type, targets.map(function (t) { return getMinMax$1(type, t.values.map(function (v) { return v.x; })); })); + var value = isObject(configValue) ? configValue.value : configValue; + value = isDefined(value) && ((_a = $$.axis) === null || _a === void 0 ? void 0 : _a.isTimeSeries()) ? parseDate.bind(this)(value) : value; + if (isObject(configValue) && configValue.fit && ((type === "min" && value < dataValue) || (type === "max" && value > dataValue))) { + value = undefined; + } + return isDefined(value) ? value : dataValue; + }, + /** + * Get x Axis padding + * @param {Array} domain x Axis domain + * @param {number} tickCount Tick count + * @returns {object} Padding object values with 'left' & 'right' key + * @private + */ + getXDomainPadding: function (domain, tickCount) { + var $$ = this; + var axis = $$.axis, config = $$.config; + var padding = config.axis_x_padding; + var isTimeSeriesTickCount = axis.isTimeSeries() && tickCount; + var diff = diffDomain(domain); + var defaultValue; + // determine default padding value + if (axis.isCategorized() || isTimeSeriesTickCount) { + defaultValue = 0; + } + else if ($$.hasType("bar")) { + var maxDataCount = $$.getMaxDataCount(); + defaultValue = maxDataCount > 1 ? (diff / (maxDataCount - 1)) / 2 : 0.5; + } + else { + defaultValue = $$.getResettedPadding(diff * 0.01); + } + var _a = isNumber(padding) ? + { left: padding, right: padding } : padding, _b = _a.left, left = _b === void 0 ? defaultValue : _b, _c = _a.right, right = _c === void 0 ? defaultValue : _c; + // when the unit is pixel, convert pixels to axis scale value + if (padding.unit === "px") { + var domainLength = Math.abs(diff + (diff * 0.2)); + left = axis.getPadding(padding, "left", defaultValue, domainLength); + right = axis.getPadding(padding, "right", defaultValue, domainLength); + } + else { + var range = diff + left + right; + if (isTimeSeriesTickCount && range) { + var relativeTickWidth = (diff / tickCount) / range; + left = left / range / relativeTickWidth; + right = right / range / relativeTickWidth; + } + } + return { left: left, right: right }; + }, + /** + * Get x Axis domain + * @param {Array} targets targets + * @returns {Array} x Axis domain + * @private + */ + getXDomain: function (targets) { + var $$ = this; + var axis = $$.axis, config = $$.config, x = $$.scale.x; + var isInverted = config.axis_x_inverted; + var domain = [ + $$.getXDomainMinMax(targets, "min"), + $$.getXDomainMinMax(targets, "max") + ]; + var _a = domain[0], min = _a === void 0 ? 0 : _a, _b = domain[1], max = _b === void 0 ? 0 : _b; + if (x.type !== "log") { + var isCategorized = axis.isCategorized(); + var isTimeSeries = axis.isTimeSeries(); + var padding = $$.getXDomainPadding(domain); + var firstX = domain[0], lastX = domain[1]; + // show center of x domain if min and max are the same + if ((firstX - lastX) === 0 && !isCategorized) { + if (isTimeSeries) { + firstX = new Date(firstX.getTime() * 0.5); + lastX = new Date(lastX.getTime() * 1.5); + } + else { + firstX = firstX === 0 ? 1 : (firstX * 0.5); + lastX = lastX === 0 ? -1 : (lastX * 1.5); + } + } + if (firstX || firstX === 0) { + min = isTimeSeries ? new Date(firstX.getTime() - padding.left) : firstX - padding.left; + } + if (lastX || lastX === 0) { + max = isTimeSeries ? new Date(lastX.getTime() + padding.right) : lastX + padding.right; + } + } + return isInverted ? [max, min] : [min, max]; + }, + updateXDomain: function (targets, withUpdateXDomain, withUpdateOrgXDomain, withTrim, domain) { + var _a; + var $$ = this; + var config = $$.config, org = $$.org, _b = $$.scale, x = _b.x, subX = _b.subX; + var zoomEnabled = config.zoom_enabled; + if (withUpdateOrgXDomain) { + x.domain(domain || sortValue($$.getXDomain(targets), !config.axis_x_inverted)); + org.xDomain = x.domain(); + // zoomEnabled && $$.zoom.updateScaleExtent(); + subX.domain(x.domain()); + (_a = $$.brush) === null || _a === void 0 ? void 0 : _a.scale(subX); + } + if (withUpdateXDomain) { + var domainValue = domain || (!$$.brush || brushEmpty($$)) ? + org.xDomain : getBrushSelection($$).map(subX.invert); + x.domain(domainValue); + // zoomEnabled && $$.zoom.updateScaleExtent(); + } + if (withUpdateOrgXDomain || withUpdateXDomain) { + zoomEnabled && $$.zoom.updateScaleExtent(); + } + // Trim domain when too big by zoom mousemove event + withTrim && x.domain($$.trimXDomain(x.orgDomain())); + return x.domain(); + }, + /** + * Trim x domain when given domain surpasses the range + * @param {Array} domain Domain value + * @returns {Array} Trimed domain if given domain is out of range + * @private + */ + trimXDomain: function (domain) { + var $$ = this; + var isInverted = $$.config.axis_x_inverted; + var zoomDomain = $$.getZoomDomain(); + var min = zoomDomain[0], max = zoomDomain[1]; + if (isInverted ? domain[0] >= min : domain[0] <= min) { + domain[1] = +domain[1] + (min - domain[0]); + domain[0] = min; + } + if (isInverted ? domain[1] <= max : domain[1] >= max) { + domain[0] = +domain[0] - (domain[1] - max); + domain[1] = max; + } + return domain; + }, + /** + * Get subchart/zoom domain + * @param {string} type "subX" or "zoom" + * @param {boolean} getCurrent Get current domain if true + * @returns {Array} zoom domain + * @private + */ + getZoomDomain: function (type, getCurrent) { + if (type === void 0) { type = "zoom"; } + if (getCurrent === void 0) { getCurrent = false; } + var $$ = this; + var config = $$.config, scale = $$.scale, org = $$.org; + var _a = getCurrent && scale[type] ? scale[type].domain() : org.xDomain, min = _a[0], max = _a[1]; + if (type === "zoom") { + if (isDefined(config.zoom_x_min)) { + min = getMinMax$1("min", [min, config.zoom_x_min]); + } + if (isDefined(config.zoom_x_max)) { + max = getMinMax$1("max", [max, config.zoom_x_max]); + } + } + return [min, max]; + }, + /** + * Converts pixels to axis' scale values + * @param {string} type Axis type + * @param {number} pixels Pixels + * @param {number} domainLength Domain length + * @returns {number} + * @private + */ + convertPixelToScale: function (type, pixels, domainLength) { + var $$ = this; + var config = $$.config, state = $$.state; + var isRotated = config.axis_rotated; + var length; + if (type === "x") { + length = isRotated ? "height" : "width"; + } + else { + length = isRotated ? "width" : "height"; + } + return domainLength * (pixels / state[length]); + }, + /** + * Check if the given domain is within subchart/zoom range + * @param {Array} domain Target domain value + * @param {Array} current Current subchart/zoom domain value + * @param {Array} range subchart/zoom range value + * @returns {boolean} + * @private + */ + withinRange: function (domain, current, range) { + var $$ = this; + var isInverted = $$.config.axis_x_inverted; + var _a = range, min = _a[0], max = _a[1]; + if (Array.isArray(domain)) { + var target = __spreadArray([], domain, true); + isInverted && target.reverse(); + if (target[0] < target[1]) { + return domain.every(function (v, i) { return (i === 0 ? (isInverted ? +v <= min : +v >= min) : (isInverted ? +v >= max : +v <= max)) && !(domain.every(function (v, i) { return v === current[i]; })); }); + } + } + return false; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get formatted + * @param {object} $$ Context + * @param {string} typeValue Axis type + * @param {number} v Value to be formatted + * @returns {number | string} + * @private + */ +function getFormat($$, typeValue, v) { + var config = $$.config; + var type = "axis_".concat(typeValue, "_tick_format"); + var format = config[type] ? + config[type] : $$.defaultValueFormat; + return format.call($$.api, v); +} +var format = { + yFormat: function (v) { + return getFormat(this, "y", v); + }, + y2Format: function (v) { + return getFormat(this, "y2", v); + }, + /** + * Get default value format function + * @returns {Function} formatter function + * @private + */ + getDefaultValueFormat: function () { + var $$ = this; + var defaultArcValueFormat = $$.defaultArcValueFormat, yFormat = $$.yFormat, y2Format = $$.y2Format; + var hasArc = $$.hasArcType(null, ["gauge", "polar", "radar"]); + return function (v, ratio, id) { + var format = hasArc ? defaultArcValueFormat : ($$.axis && $$.axis.getId(id) === "y2" ? y2Format : yFormat); + return format.call($$, v, ratio); + }; + }, + defaultValueFormat: function (v) { + return isValue(v) ? +v : ""; + }, + defaultArcValueFormat: function (v, ratio) { + return "".concat((ratio * 100).toFixed(1), "%"); + }, + defaultPolarValueFormat: function (v) { + return "".concat(v); + }, + dataLabelFormat: function (targetId) { + var $$ = this; + var dataLabels = $$.config.data_labels; + var defaultFormat = function (v) { return (isValue(v) ? +v : ""); }; + var format = defaultFormat; + // find format according to axis id + if (isFunction(dataLabels.format)) { + format = dataLabels.format; + } + else if (isObjectType(dataLabels.format)) { + if (dataLabels.format[targetId]) { + format = dataLabels.format[targetId] === true ? + defaultFormat : dataLabels.format[targetId]; + } + else { + format = function () { return ""; }; + } + } + return format.bind($$.api); + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get color string for given data id + * @param {string} id Data id + * @returns {string} Color string + * @private + */ +function getLegendColor(id) { + var $$ = this; + var data = $$.getDataById(id); + var color = $$.levelColor ? + $$.levelColor(data.values[0].value) : + $$.color(data); + return color; +} +var legend$1 = { + /** + * Initialize the legend. + * @private + */ + initLegend: function () { + var $$ = this; + var config = $$.config, $el = $$.$el; + $$.legendItemTextBox = {}; + $$.state.legendHasRendered = false; + if (config.legend_show) { + if (!config.legend_contents_bindto) { + $el.legend = $$.$el.svg.append("g") + .classed($LEGEND.legend, true) + .attr("transform", $$.getTranslate("legend")); + } + // MEMO: call here to update legend box and translate for all + // MEMO: translate will be updated by this, so transform not needed in updateLegend() + $$.updateLegend(); + } + else { + $$.state.hiddenLegendIds = $$.mapToIds($$.data.targets); + } + }, + /** + * Update legend element + * @param {Array} targetIds ID's of target + * @param {object} options withTransform : Whether to use the transform property / withTransitionForTransform: Whether transition is used when using the transform property / withTransition : whether or not to transition. + * @param {object} transitions Return value of the generateTransitions + * @private + */ + updateLegend: function (targetIds, options, transitions) { + var _a; + var $$ = this; + var config = $$.config, state = $$.state, scale = $$.scale, $el = $$.$el; + var optionz = options || { + withTransform: false, + withTransitionForTransform: false, + withTransition: false + }; + optionz.withTransition = getOption(optionz, "withTransition", true); + optionz.withTransitionForTransform = getOption(optionz, "withTransitionForTransform", true); + if (config.legend_contents_bindto && config.legend_contents_template) { + $$.updateLegendTemplate(); + } + else if (!state.hasTreemap) { + $$.updateLegendElement(targetIds || $$.mapToIds($$.data.targets), optionz, transitions); + } + // toggle legend state + (_a = $el.legend) === null || _a === void 0 ? void 0 : _a.selectAll(".".concat($LEGEND.legendItem)).classed($LEGEND.legendItemHidden, function (id) { + var hide = !$$.isTargetToShow(id); + if (hide) { + this.style.opacity = null; + } + return hide; + }); + // Update size and scale + $$.updateScales(false, !scale.zoom); + $$.updateSvgSize(); + // Update g positions + $$.transformAll(optionz.withTransitionForTransform, transitions); + state.legendHasRendered = true; + }, + /** + * Update legend using template option + * @private + */ + updateLegendTemplate: function () { + var $$ = this; + var config = $$.config, $el = $$.$el; + var wrapper = select(config.legend_contents_bindto); + var template = config.legend_contents_template; + if (!wrapper.empty()) { + var targets = $$.mapToIds($$.data.targets); + var ids_1 = []; + var html_1 = ""; + targets.forEach(function (v) { + var content = isFunction(template) ? + template.bind($$.api)(v, $$.color(v), $$.api.data(v)[0].values) : + tplProcess(template, { + COLOR: $$.color(v), + TITLE: v + }); + if (content) { + ids_1.push(v); + html_1 += content; + } + }); + var legendItem = wrapper.html(html_1) + .selectAll(function () { return this.childNodes; }) + .data(ids_1); + $$.setLegendItem(legendItem); + $el.legend = wrapper; + } + }, + /** + * Update the size of the legend. + * @param {Obejct} size Size object + * @private + */ + updateSizeForLegend: function (size) { + var $$ = this; + var config = $$.config, _a = $$.state, isLegendTop = _a.isLegendTop, isLegendLeft = _a.isLegendLeft, isLegendRight = _a.isLegendRight, isLegendInset = _a.isLegendInset, current = _a.current; + var width = size.width, height = size.height; + var insetLegendPosition = { + top: isLegendTop ? + $$.getCurrentPaddingByDirection("top") + config.legend_inset_y + 5.5 : + current.height - height - $$.getCurrentPaddingByDirection("bottom") - config.legend_inset_y, + left: isLegendLeft ? + $$.getCurrentPaddingByDirection("left") + config.legend_inset_x + 0.5 : + current.width - width - $$.getCurrentPaddingByDirection("right") - config.legend_inset_x + 0.5 + }; + $$.state.margin3 = { + top: isLegendRight ? + 0 : isLegendInset ? insetLegendPosition.top : current.height - height, + right: NaN, + bottom: 0, + left: isLegendRight ? + current.width - width : isLegendInset ? insetLegendPosition.left : 0 + }; + }, + /** + * Transform Legend + * @param {boolean} withTransition whether or not to transition. + * @private + */ + transformLegend: function (withTransition) { + var $$ = this; + var legend = $$.$el.legend, $T = $$.$T; + $T(legend, withTransition) + .attr("transform", $$.getTranslate("legend")); + }, + /** + * Update the legend step + * @param {number} step Step value + * @private + */ + updateLegendStep: function (step) { + this.state.legendStep = step; + }, + /** + * Update legend item width + * @param {number} width Width value + * @private + */ + updateLegendItemWidth: function (width) { + this.state.legendItemWidth = width; + }, + /** + * Update legend item height + * @param {number} height Height value + * @private + */ + updateLegendItemHeight: function (height) { + this.state.legendItemHeight = height; + }, + /** + * Update legend item color + * @param {string} id Corresponding data ID value + * @param {string} color Color value + * @private + */ + updateLegendItemColor: function (id, color) { + var legend = this.$el.legend; + if (legend) { + legend.select(".".concat($LEGEND.legendItem, "-").concat(id, " line")) + .style("stroke", color); + } + }, + /** + * Get the width of the legend + * @returns {number} width + * @private + */ + getLegendWidth: function () { + var $$ = this; + var _a = $$.state, width = _a.current.width, isLegendRight = _a.isLegendRight, isLegendInset = _a.isLegendInset, legendItemWidth = _a.legendItemWidth, legendStep = _a.legendStep; + return $$.config.legend_show ? (isLegendRight || isLegendInset ? + legendItemWidth * (legendStep + 1) : width) : 0; + }, + /** + * Get the height of the legend + * @returns {number} height + * @private + */ + getLegendHeight: function () { + var _a; + var $$ = this; + var _b = $$.state, current = _b.current, isLegendRight = _b.isLegendRight, legendItemHeight = _b.legendItemHeight, legendStep = _b.legendStep; + var isFitPadding = ((_a = $$.config.padding) === null || _a === void 0 ? void 0 : _a.mode) === "fit"; + return $$.config.legend_show ? (isLegendRight ? + current.height : (isFitPadding ? 10 : Math.max(20, legendItemHeight)) * (legendStep + 1)) : 0; + }, + /** + * Get the opacity of the legend that is unfocused + * @param {d3.selection} legendItem Legend item node + * @returns {string|null} opacity + * @private + */ + opacityForUnfocusedLegend: function (legendItem) { + return legendItem.classed($LEGEND.legendItemHidden) ? null : "0.3"; + }, + /** + * Toggles the focus of the legend + * @param {Array} targetIds ID's of target + * @param {boolean} focus whether or not to focus. + * @private + */ + toggleFocusLegend: function (targetIds, focus) { + var $$ = this; + var legend = $$.$el.legend, $T = $$.$T; + var targetIdz = $$.mapToTargetIds(targetIds); + legend && $T(legend.selectAll(".".concat($LEGEND.legendItem)) + .filter(function (id) { return targetIdz.indexOf(id) >= 0; }) + .classed($FOCUS.legendItemFocused, focus)) + .style("opacity", function () { + return focus ? null : + $$.opacityForUnfocusedLegend.call($$, select(this)); + }); + }, + /** + * Revert the legend to its default state + * @private + */ + revertLegend: function () { + var $$ = this; + var legend = $$.$el.legend, $T = $$.$T; + legend && $T(legend.selectAll(".".concat($LEGEND.legendItem)) + .classed($FOCUS.legendItemFocused, false)) + .style("opacity", null); + }, + /** + * Shows the legend + * @param {Array} targetIds ID's of target + * @private + */ + showLegend: function (targetIds) { + var $$ = this; + var config = $$.config, $el = $$.$el, $T = $$.$T; + if (!config.legend_show) { + config.legend_show = true; + $el.legend ? + $el.legend.style("visibility", null) : + $$.initLegend(); + !$$.state.legendHasRendered && $$.updateLegend(); + } + $$.removeHiddenLegendIds(targetIds); + $T($el.legend.selectAll($$.selectorLegends(targetIds)) + .style("visibility", null)).style("opacity", null); + }, + /** + * Hide the legend + * @param {Array} targetIds ID's of target + * @private + */ + hideLegend: function (targetIds) { + var $$ = this; + var config = $$.config, legend = $$.$el.legend; + if (config.legend_show && isEmpty(targetIds)) { + config.legend_show = false; + legend.style("visibility", "hidden"); + } + $$.addHiddenLegendIds(targetIds); + legend.selectAll($$.selectorLegends(targetIds)) + .style("opacity", "0") + .style("visibility", "hidden"); + }, + /** + * Get legend item textbox dimension + * @param {string} id Data ID + * @param {HTMLElement|d3.selection} textElement Text node element + * @returns {object} Bounding rect + * @private + */ + getLegendItemTextBox: function (id, textElement) { + var $$ = this; + var cache = $$.cache, state = $$.state; + var data; + // do not prefix w/'$', to not be resetted cache in .load() call + var cacheKey = KEY.legendItemTextBox; + if (id) { + data = (!state.redrawing && cache.get(cacheKey)) || {}; + if (!data[id]) { + data[id] = $$.getTextRect(textElement, $LEGEND.legendItem); + cache.add(cacheKey, data); + } + data = data[id]; + } + return data; + }, + /** + * Set legend item style & bind events + * @param {d3.selection} item Item node + * @private + */ + setLegendItem: function (item) { + var $$ = this; + var $el = $$.$el, api = $$.api, config = $$.config, state = $$.state; + var isTouch = state.inputType === "touch"; + var hasGauge = $$.hasType("gauge"); + var useCssRule = config.boost_useCssRule; + var interaction = config.legend_item_interaction; + item + .attr("class", function (id) { + var node = select(this); + var itemClass = (!node.empty() && node.attr("class")) || ""; + return itemClass + $$.generateClass($LEGEND.legendItem, id); + }) + .style("visibility", function (id) { return ($$.isLegendToShow(id) ? null : "hidden"); }); + if (config.interaction_enabled) { + if (useCssRule) { + [ + [".".concat($LEGEND.legendItem), "cursor:pointer"], + [".".concat($LEGEND.legendItem, " text"), "pointer-events:none"], + [".".concat($LEGEND.legendItemPoint, " text"), "pointer-events:none"], + [".".concat($LEGEND.legendItemTile), "pointer-events:none"], + [".".concat($LEGEND.legendItemEvent), "fill-opacity:0"] + ].forEach(function (v) { + var selector = v[0], props = v[1]; + $$.setCssRule(false, selector, [props])($el.legend); + }); + } + item + .on(interaction.dblclick ? "dblclick" : "click", interaction || isFunction(config.legend_item_onclick) ? + function (event, id) { + if (!callFn(config.legend_item_onclick, api, id)) { + var altKey = event.altKey, target = event.target, type = event.type; + if (type === "dblclick" || altKey) { + // when focused legend is clicked(with altKey or double clicked), reset all hiding. + if (state.hiddenTargetIds.length && + target.parentNode.getAttribute("class").indexOf($LEGEND.legendItemHidden) === -1) { + api.show(); + } + else { + api.hide(); + api.show(id); + } + } + else { + api.toggle(id); + select(this) + .classed($FOCUS.legendItemFocused, false); + } + } + isTouch && $$.hideTooltip(); + } : null); + !isTouch && item + .on("mouseout", interaction || isFunction(config.legend_item_onout) ? + function (event, id) { + if (!callFn(config.legend_item_onout, api, id)) { + select(this).classed($FOCUS.legendItemFocused, false); + if (hasGauge) { + $$.undoMarkOverlapped($$, ".".concat($GAUGE.gaugeValue)); + } + $$.api.revert(); + } + } : null) + .on("mouseover", interaction || isFunction(config.legend_item_onover) ? + function (event, id) { + if (!callFn(config.legend_item_onover, api, id)) { + select(this).classed($FOCUS.legendItemFocused, true); + if (hasGauge) { + $$.markOverlapped(id, $$, ".".concat($GAUGE.gaugeValue)); + } + if (!state.transiting && $$.isTargetToShow(id)) { + api.focus(id); + } + } + } : null); + // set cursor when has some interaction + !item.empty() && item.on("click mouseout mouseover") && + item.style("cursor", $$.getStylePropValue("pointer")); + } + }, + /** + * Update the legend + * @param {Array} targetIds ID's of target + * @param {object} options withTransform : Whether to use the transform property / withTransitionForTransform: Whether transition is used when using the transform property / withTransition : whether or not to transition. + * @private + */ + updateLegendElement: function (targetIds, options) { + var $$ = this; + var config = $$.config, state = $$.state, legend = $$.$el.legend, $T = $$.$T; + var legendType = config.legend_item_tile_type; + var isRectangle = legendType !== "circle"; + var legendItemR = config.legend_item_tile_r; + var itemTileSize = { + width: isRectangle ? config.legend_item_tile_width : legendItemR * 2, + height: isRectangle ? config.legend_item_tile_height : legendItemR * 2 + }; + var dimension = { + padding: { + top: 4, + right: 10 + }, + max: { + width: 0, + height: 0 + }, + posMin: 10, + step: 0, + tileWidth: itemTileSize.width + 5, + totalLength: 0 + }; + var sizes = { + offsets: {}, + widths: {}, + heights: {}, + margins: [0], + steps: {} + }; + var xForLegend; + var yForLegend; + var background; + // Skip elements when their name is set to null + var targetIdz = targetIds + .filter(function (id) { return !isDefined(config.data_names[id]) || config.data_names[id] !== null; }); + var withTransition = options.withTransition; + var updatePositions = $$.getUpdateLegendPositions(targetIdz, dimension, sizes); + if (state.isLegendInset) { + dimension.step = config.legend_inset_step ? config.legend_inset_step : targetIdz.length; + $$.updateLegendStep(dimension.step); + } + if (state.isLegendRight) { + xForLegend = function (id) { return dimension.max.width * sizes.steps[id]; }; + yForLegend = function (id) { return sizes.margins[sizes.steps[id]] + sizes.offsets[id]; }; + } + else if (state.isLegendInset) { + xForLegend = function (id) { return dimension.max.width * sizes.steps[id] + 10; }; + yForLegend = function (id) { return sizes.margins[sizes.steps[id]] + sizes.offsets[id]; }; + } + else { + xForLegend = function (id) { return sizes.margins[sizes.steps[id]] + sizes.offsets[id]; }; + yForLegend = function (id) { return dimension.max.height * sizes.steps[id]; }; + } + var posFn = { + xText: function (id, i) { return xForLegend(id, i) + 4 + itemTileSize.width; }, + xRect: function (id, i) { return xForLegend(id, i); }, + x1Tile: function (id, i) { return xForLegend(id, i) - 2; }, + x2Tile: function (id, i) { return xForLegend(id, i) - 2 + itemTileSize.width; }, + yText: function (id, i) { return yForLegend(id, i) + 9; }, + yRect: function (id, i) { return yForLegend(id, i) - 5; }, + yTile: function (id, i) { return yForLegend(id, i) + 4; } + }; + $$.generateLegendItem(targetIdz, itemTileSize, updatePositions, posFn); + // Set background for inset legend + background = legend.select(".".concat($LEGEND.legendBackground, " rect")); + if (state.isLegendInset && dimension.max.width > 0 && background.size() === 0) { + background = legend.insert("g", ".".concat($LEGEND.legendItem)) + .attr("class", $LEGEND.legendBackground) + .append("rect"); + } + var texts = legend.selectAll("text") + .data(targetIdz) + .text(function (id) { return (isDefined(config.data_names[id]) ? config.data_names[id] : id); }) // MEMO: needed for update + .each(function (id, i) { + updatePositions(this, id, i); + }); + $T(texts, withTransition) + .attr("x", posFn.xText) + .attr("y", posFn.yText); + var rects = legend.selectAll("rect.".concat($LEGEND.legendItemEvent)) + .data(targetIdz); + $T(rects, withTransition) + .attr("width", function (id) { return sizes.widths[id]; }) + .attr("height", function (id) { return sizes.heights[id]; }) + .attr("x", posFn.xRect) + .attr("y", posFn.yRect); + // update legend items position + $$.updateLegendItemPos(targetIdz, withTransition, posFn); + if (background) { + $T(background, withTransition) + .attr("height", $$.getLegendHeight() - 12) + .attr("width", dimension.max.width * (dimension.step + 1) + 10); + } + // Update all to reflect change of legend + $$.updateLegendItemWidth(dimension.max.width); + $$.updateLegendItemHeight(dimension.max.height); + $$.updateLegendStep(dimension.step); + }, + /** + * Get position update function + * @param {Array} targetIdz Data ids + * @param {object} dimension Dimension object + * @param {object} sizes Size object + * @returns {Function} Update position function + * @private + */ + getUpdateLegendPositions: function (targetIdz, dimension, sizes) { + var $$ = this; + var config = $$.config, state = $$.state; + var isLegendRightOrInset = state.isLegendRight || state.isLegendInset; + return function (textElement, id, index) { + var reset = index === 0; + var isLast = index === targetIdz.length - 1; + var box = $$.getLegendItemTextBox(id, textElement); + var itemWidth = box.width + dimension.tileWidth + + (isLast && !isLegendRightOrInset ? 0 : dimension.padding.right) + config.legend_padding; + var itemHeight = box.height + dimension.padding.top; + var itemLength = isLegendRightOrInset ? itemHeight : itemWidth; + var areaLength = isLegendRightOrInset ? $$.getLegendHeight() : $$.getLegendWidth(); + var margin; + // MEMO: care about condifion of step, totalLength + var updateValues = function (id2, withoutStep) { + if (!withoutStep) { + margin = (areaLength - dimension.totalLength - itemLength) / 2; + if (margin < dimension.posMin) { + margin = (areaLength - itemLength) / 2; + dimension.totalLength = 0; + dimension.step++; + } + } + sizes.steps[id2] = dimension.step; + sizes.margins[dimension.step] = state.isLegendInset ? 10 : margin; + sizes.offsets[id2] = dimension.totalLength; + dimension.totalLength += itemLength; + }; + if (reset) { + dimension.totalLength = 0; + dimension.step = 0; + dimension.max.width = 0; + dimension.max.height = 0; + } + if (config.legend_show && !$$.isLegendToShow(id)) { + sizes.widths[id] = 0; + sizes.heights[id] = 0; + sizes.steps[id] = 0; + sizes.offsets[id] = 0; + return; + } + sizes.widths[id] = itemWidth; + sizes.heights[id] = itemHeight; + if (!dimension.max.width || itemWidth >= dimension.max.width) { + dimension.max.width = itemWidth; + } + if (!dimension.max.height || itemHeight >= dimension.max.height) { + dimension.max.height = itemHeight; + } + var maxLength = isLegendRightOrInset ? dimension.max.height : dimension.max.width; + if (config.legend_equally) { + Object.keys(sizes.widths).forEach(function (id2) { return (sizes.widths[id2] = dimension.max.width); }); + Object.keys(sizes.heights).forEach(function (id2) { return (sizes.heights[id2] = dimension.max.height); }); + margin = (areaLength - maxLength * targetIdz.length) / 2; + if (margin < dimension.posMin) { + dimension.totalLength = 0; + dimension.step = 0; + targetIdz.forEach(function (id2) { return updateValues(id2); }); + } + else { + updateValues(id, true); + } + } + else { + updateValues(id); + } + }; + }, + /** + * Generate legend item elements + * @param {Array} targetIdz Data ids + * @param {object} itemTileSize Item tile size {width, height} + * @param {Function} updatePositions Update position function + * @param {object} posFn Position functions + * @private + */ + generateLegendItem: function (targetIdz, itemTileSize, updatePositions, posFn) { + var $$ = this; + var config = $$.config, state = $$.state, legend = $$.$el.legend; + var usePoint = config.legend_usePoint; + var legendItemR = config.legend_item_tile_r; + var legendType = config.legend_item_tile_type; + var isRectangle = legendType !== "circle"; + var isLegendRightOrInset = state.isLegendRight || state.isLegendInset; + var pos = -200; + // Define g for legend area + var l = legend.selectAll(".".concat($LEGEND.legendItem)) + .data(targetIdz) + .enter() + .append("g"); + $$.setLegendItem(l); + l.append("text") + .text(function (id) { return (isDefined(config.data_names[id]) ? config.data_names[id] : id); }) + .each(function (id, i) { + updatePositions(this, id, i); + }) + .style("pointer-events", $$.getStylePropValue("none")) + .attr("x", isLegendRightOrInset ? posFn.xText : pos) + .attr("y", isLegendRightOrInset ? pos : posFn.yText); + l.append("rect") + .attr("class", $LEGEND.legendItemEvent) + .style("fill-opacity", $$.getStylePropValue("0")) + .attr("x", isLegendRightOrInset ? posFn.xRect : pos) + .attr("y", isLegendRightOrInset ? pos : posFn.yRect); + if (usePoint) { + var ids_2 = []; + l.append(function (d) { + var pattern = notEmpty(config.point_pattern) ? + config.point_pattern : [config.point_type]; + ids_2.indexOf(d) === -1 && ids_2.push(d); + var point = pattern[ids_2.indexOf(d) % pattern.length]; + if (point === "rectangle") { + point = "rect"; + } + return doc.createElementNS(namespaces.svg, ("hasValidPointType" in $$) && $$.hasValidPointType(point) ? point : "use"); + }) + .attr("class", $LEGEND.legendItemPoint) + .style("fill", getLegendColor.bind($$)) + .style("pointer-events", $$.getStylePropValue("none")) + .attr("href", function (data, idx, selection) { + var node = selection[idx]; + var nodeName = node.nodeName.toLowerCase(); + var id = $$.getTargetSelectorSuffix(data); + return nodeName === "use" ? "#".concat(state.datetimeId, "-point").concat(id) : undefined; + }); + } + else { + l.append(isRectangle ? "line" : legendType) + .attr("class", $LEGEND.legendItemTile) + .style("stroke", getLegendColor.bind($$)) + .style("pointer-events", $$.getStylePropValue("none")) + .call(function (selection) { + if (legendType === "circle") { + selection + .attr("r", legendItemR) + .style("fill", getLegendColor.bind($$)) + .attr("cx", isLegendRightOrInset ? posFn.x2Tile : pos) + .attr("cy", isLegendRightOrInset ? pos : posFn.yTile); + } + else if (isRectangle) { + selection + .attr("stroke-width", itemTileSize.height) + .attr("x1", isLegendRightOrInset ? posFn.x1Tile : pos) + .attr("y1", isLegendRightOrInset ? pos : posFn.yTile) + .attr("x2", isLegendRightOrInset ? posFn.x2Tile : pos) + .attr("y2", isLegendRightOrInset ? pos : posFn.yTile); + } + }); + } + }, + /** + * Update legend item position + * @param {Array} targetIdz Data ids + * @param {boolean} withTransition Whether or not to apply transition + * @param {object} posFn Position functions + * @private + */ + updateLegendItemPos: function (targetIdz, withTransition, posFn) { + var $$ = this; + var config = $$.config, legend = $$.$el.legend, $T = $$.$T; + var usePoint = config.legend_usePoint; + var legendType = config.legend_item_tile_type; + var isRectangle = legendType !== "circle"; + if (usePoint) { + var tiles = legend.selectAll(".".concat($LEGEND.legendItemPoint)) + .data(targetIdz); + $T(tiles, withTransition) + .each(function () { + var nodeName = this.nodeName.toLowerCase(); + var pointR = config.point_r; + var x = "x"; + var y = "y"; + var xOffset = 2; + var yOffset = 2.5; + var radius = null; + var width = null; + var height = null; + if (nodeName === "circle") { + var size = pointR * 0.2; + x = "cx"; + y = "cy"; + radius = pointR + size; + xOffset = pointR * 2; + yOffset = -size; + } + else if (nodeName === "rect") { + var size = pointR * 2.5; + width = size; + height = size; + yOffset = 3; + } + select(this) + .attr(x, function (d) { return posFn.x1Tile(d) + xOffset; }) + .attr(y, function (d) { return posFn.yTile(d) - yOffset; }) + .attr("r", radius) + .attr("width", width) + .attr("height", height); + }); + } + else { + var tiles = legend.selectAll(".".concat($LEGEND.legendItemTile)) + .data(targetIdz); + $T(tiles, withTransition) + .style("stroke", getLegendColor.bind($$)) + .call(function (selection) { + if (legendType === "circle") { + selection + .attr("cx", function (d) { + var x2 = posFn.x2Tile(d); + return x2 - ((x2 - posFn.x1Tile(d)) / 2); + }) + .attr("cy", posFn.yTile); + } + else if (isRectangle) { + selection + .attr("x1", posFn.x1Tile) + .attr("y1", posFn.yTile) + .attr("x2", posFn.x2Tile) + .attr("y2", posFn.yTile); + } + }); + } + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var redraw = { + redraw: function (options) { + var _a, _b, _c; + if (options === void 0) { options = {}; } + var $$ = this; + var config = $$.config, state = $$.state, $el = $$.$el; + var main = $el.main, treemap = $el.treemap; + state.redrawing = true; + var targetsToShow = $$.filterTargetsToShow($$.data.targets); + var flow = options.flow, initializing = options.initializing; + var wth = $$.getWithOption(options); + var duration = wth.Transition ? config.transition_duration : 0; + var durationForExit = wth.TransitionForExit ? duration : 0; + var durationForAxis = wth.TransitionForAxis ? duration : 0; + var transitions = (_a = $$.axis) === null || _a === void 0 ? void 0 : _a.generateTransitions(durationForAxis); + $$.updateSizes(initializing); + // update legend and transform each g + if (wth.Legend && config.legend_show) { + options.withTransition = !!duration; + !treemap && $$.updateLegend($$.mapToIds($$.data.targets), options, transitions); + } + else if (wth.Dimension) { + // need to update dimension (e.g. axis.y.tick.values) because y tick values should change + // no need to update axis in it because they will be updated in redraw() + $$.updateDimension(true); + } + // Data empty label positioning and text. + config.data_empty_label_text && main.select("text.".concat($TEXT.text, ".").concat($COMMON.empty)) + .attr("x", state.width / 2) + .attr("y", state.height / 2) + .text(config.data_empty_label_text) + .style("display", targetsToShow.length ? "none" : null); + // update axis + if (state.hasAxis) { + // @TODO: Make 'init' state to be accessible everywhere not passing as argument. + $$.axis.redrawAxis(targetsToShow, wth, transitions, flow, initializing); + // grid + $$.hasGrid() && $$.updateGrid(); + // rect for regions + config.regions.length && $$.updateRegion(); + ["bar", "candlestick", "line", "area"].forEach(function (v) { + var name = capitalize(v); + if ((/^(line|area)$/.test(v) && $$.hasTypeOf(name)) || $$.hasType(v)) { + $$["update".concat(name)](wth.TransitionForExit); + } + }); + // circles for select + $el.text && main.selectAll(".".concat($SELECT.selectedCircles)) + .filter($$.isBarType.bind($$)) + .selectAll("circle") + .remove(); + // event rects will redrawn when flow called + if (config.interaction_enabled && !flow && wth.EventRect) { + $$.redrawEventRect(); + (_b = $$.bindZoomEvent) === null || _b === void 0 ? void 0 : _b.call($$); + } + } + else { + // arc + $el.arcs && $$.redrawArc(duration, durationForExit, wth.Transform); + // radar + $el.radar && $$.redrawRadar(); + // polar + $el.polar && $$.redrawPolar(); + // treemap + treemap && $$.updateTreemap(durationForExit); + } + // @TODO: Axis & Radar type + if (!state.resizing && !treemap && ($$.hasPointType() || state.hasRadar)) { + $$.updateCircle(); + } + // text + $$.hasDataLabel() && !$$.hasArcType(null, ["radar"]) && $$.updateText(); + // title + (_c = $$.redrawTitle) === null || _c === void 0 ? void 0 : _c.call($$); + initializing && $$.updateTypesElements(); + $$.generateRedrawList(targetsToShow, flow, duration, wth.Subchart); + $$.updateTooltipOnRedraw(); + $$.callPluginHook("$redraw", options, duration); + }, + /** + * Generate redraw list + * @param {object} targets targets data to be shown + * @param {object} flow flow object + * @param {number} duration duration value + * @param {boolean} withSubchart whether or not to show subchart + * @private + */ + generateRedrawList: function (targets, flow, duration, withSubchart) { + var $$ = this; + var config = $$.config, state = $$.state; + var shape = $$.getDrawShape(); + if (state.hasAxis) { + // subchart + config.subchart_show && $$.redrawSubchart(withSubchart, duration, shape); + } + // generate flow + var flowFn = flow && $$.generateFlow({ + targets: targets, + flow: flow, + duration: flow.duration, + shape: shape, + xv: $$.xv.bind($$) + }); + var withTransition = (duration || flowFn) && isTabVisible(); + // redraw list + var redrawList = $$.getRedrawList(shape, flow, flowFn, withTransition); + // callback function after redraw ends + var afterRedraw = function () { + flowFn && flowFn(); + state.redrawing = false; + callFn(config.onrendered, $$.api); + }; + if (afterRedraw) { + // Only use transition when current tab is visible. + if (withTransition && redrawList.length) { + // Wait for end of transitions for callback + var waitForDraw_1 = generateWait(); + // transition should be derived from one transition + transition().duration(duration) + .each(function () { + redrawList + .reduce(function (acc, t1) { return acc.concat(t1); }, []) + .forEach(function (t) { return waitForDraw_1.add(t); }); + }) + .call(waitForDraw_1, afterRedraw); + } + else if (!state.transiting) { + afterRedraw(); + } + } + // update fadein condition + $$.mapToIds($$.data.targets).forEach(function (id) { + state.withoutFadeIn[id] = true; + }); + }, + getRedrawList: function (shape, flow, flowFn, withTransition) { + var $$ = this; + var config = $$.config, _a = $$.state, hasAxis = _a.hasAxis, hasRadar = _a.hasRadar, hasTreemap = _a.hasTreemap, grid = $$.$el.grid; + var _b = shape.pos, cx = _b.cx, cy = _b.cy, xForText = _b.xForText, yForText = _b.yForText; + var list = []; + if (hasAxis) { + if (config.grid_x_lines.length || config.grid_y_lines.length) { + list.push($$.redrawGrid(withTransition)); + } + if (config.regions.length) { + list.push($$.redrawRegion(withTransition)); + } + Object.keys(shape.type).forEach(function (v) { + var name = capitalize(v); + var drawFn = shape.type[v]; + if ((/^(area|line)$/.test(v) && $$.hasTypeOf(name)) || $$.hasType(v)) { + list.push($$["redraw".concat(name)](drawFn, withTransition)); + } + }); + !flow && grid.main && list.push($$.updateGridFocus()); + } + if (!$$.hasArcType() || hasRadar) { + notEmpty(config.data_labels) && config.data_labels !== false && + list.push($$.redrawText(xForText, yForText, flow, withTransition)); + } + if (($$.hasPointType() || hasRadar) && !$$.isPointFocusOnly()) { + $$.redrawCircle && list.push($$.redrawCircle(cx, cy, withTransition, flowFn)); + } + if (hasTreemap) { + list.push($$.redrawTreemap(withTransition)); + } + return list; + }, + updateAndRedraw: function (options) { + if (options === void 0) { options = {}; } + var $$ = this; + var config = $$.config, state = $$.state; + var transitions; + // same with redraw + options.withTransition = getOption(options, "withTransition", true); + options.withTransform = getOption(options, "withTransform", false); + options.withLegend = getOption(options, "withLegend", false); + // NOT same with redraw + options.withUpdateXDomain = true; + options.withUpdateOrgXDomain = true; + options.withTransitionForExit = false; + options.withTransitionForTransform = getOption(options, "withTransitionForTransform", options.withTransition); + // MEMO: called in updateLegend in redraw if withLegend + if (!(options.withLegend && config.legend_show)) { + if (state.hasAxis) { + transitions = $$.axis.generateTransitions(options.withTransitionForAxis ? config.transition_duration : 0); + } + // Update scales + $$.updateScales(); + $$.updateSvgSize(); + // Update g positions + $$.transformAll(options.withTransitionForTransform, transitions); + } + // Draw with new sizes & scales + $$.redraw(options, transitions); + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get scale + * @param {string} [type='linear'] Scale type + * @param {number} [min] Min range + * @param {number} [max] Max range + * @returns {d3.scaleLinear|d3.scaleTime} scale + * @private + */ +function getScale(type, min, max) { + if (type === void 0) { type = "linear"; } + if (min === void 0) { min = 0; } + if (max === void 0) { max = 1; } + var scale = ({ + linear: scaleLinear, + log: scaleSymlog, + _log: scaleLog, + time: scaleTime, + utc: scaleUtc + })[type](); + scale.type = type; + /_?log/.test(type) && scale.clamp(true); + return scale.range([min, max]); +} +var scale = { + /** + * Get x Axis scale function + * @param {number} min Min value + * @param {number} max Max value + * @param {Array} domain Domain value + * @param {Function} offset The offset getter to be sum + * @returns {Function} scale + * @private + */ + getXScale: function (min, max, domain, offset) { + var $$ = this; + var scale = $$.scale.zoom || getScale($$.axis.getAxisType("x"), min, max); + return $$.getCustomizedXScale(domain ? scale.domain(domain) : scale, offset); + }, + /** + * Get y Axis scale function + * @param {string} id Axis id: 'y' or 'y2' + * @param {number} min Min value + * @param {number} max Max value + * @param {Array} domain Domain value + * @returns {Function} Scale function + * @private + */ + getYScale: function (id, min, max, domain) { + var $$ = this; + var scale = getScale($$.axis.getAxisType(id), min, max); + domain && scale.domain(domain); + return scale; + }, + /** + * Get y Axis scale + * @param {string} id Axis id + * @param {boolean} isSub Weather is sub Axis + * @returns {Function} Scale function + * @private + */ + getYScaleById: function (id, isSub) { + var _a; + if (isSub === void 0) { isSub = false; } + var isY2 = ((_a = this.axis) === null || _a === void 0 ? void 0 : _a.getId(id)) === "y2"; + var key = isSub ? (isY2 ? "subY2" : "subY") : (isY2 ? "y2" : "y"); + return this.scale[key]; + }, + /** + * Get customized x axis scale + * @param {d3.scaleLinear|d3.scaleTime} scaleValue Scale function + * @param {Function} offsetValue Offset getter to be sum + * @returns {Function} Scale function + * @private + */ + getCustomizedXScale: function (scaleValue, offsetValue) { + var $$ = this; + var offset = offsetValue || (function () { return $$.axis.x.tickOffset(); }); + var isInverted = $$.config.axis_x_inverted; + var scale = function (d, raw) { + var v = scaleValue(d) + offset(); + return raw ? v : Math.ceil(v); + }; + // copy original scale methods + for (var key in scaleValue) { + scale[key] = scaleValue[key]; + } + scale.orgDomain = function () { return scaleValue.domain(); }; + scale.orgScale = function () { return scaleValue; }; + // define custom domain() for categorized axis + if ($$.axis.isCategorized()) { + scale.domain = function (domainValue) { + var domain = domainValue; + if (!arguments.length) { + domain = this.orgDomain(); + return isInverted ? + [domain[0] + 1, domain[1]] : + [domain[0], domain[1] + 1]; + } + scaleValue.domain(domain); + return scale; + }; + } + return scale; + }, + /** + * Update scale + * @param {boolean} isInit Param is given at the init rendering + * @param {boolean} updateXDomain If update x domain + * @private + */ + updateScales: function (isInit, updateXDomain) { + var _a, _b; + if (updateXDomain === void 0) { updateXDomain = true; } + var $$ = this; + var axis = $$.axis, config = $$.config, format = $$.format, org = $$.org, scale = $$.scale, _c = $$.state, current = _c.current, width = _c.width, height = _c.height, width2 = _c.width2, height2 = _c.height2, hasAxis = _c.hasAxis, hasTreemap = _c.hasTreemap; + if (hasAxis) { + var isRotated = config.axis_rotated; + var resettedPadding = $$.getResettedPadding(1); + // update edges + var min = { + x: isRotated ? resettedPadding : 0, + y: isRotated ? 0 : height, + subX: isRotated ? 1 : 0, + subY: isRotated ? 0 : height2 + }; + var max = { + x: isRotated ? height : width, + y: isRotated ? width : resettedPadding, + subX: isRotated ? height : width, + subY: isRotated ? width2 : 1 + }; + // update scales + // x Axis + var xDomain = updateXDomain && ((_a = scale.x) === null || _a === void 0 ? void 0 : _a.orgDomain()); + var xSubDomain = updateXDomain && org.xDomain; + scale.x = $$.getXScale(min.x, max.x, xDomain, function () { return axis.x.tickOffset(); }); + scale.subX = $$.getXScale(min.x, max.x, xSubDomain, function (d) { + var _a; + return (d % 1 ? 0 : ((_a = axis.subX) !== null && _a !== void 0 ? _a : axis.x).tickOffset()); + }); + format.xAxisTick = axis.getXAxisTickFormat(); + format.subXAxisTick = axis.getXAxisTickFormat(true); + axis.setAxis("x", scale.x, config.axis_x_tick_outer, isInit); + if (config.subchart_show) { + axis.setAxis("subX", scale.subX, config.axis_x_tick_outer, isInit); + } + // y Axis + scale.y = $$.getYScale("y", min.y, max.y, scale.y ? scale.y.domain() : config.axis_y_default); + scale.subY = $$.getYScale("y", min.subY, max.subY, scale.subY ? scale.subY.domain() : config.axis_y_default); + axis.setAxis("y", scale.y, config.axis_y_tick_outer, isInit); + // y2 Axis + if (config.axis_y2_show) { + scale.y2 = $$.getYScale("y2", min.y, max.y, scale.y2 ? scale.y2.domain() : config.axis_y2_default); + scale.subY2 = $$.getYScale("y2", min.subY, max.subY, scale.subY2 ? scale.subY2.domain() : config.axis_y2_default); + axis.setAxis("y2", scale.y2, config.axis_y2_tick_outer, isInit); + } + } + else if (hasTreemap) { + var padding = $$.getCurrentPadding(); + scale.x = scaleLinear().rangeRound([padding.left, current.width - padding.right]); + scale.y = scaleLinear().rangeRound([padding.top, current.height - padding.bottom]); + } + else { + // update for arc + (_b = $$.updateArc) === null || _b === void 0 ? void 0 : _b.call($$); + } + }, + /** + * Get the zoom or unzoomed scaled value + * @param {Date|number|object} d Data value + * @returns {number|null} + * @private + */ + xx: function (d) { + var $$ = this; + var config = $$.config, _a = $$.scale, x = _a.x, zoom = _a.zoom; + var fn = config.zoom_enabled && zoom ? zoom : x; + return d ? fn(isValue(d.x) ? d.x : d) : null; + }, + xv: function (d) { + var $$ = this; + var axis = $$.axis, config = $$.config, _a = $$.scale, x = _a.x, zoom = _a.zoom; + var fn = config.zoom_enabled && zoom ? zoom : x; + var value = $$.getBaseValue(d); + if (axis.isTimeSeries()) { + value = parseDate.call($$, value); + } + else if (axis.isCategorized() && isString(value)) { + value = config.axis_x_categories.indexOf(value); + } + return Math.ceil(fn(value)); + }, + yv: function (d) { + var $$ = this; + var _a = $$.scale, y = _a.y, y2 = _a.y2; + var yScale = d.axis && d.axis === "y2" ? y2 : y; + return Math.ceil(yScale($$.getBaseValue(d))); + }, + subxx: function (d) { + return d ? this.scale.subX(d.x) : null; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get grouped data point function for y coordinate + * - Note: Grouped(stacking) works only for line and bar types + * @param {object} d data vlaue + * @returns {Function|undefined} + * @private + */ +function getGroupedDataPointsFn(d) { + var $$ = this; + var fn; + if ($$.isLineType(d)) { + fn = $$.generateGetLinePoints($$.getShapeIndices($$.isLineType)); + } + else if ($$.isBarType(d)) { + fn = $$.generateGetBarPoints($$.getShapeIndices($$.isBarType)); + } + return fn; +} +var shape = { + /** + * Get the shape draw function + * @returns {object} + * @private + */ + getDrawShape: function () { + var $$ = this; + var isRotated = $$.config.axis_rotated; + var _a = $$.state, hasRadar = _a.hasRadar, hasTreemap = _a.hasTreemap; + var shape = { type: {}, indices: {}, pos: {} }; + !hasTreemap && ["bar", "candlestick", "line", "area"].forEach(function (v) { + var name = capitalize(/^(bubble|scatter)$/.test(v) ? "line" : v); + if ($$.hasType(v) || $$.hasTypeOf(name) || (v === "line" && ($$.hasType("bubble") || $$.hasType("scatter")))) { + var indices = $$.getShapeIndices($$["is".concat(name, "Type")]); + var drawFn = $$["generateDraw".concat(name)]; + shape.indices[v] = indices; + shape.type[v] = drawFn ? drawFn.bind($$)(indices, false) : undefined; + } + }); + if (!$$.hasArcType() || hasRadar || hasTreemap) { + var cx = void 0; + var cy = void 0; + // generate circle x/y functions depending on updated params + if (!hasTreemap) { + cx = hasRadar ? $$.radarCircleX : (isRotated ? $$.circleY : $$.circleX); + cy = hasRadar ? $$.radarCircleY : (isRotated ? $$.circleX : $$.circleY); + } + shape.pos = { + xForText: $$.generateXYForText(shape.indices, true), + yForText: $$.generateXYForText(shape.indices, false), + cx: (cx || function () { }).bind($$), + cy: (cy || function () { }).bind($$) + }; + } + return shape; + }, + /** + * Get shape's indices according it's position within each axis tick. + * + * From the below example, indices will be: + * ==> {data1: 0, data2: 0, data3: 1, data4: 1, __max__: 1} + * + * data1 data3 data1 data3 + * data2 data4 data2 data4 + * ------------------------- + * 0 1 + * @param {Function} typeFilter Chart type filter function + * @returns {object} Indices object with its position + */ + getShapeIndices: function (typeFilter) { + var $$ = this; + var config = $$.config; + var xs = config.data_xs; + var hasXs = notEmpty(xs); + var indices = {}; + var i = hasXs ? {} : 0; + if (hasXs) { + getUnique(Object.keys(xs).map(function (v) { return xs[v]; })) + .forEach(function (v) { + i[v] = 0; + indices[v] = {}; + }); + } + $$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$)) + .forEach(function (d) { + var _a; + var xKey = d.id in xs ? xs[d.id] : ""; + var ind = xKey ? indices[xKey] : indices; + for (var j = 0, groups = void 0; (groups = config.data_groups[j]); j++) { + if (groups.indexOf(d.id) < 0) { + continue; + } + for (var k = 0, key = void 0; (key = groups[k]); k++) { + if (key in ind) { + ind[d.id] = ind[key]; + break; + } + // for same grouped data, add other data to same indices + if (d.id !== key && xKey) { + ind[key] = (_a = ind[d.id]) !== null && _a !== void 0 ? _a : i[xKey]; + } + } + } + if (isUndefined(ind[d.id])) { + ind[d.id] = xKey ? i[xKey]++ : i++; + ind.__max__ = (xKey ? i[xKey] : i) - 1; + } + }); + return indices; + }, + /** + * Get indices value based on data ID value + * @param {object} indices Indices object + * @param {object} d Data row + * @param {string} caller Caller function name (Used only for 'sparkline' plugin) + * @returns {object} Indices object + * @private + */ + getIndices: function (indices, d, caller) { + var $$ = this; + var _a = $$.config, xs = _a.data_xs, removeNull = _a.bar_indices_removeNull; + var id = d.id, index = d.index; + if ($$.isBarType(id) && removeNull) { + var ind_1 = {}; + // redefine bar indices order + $$.getAllValuesOnIndex(index, true) + .forEach(function (v, i) { + ind_1[v.id] = i; + ind_1.__max__ = i; + }); + return ind_1; + } + return notEmpty(xs) ? + indices[xs[id]] : indices; + }, + /** + * Get indices max number + * @param {object} indices Indices object + * @returns {number} Max number + * @private + */ + getIndicesMax: function (indices) { + return notEmpty(this.config.data_xs) ? + // if is multiple xs, return total sum of xs' __max__ value + Object.keys(indices) + .map(function (v) { return indices[v].__max__ || 0; }) + .reduce(function (acc, curr) { return acc + curr; }) : indices.__max__; + }, + getShapeX: function (offset, indices, isSub) { + var $$ = this; + var config = $$.config, scale = $$.scale; + var currScale = isSub ? scale.subX : (scale.zoom || scale.x); + var barOverlap = config.bar_overlap; + var barPadding = config.bar_padding; + var sum = function (p, c) { return p + c; }; + // total shapes half width + var halfWidth = isObjectType(offset) && (offset._$total.length ? offset._$total.reduce(sum) / 2 : 0); + return function (d) { + var ind = $$.getIndices(indices, d, "getShapeX"); + var index = d.id in ind ? ind[d.id] : 0; + var targetsNum = (ind.__max__ || 0) + 1; + var x = 0; + if (notEmpty(d.x)) { + var xPos = currScale(d.x, true); + if (halfWidth) { + var offsetWidth = offset[d.id] || offset._$width; + x = barOverlap ? + xPos - offsetWidth / 2 : + xPos - offsetWidth + offset._$total.slice(0, index + 1).reduce(sum) - halfWidth; + } + else { + x = xPos - (isNumber(offset) ? offset : offset._$width) * + (targetsNum / 2 - (barOverlap ? 1 : index)); + } + } + // adjust x position for bar.padding option + if (offset && x && targetsNum > 1 && barPadding) { + if (index) { + x += barPadding * index; + } + if (targetsNum > 2) { + x -= (targetsNum - 1) * barPadding / 2; + } + else if (targetsNum === 2) { + x -= barPadding / 2; + } + } + return x; + }; + }, + getShapeY: function (isSub) { + var $$ = this; + var isStackNormalized = $$.isStackNormalized(); + return function (d) { + var value = d.value; + if (isNumber(d)) { + value = d; + } + else if (isStackNormalized) { + value = $$.getRatio("index", d, true); + } + else if ($$.isBubbleZType(d)) { + value = $$.getBubbleZData(d.value, "y"); + } + else if ($$.isBarRangeType(d)) { + // TODO use range.getEnd() like method + value = value[1]; + } + return $$.getYScaleById(d.id, isSub)(value); + }; + }, + /** + * Get shape based y Axis min value + * @param {string} id Data id + * @returns {number} + * @private + */ + getShapeYMin: function (id) { + var $$ = this; + var axisId = $$.axis.getId(id); + var scale = $$.scale[axisId]; + var yMin = scale.domain()[0]; + var inverted = $$.config["axis_".concat(axisId, "_inverted")]; + return !$$.isGrouped(id) && !inverted && yMin > 0 ? yMin : 0; + }, + /** + * Get Shape's offset data + * @param {Function} typeFilter Type filter function + * @returns {object} + * @private + */ + getShapeOffsetData: function (typeFilter) { + var $$ = this; + var targets = $$.orderTargets($$.filterTargetsToShow($$.data.targets.filter(typeFilter, $$))); + var isStackNormalized = $$.isStackNormalized(); + var shapeOffsetTargets = targets.map(function (target) { + var rowValues = target.values; + var values = {}; + if ($$.isStepType(target)) { + rowValues = $$.convertValuesToStep(rowValues); + } + var rowValueMapByXValue = rowValues.reduce(function (out, d) { + var key = Number(d.x); + out[key] = d; + values[key] = isStackNormalized ? $$.getRatio("index", d, true) : d.value; + return out; + }, {}); + return { + id: target.id, + rowValues: rowValues, + rowValueMapByXValue: rowValueMapByXValue, + values: values + }; + }); + var indexMapByTargetId = targets.reduce(function (out, _a, index) { + var id = _a.id; + out[id] = index; + return out; + }, {}); + return { indexMapByTargetId: indexMapByTargetId, shapeOffsetTargets: shapeOffsetTargets }; + }, + getShapeOffset: function (typeFilter, indices, isSub) { + var $$ = this; + var _a = $$.getShapeOffsetData(typeFilter), shapeOffsetTargets = _a.shapeOffsetTargets, indexMapByTargetId = _a.indexMapByTargetId; + var groupsZeroAs = $$.config.data_groupsZeroAs; + return function (d, idx) { + var id = d.id, value = d.value, x = d.x; + var ind = $$.getIndices(indices, d); + var scale = $$.getYScaleById(id, isSub); + if ($$.isBarRangeType(d)) { + // TODO use range.getStart() + return scale(value[0]); + } + var dataXAsNumber = Number(x); + var y0 = scale(groupsZeroAs === "zero" ? 0 : $$.getShapeYMin(id)); + var offset = y0; + shapeOffsetTargets + .filter(function (t) { return t.id !== id && ind[t.id] === ind[id]; }) + .forEach(function (t) { + var tid = t.id, rowValueMapByXValue = t.rowValueMapByXValue, rowValues = t.rowValues, tvalues = t.values; + // for same stacked group (ind[tid] === ind[id]) + if (indexMapByTargetId[tid] < indexMapByTargetId[id]) { + var rValue = tvalues[dataXAsNumber]; + var row = rowValues[idx]; + // check if the x values line up + if (!row || Number(row.x) !== dataXAsNumber) { + row = rowValueMapByXValue[dataXAsNumber]; + } + if ((row === null || row === void 0 ? void 0 : row.value) * value >= 0 && isNumber(rValue)) { + var addOffset = value === 0 ? ((groupsZeroAs === "positive" && rValue > 0) || + (groupsZeroAs === "negative" && rValue < 0)) : true; + if (addOffset) { + offset += scale(rValue) - y0; + } + } + } + }); + return offset; + }; + }, + /** + * Get data's y coordinate + * @param {object} d Target data + * @param {number} i Index number + * @returns {number} y coordinate + * @private + */ + circleY: function (d, i) { + var $$ = this; + var id = d.id; + var points; + if ($$.isGrouped(id)) { + points = getGroupedDataPointsFn.bind($$)(d); + } + return points ? + points(d, i)[0][1] : + $$.getYScaleById(id)($$.getBaseValue(d)); + }, + getBarW: function (type, axis, targetsNum) { + var $$ = this; + var config = $$.config, org = $$.org, scale = $$.scale; + var maxDataCount = $$.getMaxDataCount(); + var isGrouped = type === "bar" && config.data_groups.length; + var configName = "".concat(type, "_width"); + var tickInterval = scale.zoom && !$$.axis.isCategorized() ? + (org.xDomain.map(function (v) { return scale.zoom(v); }) + .reduce(function (a, c) { return Math.abs(a) + c; }) / maxDataCount) : axis.tickInterval(maxDataCount); + var getWidth = function (id) { + var width = id ? config[configName][id] : config[configName]; + var ratio = id ? width.ratio : config["".concat(configName, "_ratio")]; + var max = id ? width.max : config["".concat(configName, "_max")]; + var w = isNumber(width) ? + width : targetsNum ? (tickInterval * ratio) / targetsNum : 0; + return max && w > max ? max : w; + }; + var result = getWidth(); + if (!isGrouped && isObjectType(config[configName])) { + result = { _$width: result, _$total: [] }; + $$.filterTargetsToShow($$.data.targets).forEach(function (v) { + if (config[configName][v.id]) { + result[v.id] = getWidth(v.id); + result._$total.push(result[v.id] || result._$width); + } + }); + } + return result; + }, + /** + * Get shape element + * @param {string} shapeName Shape string + * @param {number} i Index number + * @param {string} id Data series id + * @returns {d3Selection} + * @private + */ + getShapeByIndex: function (shapeName, i, id) { + var $$ = this; + var $el = $$.$el; + var suffix = (isValue(i) ? "-".concat(i) : ""); + var shape = $el[shapeName]; + // filter from shape reference if has + if (shape && !shape.empty()) { + shape = shape + .filter(function (d) { return (id ? d.id === id : true); }) + .filter(function (d) { return (isValue(i) ? d.index === i : true); }); + } + else { + shape = (id ? $el.main + .selectAll(".".concat(CLASS["".concat(shapeName, "s")]).concat($$.getTargetSelectorSuffix(id))) : $el.main) + .selectAll(".".concat(CLASS[shapeName]).concat(suffix)); + } + return shape; + }, + isWithinShape: function (that, d) { + var _a; + var $$ = this; + var shape = select(that); + var isWithin; + if (!$$.isTargetToShow(d.id)) { + isWithin = false; + } + else if ((_a = $$.hasValidPointType) === null || _a === void 0 ? void 0 : _a.call($$, that.nodeName)) { + isWithin = $$.isStepType(d) ? + $$.isWithinStep(that, $$.getYScaleById(d.id)(d.value)) : + $$.isWithinCircle(that, $$.isBubbleType(d) ? $$.pointSelectR(d) * 1.5 : 0); + } + else if (that.nodeName === "path") { + isWithin = shape.classed(CLASS.bar) ? $$.isWithinBar(that) : true; + } + return isWithin; + }, + getInterpolate: function (d) { + var $$ = this; + var interpolation = $$.getInterpolateType(d); + return { + "basis": curveBasis, + "basis-closed": curveBasisClosed, + "basis-open": curveBasisOpen, + "bundle": curveBundle, + "cardinal": curveCardinal, + "cardinal-closed": curveCardinalClosed, + "cardinal-open": curveCardinalOpen, + "catmull-rom": curveCatmullRom, + "catmull-rom-closed": curveCatmullRomClosed, + "catmull-rom-open": curveCatmullRomOpen, + "monotone-x": curveMonotoneX, + "monotone-y": curveMonotoneY, + "natural": curveNatural, + "linear-closed": curveLinearClosed, + "linear": curveLinear, + "step": curveStep, + "step-after": curveStepAfter, + "step-before": curveStepBefore + }[interpolation]; + }, + getInterpolateType: function (d) { + var $$ = this; + var config = $$.config; + var type = config.spline_interpolation_type; + var interpolation = $$.isInterpolationType(type) ? type : "cardinal"; + return $$.isSplineType(d) ? + interpolation : ($$.isStepType(d) ? + config.line_step_type : "linear"); + }, + isWithinBar: function (that) { + var mouse = getPointer(this.state.event, that); + var list = getRectSegList(that); + var seg0 = list[0], seg1 = list[1]; + var x = Math.min(seg0.x, seg1.x); + var y = Math.min(seg0.y, seg1.y); + var offset = this.config.bar_sensitivity; + var _a = that.getBBox(), width = _a.width, height = _a.height; + var sx = x - offset; + var ex = x + width + offset; + var sy = y + height + offset; + var ey = y - offset; + var isWithin = sx < mouse[0] && + mouse[0] < ex && + ey < mouse[1] && + mouse[1] < sy; + return isWithin; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var size = { + /** + * Update container size + * @private + */ + setContainerSize: function () { + var $$ = this; + var state = $$.state; + state.current.width = $$.getCurrentWidth(); + state.current.height = $$.getCurrentHeight(); + }, + getCurrentWidth: function () { + var $$ = this; + return $$.config.size_width || $$.getParentWidth(); + }, + getCurrentHeight: function () { + var $$ = this; + var config = $$.config; + var h = config.size_height || $$.getParentHeight(); + return h > 0 ? h : 320 / ($$.hasType("gauge") && !config.gauge_fullCircle ? 2 : 1); + }, + /** + * Get the parent rect element's size + * @param {string} key property/attribute name + * @returns {number} + * @private + */ + getParentRectValue: function (key) { + var offsetName = "offset".concat(capitalize(key)); + var parent = this.$el.chart.node(); + var v = 0; + while (v < 30 && parent && parent.tagName !== "BODY") { + try { + v = parent.getBoundingClientRect()[key]; + } + catch (e) { + if (offsetName in parent) { + // In IE in certain cases getBoundingClientRect + // will cause an "unspecified error" + v = parent[offsetName]; + } + } + parent = parent.parentNode; + } + // Sometimes element's dimension value is incorrect(ex. flex container) + // In this case, use body's offset instead. + var bodySize = doc.body[offsetName]; + v > bodySize && (v = bodySize); + return v; + }, + getParentWidth: function () { + return this.getParentRectValue("width"); + }, + getParentHeight: function () { + var h = this.$el.chart.style("height"); + var height = 0; + if (h) { + height = /px$/.test(h) ? + parseInt(h, 10) : + this.getParentRectValue("height"); + } + return height; + }, + getSvgLeft: function (withoutRecompute) { + var $$ = this; + var config = $$.config, hasAxis = $$.state.hasAxis, $el = $$.$el; + var isRotated = config.axis_rotated; + var hasLeftAxisRect = isRotated || (!isRotated && !config.axis_y_inner); + var leftAxisClass = isRotated ? $AXIS.axisX : $AXIS.axisY; + var leftAxis = $el.main.select(".".concat(leftAxisClass)).node(); + var leftLabel = hasAxis && config["axis_".concat(isRotated ? "x" : "y", "_label")]; + var labelWidth = 0; + // if axis label position set to inner, exclude from the value + if (hasAxis && (isString(leftLabel) || isString(leftLabel.text) || /^inner-/.test(leftLabel === null || leftLabel === void 0 ? void 0 : leftLabel.position))) { + var label = $el.main.select(".".concat(leftAxisClass, "-label")); + if (!label.empty()) { + labelWidth = label.node().getBoundingClientRect().left; + } + } + var svgRect = leftAxis && hasLeftAxisRect ? leftAxis.getBoundingClientRect() : { right: 0 }; + var chartRectLeft = $el.chart.node().getBoundingClientRect().left + labelWidth; + var hasArc = $$.hasArcType(); + var svgLeft = svgRect.right - chartRectLeft - + (hasArc ? 0 : $$.getCurrentPaddingByDirection("left", withoutRecompute)); + return svgLeft > 0 ? svgLeft : 0; + }, + updateDimension: function (withoutAxis) { + var _a; + var $$ = this; + var config = $$.config, hasAxis = $$.state.hasAxis, $el = $$.$el; + if (hasAxis && !withoutAxis && $$.axis.x && config.axis_rotated) { + (_a = $$.axis.subX) === null || _a === void 0 ? void 0 : _a.create($el.axis.subX); + } + // pass 'withoutAxis' param to not animate at the init rendering + $$.updateScales(withoutAxis); + $$.updateSvgSize(); + $$.transformAll(false); + }, + updateSvgSize: function () { + var $$ = this; + var _a = $$.state, clip = _a.clip, current = _a.current, hasAxis = _a.hasAxis, width = _a.width, height = _a.height, svg = $$.$el.svg; + svg + .attr("width", current.width) + .attr("height", current.height); + if (hasAxis) { + var brush = svg.select(".".concat($SUBCHART.brush, " .overlay")); + var brushSize = { width: 0, height: 0 }; + if (brush.size()) { + brushSize.width = +brush.attr("width"); + brushSize.height = +brush.attr("height"); + } + svg.selectAll(["#".concat(clip.id), "#".concat(clip.idGrid)]) + .select("rect") + .attr("width", width) + .attr("height", height); + svg.select("#".concat(clip.idXAxis)) + .select("rect") + .call($$.setXAxisClipPath.bind($$)); + svg.select("#".concat(clip.idYAxis)) + .select("rect") + .call($$.setYAxisClipPath.bind($$)); + clip.idSubchart && svg.select("#".concat(clip.idSubchart)) + .select("rect") + .attr("width", width) + .attr("height", brushSize.height); + } + }, + /** + * Get padding by the direction. + * @param {string} type "top" | "bottom" | "left" | "right" + * @param {boolean} [withoutRecompute=false] If set true, do not recompute the padding value. + * @returns {number} padding value + * @private + */ + getCurrentPaddingByDirection: function (type, withoutRecompute) { + var _a; + if (withoutRecompute === void 0) { withoutRecompute = false; } + var $$ = this; + var config = $$.config, $el = $$.$el, hasAxis = $$.state.hasAxis; + var isRotated = config.axis_rotated; + var isFitPadding = ((_a = config.padding) === null || _a === void 0 ? void 0 : _a.mode) === "fit"; + var paddingOption = isNumber(config["padding_".concat(type)]) ? config["padding_".concat(type)] : undefined; + var axisId = hasAxis ? { + top: isRotated ? "y2" : null, + bottom: isRotated ? "y" : "x", + left: isRotated ? "x" : "y", + right: isRotated ? null : "y2" + }[type] : null; + var isLeftRight = /^(left|right)$/.test(type); + var isAxisInner = axisId && config["axis_".concat(axisId, "_inner")]; + var isAxisShow = axisId && config["axis_".concat(axisId, "_show")]; + var axesLen = axisId ? config["axis_".concat(axisId, "_axes")].length : 0; + var axisSize = axisId ? (isLeftRight ? + $$.getAxisWidthByAxisId(axisId, withoutRecompute) : + $$.getHorizontalAxisHeight(axisId)) : 0; + var defaultPadding = 20; + var gap = 0; + if (!isFitPadding && isLeftRight) { + axisSize = ceil10(axisSize); + } + var padding = hasAxis && isLeftRight && (isAxisInner || (isUndefined(paddingOption) && !isAxisShow)) ? 0 : (isFitPadding ? (isAxisShow ? axisSize : 0) + (paddingOption !== null && paddingOption !== void 0 ? paddingOption : 0) : (isUndefined(paddingOption) ? axisSize : paddingOption)); + if (isLeftRight && hasAxis) { + if (axisId && (isFitPadding || isAxisInner) && config["axis_".concat(axisId, "_label")].text) { + padding += $$.axis.getAxisLabelPosition(axisId).isOuter ? defaultPadding : 0; + } + if (type === "right") { + padding += isRotated ? (!isFitPadding && isUndefined(paddingOption) ? 10 : 2) : !isAxisShow || isAxisInner ? (isFitPadding ? 2 : 1) : 0; + } + else if (type === "left" && isRotated && isUndefined(paddingOption)) { + padding = !config.axis_x_show ? + 1 : (isFitPadding ? axisSize : Math.max(axisSize, 40)); + } + } + else { + if (type === "top") { + if ($el.title && $el.title.node()) { + padding += $$.getTitlePadding(); + } + gap = isRotated && !isAxisInner ? axesLen : 0; + } + else if (type === "bottom" && hasAxis && isRotated && !isAxisShow) { + padding += 1; + } + } + return padding + (axisSize * axesLen) - gap; + }, + getCurrentPadding: function () { + var $$ = this; + var _a = ["top", "bottom", "left", "right"] + .map(function (v) { return $$.getCurrentPaddingByDirection(v); }), top = _a[0], bottom = _a[1], left = _a[2], right = _a[3]; + return { top: top, bottom: bottom, left: left, right: right }; + }, + /** + * Get resetted padding values when 'padding=false' option is set + * https://github.com/naver/billboard.js/issues/2367 + * @param {number|object} v Padding values to be resetted + * @returns {number|object} Padding value + * @private + */ + getResettedPadding: function (v) { + var $$ = this; + var config = $$.config; + var isNum = isNumber(v); + var p = isNum ? 0 : {}; + if (config.padding === false) { + !isNum && Object.keys(v).forEach(function (key) { + // when data.lables=true, do not reset top padding + p[key] = (!isEmpty(config.data_labels) && + config.data_labels !== false && + key === "top") ? v[key] : 0; + }); + } + else { + p = v; + } + return p; + }, + /** + * Update size values + * @param {boolean} isInit If is called at initialization + * @private + */ + updateSizes: function (isInit) { + var _a, _b, _c; + var $$ = this; + var config = $$.config, state = $$.state, legend = $$.$el.legend; + var isRotated = config.axis_rotated; + var isNonAxis = $$.hasArcType() || state.hasTreemap; + var isFitPadding = ((_a = config.padding) === null || _a === void 0 ? void 0 : _a.mode) === "fit"; + !isInit && $$.setContainerSize(); + var currLegend = { + width: legend ? $$.getLegendWidth() : 0, + height: legend ? $$.getLegendHeight() : 0 + }; + if (!isNonAxis && config.axis_x_show && config.axis_x_tick_autorotate) { + $$.updateXAxisTickClip(); + } + var legendSize = { + right: config.legend_show && state.isLegendRight ? $$.getLegendWidth() + 20 : 0, + bottom: !config.legend_show || state.isLegendRight || state.isLegendInset ? 0 : currLegend.height + }; + var xAxisHeight = isRotated || isNonAxis ? 0 : $$.getHorizontalAxisHeight("x"); + var subchartXAxisHeight = config.subchart_axis_x_show && config.subchart_axis_x_tick_text_show ? + xAxisHeight : 30; + var subchartHeight = config.subchart_show && !isNonAxis ? + (config.subchart_size_height + subchartXAxisHeight) : 0; + // when needle is shown with legend, it need some bottom space to not overlap with legend text + var gaugeHeight = $$.hasType("gauge") && config.arc_needle_show && + !config.gauge_fullCircle && !config.gauge_label_show ? 10 : 0; + var padding = $$.getCurrentPadding(); + // for main + state.margin = !isNonAxis && isRotated ? { + top: padding.top, + right: isNonAxis ? 0 : padding.right + legendSize.right, + bottom: legendSize.bottom + padding.bottom, + left: subchartHeight + (isNonAxis ? 0 : padding.left) + } : { + top: (isFitPadding ? 0 : 4) + padding.top, + right: isNonAxis ? 0 : padding.right + legendSize.right, + bottom: gaugeHeight + subchartHeight + legendSize.bottom + padding.bottom, + left: isNonAxis ? 0 : padding.left + }; + state.margin = $$.getResettedPadding(state.margin); + // for subchart + state.margin2 = isRotated ? { + top: state.margin.top, + right: NaN, + bottom: 20 + legendSize.bottom, + left: $$.state.rotatedPadding.left + } : { + top: state.current.height - subchartHeight - legendSize.bottom, + right: NaN, + bottom: subchartXAxisHeight + legendSize.bottom, + left: state.margin.left + }; + // for legend + state.margin3 = { + top: 0, + right: NaN, + bottom: 0, + left: 0 + }; + (_b = $$.updateSizeForLegend) === null || _b === void 0 ? void 0 : _b.call($$, currLegend); + state.width = state.current.width - state.margin.left - state.margin.right; + state.height = state.current.height - state.margin.top - state.margin.bottom; + if (state.width < 0) { + state.width = 0; + } + if (state.height < 0) { + state.height = 0; + } + state.width2 = isRotated ? + state.margin.left - state.rotatedPadding.left - state.rotatedPadding.right : state.width; + state.height2 = isRotated ? + state.height : state.current.height - state.margin2.top - state.margin2.bottom; + if (state.width2 < 0) { + state.width2 = 0; + } + if (state.height2 < 0) { + state.height2 = 0; + } + // for arc + if ($$.hasArcType()) { + var hasGauge = $$.hasType("gauge"); + var isLegendRight = config.legend_show && state.isLegendRight; + state.arcWidth = state.width - (isLegendRight ? currLegend.width + 10 : 0); + state.arcHeight = state.height - (isLegendRight && !hasGauge ? 0 : 10); + if (hasGauge && !config.gauge_fullCircle) { + state.arcHeight += state.height - $$.getPaddingBottomForGauge(); + } + (_c = $$.updateRadius) === null || _c === void 0 ? void 0 : _c.call($$); + } + if (state.isLegendRight && isNonAxis) { + state.margin3.left = state.arcWidth / 2 + state.radiusExpanded * 1.1; + } + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var style = { + /** + * Add props color css rule to given selector + * @param {boolean} withShape Set shpes' prefix class + * @param {string} selector CSS selector + * @param {Array} props CSS props list + * @param {Function} propsFn Function to retrieve value or determine for props + * @returns {Function} + * @private + */ + setCssRule: function (withShape, selector, props, propsFn) { + var $$ = this; + var config = $$.config, _a = $$.state, cssRule = _a.cssRule, style = _a.style; + return config.boost_useCssRule ? function (selection) { + selection.each(function (d) { + var res = propsFn && (propsFn === null || propsFn === void 0 ? void 0 : propsFn.call($$, d)); + var shapeSelector = "".concat(withShape ? ".".concat($SHAPE.shapes + $$.getTargetSelectorSuffix(d.id)) : "").concat(selector); + (selector in cssRule) && style.sheet.deleteRule(cssRule[shapeSelector]); + $$.state.cssRule[shapeSelector] = addCssRules(style, shapeSelector, props.filter(Boolean).map(function (v) { return (isString(res) && v.indexOf(":") === -1 ? "".concat(v, ": ").concat(res) : (v || "")); })); + }); + } : function () { }; + }, + /** + * Get style prop value + * @param {Function|string} v Value + * @returns {string|null} + * @private + */ + getStylePropValue: function (v) { + var useCssRule = this.config.boost_useCssRule; + return useCssRule ? null : isFunction(v) ? v.bind(this) : v; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get text-anchor according text.labels.rotate angle + * @param {number} angle Angle value + * @returns {string} Anchor string value + * @private + */ +function getRotateAnchor(angle) { + var anchor = "middle"; + if (angle > 0 && angle <= 170) { + anchor = "end"; + } + else if (angle > 190 && angle <= 360) { + anchor = "start"; + } + return anchor; +} +/** + * Set rotated position coordinate according text.labels.rotate angle + * @param {object} d Data object + * @param {object} pos Position object + * @param {object} pos.x x coordinate + * @param {object} pos.y y coordinate + * @param {string} anchor string value + * @param {boolean} isRotated If axis is rotated + * @param {boolean} isInverted If axis is inverted + * @returns {object} x, y coordinate + * @private + */ +function setRotatePos(d, pos, anchor, isRotated, isInverted) { + var _a; + var $$ = this; + var value = d.value; + var isCandlestickType = $$.isCandlestickType(d); + var isNegative = (isNumber(value) && value < 0) || (isCandlestickType && !((_a = $$.getCandlestickData(d)) === null || _a === void 0 ? void 0 : _a._isUp)); + var x = pos.x, y = pos.y; + var gap = 4; + var doubleGap = gap * 2; + if (isRotated) { + if (anchor === "start") { + x += isNegative ? 0 : doubleGap; + y += gap; + } + else if (anchor === "middle") { + x += doubleGap; + y -= doubleGap; + } + else if (anchor === "end") { + isNegative && (x -= doubleGap); + y += gap; + } + } + else { + if (anchor === "start") { + x += gap; + isNegative && (y += doubleGap * 2); + } + else if (anchor === "middle") { + y -= doubleGap; + } + else if (anchor === "end") { + x -= gap; + isNegative && (y += doubleGap * 2); + } + if (isInverted) { + y += isNegative ? -17 : (isCandlestickType ? 13 : 7); + } + } + return { x: x, y: y }; +} +/** + * Get data.labels.position value + * @param {object} d Data object + * @param {string} type x | y + * @returns {number} Position value + * @private + */ +function getTextPos(d, type) { + var _a; + var position = this.config.data_labels_position; + var id = d.id, index = d.index, value = d.value; + return (_a = (isFunction(position) ? + position.bind(this.api)(type, value, id, index, this.$el.text) : + (id in position ? position[id] : position)[type])) !== null && _a !== void 0 ? _a : 0; +} +var text = { + opacityForText: function (d) { + var $$ = this; + return $$.isBarType(d) && !$$.meetsLabelThreshold(Math.abs($$.getRatio("bar", d)), "bar") ? "0" : ($$.hasDataLabel ? null : "0"); + }, + /** + * Initializes the text + * @private + */ + initText: function () { + var $el = this.$el; + $el.main.select(".".concat($COMMON.chart)).append("g") + .attr("class", $TEXT.chartTexts) + .style("pointer-events", $el.treemap ? "none" : null); + }, + /** + * Update chartText + * @param {object} targets $$.data.targets + * @private + */ + updateTargetsForText: function (targets) { + var $$ = this; + var classChartText = $$.getChartClass("Text"); + var classTexts = $$.getClass("texts", "id"); + var classFocus = $$.classFocus.bind($$); + var mainTextUpdate = $$.$el.main.select(".".concat($TEXT.chartTexts)) + .selectAll(".".concat($TEXT.chartText)) + .data(targets) + .attr("class", function (d) { return "".concat(classChartText(d)).concat(classFocus(d)).trim(); }); + var mainTextEnter = mainTextUpdate.enter().append("g") + .style("opacity", "0") + .attr("class", classChartText) + .call($$.setCssRule(true, " .".concat($TEXT.text), ["fill", "pointer-events:none"], $$.updateTextColor)); + mainTextEnter.append("g") + .attr("class", classTexts); + }, + /** + * Update text + * @private + */ + updateText: function () { + var $$ = this; + var $el = $$.$el, $T = $$.$T, config = $$.config, axis = $$.axis; + var classText = $$.getClass("text", "index"); + var labelsCentered = config.data_labels.centered; + var text = $el.main.selectAll(".".concat($TEXT.texts)) + .selectAll(".".concat($TEXT.text)) + .data($$.labelishData.bind($$)); + $T(text.exit()) + .style("fill-opacity", "0") + .remove(); + $el.text = text.enter() + .append("text") + .merge(text) + .attr("class", classText) + .attr("text-anchor", function (d) { + var isInverted = config["axis_".concat(axis === null || axis === void 0 ? void 0 : axis.getId(d.id), "_inverted")]; + // when value is negative or + var isEndAnchor = isInverted ? d.value > 0 : d.value < 0; + if ($$.isCandlestickType(d)) { + var data = $$.getCandlestickData(d); + isEndAnchor = !(data === null || data === void 0 ? void 0 : data._isUp); + } + else if ($$.isTreemapType(d)) { + return labelsCentered ? "middle" : "start"; + } + return (config.axis_rotated ? (isEndAnchor ? "end" : "start") : "middle"); + }) + .style("fill", $$.getStylePropValue($$.updateTextColor)) + .style("fill-opacity", "0") + .each(function (d, i, texts) { + var node = select(this); + var value = d.value; + if ($$.isBubbleZType(d)) { + value = $$.getBubbleZData(value, "z"); + } + else if ($$.isCandlestickType(d)) { + var data = $$.getCandlestickData(d); + if (data) { + value = data.close; + } + } + value = $$.isTreemapType(d) ? $$.treemapDataLabelFormat(d)(node) : + $$.dataLabelFormat(d.id)(value, d.id, d.index, texts); + if (isNumber(value)) { + this.textContent = value; + } + else { + setTextValue(node, value); + } + }); + }, + updateTextColor: function (d) { + var $$ = this; + var config = $$.config; + var labelColors = config.data_labels_colors; + var defaultColor = ($$.isArcType(d) && !$$.isRadarType(d)) || $$.isTreemapType(d) ? + null : $$.color(d); + var color; + if (isString(labelColors)) { + color = labelColors; + } + else if (isObject(labelColors)) { + var id = (d.data || d).id; + color = labelColors[id]; + } + else if (isFunction(labelColors)) { + color = labelColors.bind($$.api)(defaultColor, d); + } + if ($$.isCandlestickType(d) && !isFunction(labelColors)) { + var value = $$.getCandlestickData(d); + if (!(value === null || value === void 0 ? void 0 : value._isUp)) { + var downColor = config.candlestick_color_down; + color = isObject(downColor) ? downColor[d.id] : downColor; + } + } + return color || defaultColor; + }, + /** + * Update data label text background color + * @param {object} d Data object + * @returns {string|null} + * @private + */ + updateTextBacgroundColor: function (d) { + var $$ = this; + var $el = $$.$el, config = $$.config; + var backgroundColor = config.data_labels_backgroundColors; + var color = ""; + if (isString(backgroundColor) || isObject(backgroundColor)) { + var id = isString(backgroundColor) ? "" : $$.getTargetSelectorSuffix(("id" in d ? d.id : d.data.id)); + var filter = $el.defs.select(["filter[id*='labels-bg", "']"].join(id)); + if (filter.size()) { + color = "url(#".concat(filter.attr("id"), ")"); + } + } + return color || null; + }, + /** + * Redraw chartText + * @param {Function} getX Positioning function for x + * @param {Function} getY Positioning function for y + * @param {boolean} forFlow Weather is flow + * @param {boolean} withTransition transition is enabled + * @returns {Array} + * @private + */ + redrawText: function (getX, getY, forFlow, withTransition) { + var $$ = this; + var $T = $$.$T, axis = $$.axis, config = $$.config, hasTreemap = $$.state.hasTreemap; + var t = getRandom(true); + var isRotated = config.axis_rotated; + var angle = config.data_labels.rotate; + var anchorString = getRotateAnchor(angle); + var rotateString = angle ? "rotate(".concat(angle, ")") : ""; + $$.$el.text + .style("fill", $$.getStylePropValue($$.updateTextColor)) + .attr("filter", $$.updateTextBacgroundColor.bind($$)) + .style("fill-opacity", forFlow ? 0 : $$.opacityForText.bind($$)) + .each(function (d, i) { + // do not apply transition for newly added text elements + var node = $T(hasTreemap && this.childElementCount ? this.parentNode : this, !!(withTransition && this.getAttribute("x")), t); + var isInverted = config["axis_".concat(axis === null || axis === void 0 ? void 0 : axis.getId(d.id), "_inverted")]; + var pos = { + x: getX.bind(this)(d, i), + y: getY.bind(this)(d, i) + }; + if (angle) { + pos = setRotatePos.bind($$)(d, pos, anchorString, isRotated, isInverted); + node.attr("text-anchor", anchorString); + } + // when is multiline + if (this.childElementCount || angle) { + node.attr("transform", "translate(".concat(pos.x, " ").concat(pos.y, ") ").concat(rotateString)); + } + else { + node.attr("x", pos.x).attr("y", pos.y); + } + }); + // need to return 'true' as of being pushed to the redraw list + // ref: getRedrawList() + return true; + }, + /** + * Gets the getBoundingClientRect value of the element + * @param {HTMLElement|d3.selection} element Target element + * @param {string} className Class name + * @returns {object} value of element.getBoundingClientRect() + * @private + */ + getTextRect: function (element, className) { + var $$ = this; + var base = (element.node ? element.node() : element); + if (!/text/i.test(base.tagName)) { + base = base.querySelector("text"); + } + var text = base.textContent; + var cacheKey = "".concat(KEY.textRect, "-").concat(text.replace(/\W/g, "_")); + var rect = $$.cache.get(cacheKey); + if (!rect) { + $$.$el.svg.append("text") + .style("visibility", "hidden") + .style("font", select(base).style("font")) + .classed(className, true) + .text(text) + .call(function (v) { + rect = getBoundingRect(v.node()); + }) + .remove(); + $$.cache.add(cacheKey, rect); + } + return rect; + }, + /** + * Gets the x or y coordinate of the text + * @param {object} indices Indices values + * @param {boolean} forX whether or not to x + * @returns {number} coordinates + * @private + */ + generateXYForText: function (indices, forX) { + var $$ = this; + var _a = $$.state, hasRadar = _a.hasRadar, hasTreemap = _a.hasTreemap; + var types = Object.keys(indices); + var points = {}; + var getter = forX ? $$.getXForText : $$.getYForText; + hasRadar && types.push("radar"); + hasTreemap && types.push("treemap"); + types.forEach(function (v) { + points[v] = $$["generateGet".concat(capitalize(v), "Points")](indices[v], false); + }); + return function (d, i) { + var type = ($$.isAreaType(d) && "area") || + ($$.isBarType(d) && "bar") || + ($$.isCandlestickType(d) && "candlestick") || + ($$.isRadarType(d) && "radar") || + ($$.isTreemapType(d) && "treemap") || "line"; + return getter.call($$, points[type](d, i), d, this); + }; + }, + /** + * Get centerized text position for bar type data.label.text + * @param {object} d Data object + * @param {Array} points Data points position + * @param {HTMLElement} textElement Data label text element + * @param {string} type 'x' or 'y' + * @returns {number} Position value + * @private + */ + getCenteredTextPos: function (d, points, textElement, type) { + var $$ = this; + var config = $$.config; + var isRotated = config.axis_rotated; + var isBarType = $$.isBarType(d); + var isTreemapType = $$.isTreemapType(d); + if (config.data_labels.centered && (isBarType || isTreemapType)) { + var rect = getBoundingRect(textElement); + if (isBarType) { + var isPositive = d.value >= 0; + if (isRotated) { + var w = (isPositive ? + points[1][1] - points[0][1] : + points[0][1] - points[1][1]) / 2 + (rect.width / 2); + return isPositive ? -w - 3 : w + 2; + } + else { + var h = (isPositive ? + points[0][1] - points[1][1] : + points[1][1] - points[0][1]) / 2 + (rect.height / 2); + return isPositive ? h : -h - 2; + } + } + else if (isTreemapType) { + return type === "x" ? + (points[1][0] - points[0][0]) / 2 : + (points[1][1] - points[0][1]) / 2 + (rect.height / 2); + } + } + return 0; + }, + /** + * Gets the x coordinate of the text + * @param {object} points Data points position + * @param {object} d Data object + * @param {HTMLElement} textElement Data label text element + * @returns {number} x coordinate + * @private + */ + getXForText: function (points, d, textElement) { + var _a; + var $$ = this; + var config = $$.config; + var isRotated = config.axis_rotated; + var isTreemapType = $$.isTreemapType(d); + var xPos = points[0][0]; + if ($$.isCandlestickType(d)) { + if (isRotated) { + xPos = ((_a = $$.getCandlestickData(d)) === null || _a === void 0 ? void 0 : _a._isUp) ? + points[2][2] + 4 : points[2][1] - 4; + } + else { + xPos += (points[1][0] - xPos) / 2; + } + } + else if (isTreemapType) { + xPos += config.data_labels.centered ? 0 : 5; + } + else { + if (isRotated) { + var isInverted = config["axis_".concat($$.axis.getId(d.id), "_inverted")]; + var padding = $$.isBarType(d) ? 4 : 6; + var value = d.value; + xPos = points[2][1]; + if (isInverted) { + xPos -= padding * (value > 0 ? 1 : -1); + } + else { + xPos += padding * (value < 0 ? -1 : 1); + } + } + else { + xPos = $$.hasType("bar") ? (points[2][0] + points[0][0]) / 2 : xPos; + } + } + if (isRotated || isTreemapType) { + xPos += $$.getCenteredTextPos(d, points, textElement, "x"); + } + return xPos + getTextPos.call(this, d, "x"); + }, + /** + * Gets the y coordinate of the text + * @param {object} points Data points position + * @param {object} d Data object + * @param {HTMLElement} textElement Data label text element + * @returns {number} y coordinate + * @private + */ + getYForText: function (points, d, textElement) { + var $$ = this; + var axis = $$.axis, config = $$.config, state = $$.state; + var isRotated = config.axis_rotated; + var isInverted = config["axis_".concat(axis === null || axis === void 0 ? void 0 : axis.getId(d.id), "_inverted")]; + var isBarType = $$.isBarType(d); + var isTreemapType = $$.isTreemapType(d); + var r = config.point_r; + var rect = getBoundingRect(textElement); + var value = d.value; + var baseY = 3; + var yPos; + if ($$.isCandlestickType(d)) { + value = $$.getCandlestickData(d); + if (isRotated) { + yPos = points[0][0]; + yPos += ((points[1][0] - yPos) / 2) + baseY; + } + else { + yPos = value && value._isUp ? + points[2][2] - baseY : + points[2][1] + (baseY * 4); + if (isInverted) { + yPos += 15 * (value._isUp ? 1 : -1); + } + } + } + else if (isTreemapType) { + yPos = points[0][1] + (config.data_labels.centered ? 0 : rect.height + 5); + } + else { + if (isRotated) { + yPos = (points[0][0] + points[2][0] + rect.height * 0.6) / 2; + } + else { + yPos = points[2][1]; + if (isNumber(r) && r > 5 && ($$.isLineType(d) || $$.isScatterType(d))) { + baseY += config.point_r / 2.3; + } + if (value < 0 || (value === 0 && !state.hasPositiveValue && state.hasNegativeValue)) { + yPos += isInverted ? (isBarType ? -3 : -5) : (rect.height + (isBarType ? -baseY : baseY)); + } + else { + var diff = -baseY * 2; + if (isBarType) { + diff = -baseY; + } + else if ($$.isBubbleType(d)) { + diff = baseY; + } + if (isInverted) { + diff = isBarType ? 10 : 15; + } + yPos += diff; + } + } + } + if (!isRotated || isTreemapType) { + yPos += $$.getCenteredTextPos(d, points, textElement, "y"); + } + return yPos + getTextPos.call(this, d, "y"); + }, + /** + * Calculate if two or more text nodes are overlapping + * Mark overlapping text nodes with "text-overlapping" class + * @param {string} id Axis id + * @param {ChartInternal} $$ ChartInternal context + * @param {string} selector Selector string + * @private + */ + markOverlapped: function (id, $$, selector) { + var textNodes = $$.$el.arcs.selectAll(selector); + var filteredTextNodes = textNodes.filter(function (node) { return node.data.id !== id; }); + var textNode = textNodes.filter(function (node) { return node.data.id === id; }); + var translate = getTranslation(textNode.node()); + // Calculates the length of the hypotenuse + var calcHypo = function (x, y) { return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); }; + textNode.node() && filteredTextNodes.each(function () { + var coordinate = getTranslation(this); + var filteredTextNode = select(this); + var nodeForWidth = calcHypo(translate.e, translate.f) > calcHypo(coordinate.e, coordinate.f) ? + textNode : filteredTextNode; + var overlapsX = Math.ceil(Math.abs(translate.e - coordinate.e)) < + Math.ceil(nodeForWidth.node().getComputedTextLength()); + var overlapsY = Math.ceil(Math.abs(translate.f - coordinate.f)) < + parseInt(textNode.style("font-size"), 10); + filteredTextNode.classed($TEXT.TextOverlapping, overlapsX && overlapsY); + }); + }, + /** + * Calculate if two or more text nodes are overlapping + * Remove "text-overlapping" class on selected text nodes + * @param {ChartInternal} $$ ChartInternal context + * @param {string} selector Selector string + * @private + */ + undoMarkOverlapped: function ($$, selector) { + $$.$el.arcs.selectAll(selector) + .each(function () { + selectAll([this, this.previousSibling]) + .classed($TEXT.TextOverlapping, false); + }); + }, + /** + * Check if meets the ratio to show data label text + * @param {number} ratio ratio to meet + * @param {string} type chart type + * @returns {boolean} + * @private + */ + meetsLabelThreshold: function (ratio, type) { + if (ratio === void 0) { ratio = 0; } + var $$ = this; + var config = $$.config; + var threshold = config["".concat(type, "_label_threshold")] || 0; + return ratio >= threshold; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Get the text position + * @param {string} pos right, left or center + * @param {number} width chart width + * @returns {string|number} text-anchor value or position in pixel + * @private + */ +function getTextXPos(pos, width) { + if (pos === void 0) { pos = "left"; } + var isNum = isNumber(width); + var position; + if (pos.indexOf("center") > -1) { + position = isNum ? width / 2 : "middle"; + } + else if (pos.indexOf("right") > -1) { + position = isNum ? width : "end"; + } + else { + position = isNum ? 0 : "start"; + } + return position; +} +var title = { + /** + * Initializes the title + * @private + */ + initTitle: function () { + var $$ = this; + var config = $$.config, $el = $$.$el; + if (config.title_text) { + $el.title = $el.svg.append("g"); + var text = $el.title + .append("text") + .style("text-anchor", getTextXPos(config.title_position)) + .attr("class", $TEXT.title); + setTextValue(text, config.title_text, [0.3, 1.5]); + } + }, + /** + * Redraw title + * @private + */ + redrawTitle: function () { + var $$ = this; + var config = $$.config, current = $$.state.current, title = $$.$el.title; + if (title) { + var x = getTextXPos(config.title_position, current.width); + var y = (config.title_padding.top || 0) + + $$.getTextRect($$.$el.title, $TEXT.title).height; + title.attr("transform", "translate(".concat(x, ", ").concat(y, ")")); + } + }, + /** + * Get title padding + * @returns {number} padding value + * @private + */ + getTitlePadding: function () { + var $$ = this; + var $el = $$.$el, config = $$.config; + return (config.title_padding.top || 0) + + $$.getTextRect($el.title, $TEXT.title).height + + (config.title_padding.bottom || 0); + }, +}; + +var tooltip$1 = { + /** + * Initializes the tooltip + * @private + */ + initTooltip: function () { + var $$ = this; + var config = $$.config, $el = $$.$el; + $el.tooltip = select(config.tooltip_contents.bindto); + if ($el.tooltip.empty()) { + $el.tooltip = $el.chart + .append("div") + .attr("class", $TOOLTIP.tooltipContainer) + .style("position", "absolute") + .style("pointer-events", "none") + .style("display", "none"); + } + $$.bindTooltipResizePos(); + }, + /** + * Show tooltip at initialization. + * Is called only when tooltip.init.show=true option is set + * @private + */ + initShowTooltip: function () { + var _a; + var _b; + var $$ = this; + var config = $$.config, $el = $$.$el, _c = $$.state, hasAxis = _c.hasAxis, hasRadar = _c.hasRadar; + // Show tooltip if needed + if (config.tooltip_init_show) { + var isArc = !(hasAxis || hasRadar); + if (((_b = $$.axis) === null || _b === void 0 ? void 0 : _b.isTimeSeries()) && isString(config.tooltip_init_x)) { + config.tooltip_init_x = parseDate.call($$, config.tooltip_init_x); + } + $$.api.tooltip.show({ + data: (_a = {}, + _a[isArc ? "index" : "x"] = config.tooltip_init_x, + _a) + }); + var position = config.tooltip_init_position; + if (!config.tooltip_contents.bindto && !isEmpty(position)) { + var _d = position.top, top_1 = _d === void 0 ? 0 : _d, _e = position.left, left = _e === void 0 ? 50 : _e; + $el.tooltip.style("top", isString(top_1) ? top_1 : "".concat(top_1, "px")) + .style("left", isString(left) ? left : "".concat(left, "px")) + .style("display", null); + } + } + }, + /** + * Get the tooltip HTML string + * @param {Array} args Arguments + * @returns {string} Formatted HTML string + * @private + */ + getTooltipHTML: function () { + var args = []; + for (var _i = 0; _i < arguments.length; _i++) { + args[_i] = arguments[_i]; + } + var $$ = this; + var api = $$.api, config = $$.config; + return isFunction(config.tooltip_contents) ? config.tooltip_contents.bind(api).apply(void 0, args) : $$.getTooltipContent.apply($$, args); + }, + /** + * Returns the tooltip content(HTML string) + * @param {object} d data + * @param {Function} defaultTitleFormat Default title format + * @param {Function} defaultValueFormat Default format for each data value in the tooltip. + * @param {Function} color Color function + * @returns {string} html + * @private + */ + getTooltipContent: function (d, defaultTitleFormat, defaultValueFormat, color) { + var $$ = this; + var api = $$.api, config = $$.config, state = $$.state, $el = $$.$el; + // get formatter function + var _a = ["title", "name", "value"].map(function (v) { + var fn = config["tooltip_format_".concat(v)]; + return isFunction(fn) ? fn.bind(api) : fn; + }), titleFn = _a[0], nameFn = _a[1], valueFn = _a[2]; + // determine fotmatter function with sanitization + var titleFormat = function () { + var arg = []; + for (var _i = 0; _i < arguments.length; _i++) { + arg[_i] = arguments[_i]; + } + return sanitize((titleFn || defaultTitleFormat).apply(void 0, arg)); + }; + var nameFormat = function () { + var arg = []; + for (var _i = 0; _i < arguments.length; _i++) { + arg[_i] = arguments[_i]; + } + return sanitize((nameFn || (function (name) { return name; })).apply(void 0, arg)); + }; + var valueFormat = function () { + var arg = []; + for (var _i = 0; _i < arguments.length; _i++) { + arg[_i] = arguments[_i]; + } + var fn = valueFn || (state.hasTreemap || $$.isStackNormalized() ? function (v, ratio) { return "".concat((ratio * 100).toFixed(2), "%"); } : defaultValueFormat); + return sanitize(fn.apply(void 0, arg)); + }; + var order = config.tooltip_order; + var getRowValue = function (row) { return ($$.axis && $$.isBubbleZType(row) ? $$.getBubbleZData(row.value, "z") : $$.getBaseValue(row)); }; + var getBgColor = $$.levelColor ? function (row) { return $$.levelColor(row.value); } : function (row) { return color(row); }; + var contents = config.tooltip_contents; + var tplStr = contents.template; + var targetIds = $$.mapToTargetIds(); + if (order === null && config.data_groups.length) { + // for stacked data, order should aligned with the visually displayed data + var ids_1 = $$.orderTargets($$.data.targets) + .map(function (i2) { return i2.id; }) + .reverse(); + d.sort(function (a, b) { + var v1 = a ? a.value : null; + var v2 = b ? b.value : null; + if (v1 > 0 && v2 > 0) { + v1 = a.id ? ids_1.indexOf(a.id) : null; + v2 = b.id ? ids_1.indexOf(b.id) : null; + } + return v1 - v2; + }); + } + else if (/^(asc|desc)$/.test(order)) { + var isAscending_1 = order === "asc"; + d.sort(function (a, b) { + var v1 = a ? getRowValue(a) : null; + var v2 = b ? getRowValue(b) : null; + return isAscending_1 ? v1 - v2 : v2 - v1; + }); + } + else if (isFunction(order)) { + d.sort(order.bind(api)); + } + var tpl = $$.getTooltipContentTemplate(tplStr); + var len = d.length; + var text; + var row; + var param; + var value; + var i; + var _loop_1 = function () { + row = d[i]; + if (!row || !(getRowValue(row) || getRowValue(row) === 0)) { + return "continue"; + } + if (isUndefined(text)) { + var title = (state.hasAxis || state.hasRadar) && titleFormat(row.x); + text = tplProcess(tpl[0], { + CLASS_TOOLTIP: $TOOLTIP.tooltip, + TITLE: isValue(title) ? (tplStr ? title : "".concat(title, "")) : "" + }); + } + if (!row.ratio && $el.arcs) { + param = ["arc", $$.$el.arcs.select("path.".concat($ARC.arc, "-").concat(row.id)).data()[0]]; + row.ratio = $$.getRatio.apply($$, param); + } + // arrange param to be passed to formatter + param = [row.ratio, row.id, row.index]; + if ($$.isAreaRangeType(row)) { + var _b = ["high", "low"].map(function (v) { return valueFormat.apply(void 0, __spreadArray([$$.getRangedData(row, v)], param, false)); }), high = _b[0], low = _b[1]; + var mid = valueFormat.apply(void 0, __spreadArray([getRowValue(row)], param, false)); + value = "Mid: ".concat(mid, " High: ").concat(high, " Low: ").concat(low); + } + else if ($$.isCandlestickType(row)) { + var _c = ["open", "high", "low", "close", "volume"].map(function (v) { + var value = $$.getRangedData(row, v, "candlestick"); + return value ? valueFormat.apply(void 0, __spreadArray([$$.getRangedData(row, v, "candlestick")], param, false)) : undefined; + }), open_1 = _c[0], high = _c[1], low = _c[2], close_1 = _c[3], volume = _c[4]; + value = "Open: ".concat(open_1, " High: ").concat(high, " Low: ").concat(low, " Close: ").concat(close_1).concat(volume ? " Volume: ".concat(volume) : ""); + } + else if ($$.isBarRangeType(row)) { + var _d = row.value, start = _d[0], end = _d[1], id = row.id, index = row.index; + value = "".concat(valueFormat(start, undefined, id, index), " ~ ").concat(valueFormat(end, undefined, id, index)); + } + else { + value = valueFormat.apply(void 0, __spreadArray([getRowValue(row)], param, false)); + } + if (value !== undefined) { + // Skip elements when their name is set to null + if (row.name === null) { + return "continue"; + } + var name_1 = nameFormat.apply(void 0, __spreadArray([row.name], param, false)); + var color_1 = getBgColor(row); + var contentValue_1 = { + CLASS_TOOLTIP_NAME: $TOOLTIP.tooltipName + $$.getTargetSelectorSuffix(row.id), + COLOR: (tplStr || !$$.patterns) ? color_1 : ""), + NAME: name_1, + VALUE: value + }; + if (tplStr && isObject(contents.text)) { + var index_1 = targetIds.indexOf(row.id); + Object.keys(contents.text).forEach(function (key) { + contentValue_1[key] = contents.text[key][index_1]; + }); + } + text += tplProcess(tpl[1], contentValue_1); + } + }; + for (i = 0; i < len; i++) { + _loop_1(); + } + return "".concat(text, ""); + }, + /** + * Get the content template string + * @param {string} tplStr Tempalte string + * @returns {Array} Template string + * @private + */ + getTooltipContentTemplate: function (tplStr) { + return (tplStr || "\n\t\t\t\t{=TITLE}\n\t\t\t\t{{\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t}}\n\t\t\t
    ".concat(this.patterns ? "{=COLOR}" : "", "{=NAME}{=VALUE}
    ")) + .replace(/(\r?\n|\t)/g, "") + .split(/{{(.*)}}/); + }, + /** + * Update tooltip position coordinate + * @param {object} dataToShow Data object + * @param {SVGElement} eventTarget Event element + * @private + */ + setTooltipPosition: function (dataToShow, eventTarget) { + var _a, _b; + var $$ = this; + var config = $$.config, scale = $$.scale, state = $$.state, _c = $$.$el, eventRect = _c.eventRect, tooltip = _c.tooltip; + var bindto = config.tooltip_contents.bindto; + var isRotated = config.axis_rotated; + var datum = tooltip === null || tooltip === void 0 ? void 0 : tooltip.datum(); + if (!bindto && datum) { + var data = dataToShow !== null && dataToShow !== void 0 ? dataToShow : JSON.parse(datum.current); + var _d = getPointer(state.event, eventTarget !== null && eventTarget !== void 0 ? eventTarget : eventRect === null || eventRect === void 0 ? void 0 : eventRect.node()), x = _d[0], y = _d[1]; // get mouse event position + var currPos = { x: x, y: y }; + if (state.hasAxis && scale.x && datum && "x" in datum) { + var getYPos = function (value, id, axisId) { + var _a; + if (value === void 0) { value = 0; } + if (axisId === void 0) { axisId = "y"; } + var scaleFn = scale[id ? (_a = $$.axis) === null || _a === void 0 ? void 0 : _a.getId(id) : axisId]; + return scaleFn ? scaleFn(value) + (isRotated ? state.margin.left : state.margin.top) : 0; + }; + currPos.xAxis = scale.x(datum.x) + ( + // add margin only when user specified tooltip.position function + config.tooltip_position ? (isRotated ? state.margin.top : state.margin.left) : 0); + if (data.length === 1) { + currPos.yAxis = getYPos(data[0].value, data[0].id); + } + else { + currPos.yAxis = getYPos; + } + } + var _e = datum.width, width = _e === void 0 ? 0 : _e, _f = datum.height, height = _f === void 0 ? 0 : _f; + // Get tooltip position + var pos_1 = (_b = (_a = config.tooltip_position) === null || _a === void 0 ? void 0 : _a.bind($$.api)(data, width, height, eventRect === null || eventRect === void 0 ? void 0 : eventRect.node(), currPos)) !== null && _b !== void 0 ? _b : $$.getTooltipPosition.bind($$)(width, height, currPos); + ["top", "left"].forEach(function (v) { + var value = pos_1[v]; + tooltip.style(v, "".concat(value, "px")); + // Remember left pos in percentage to be used on resize call + if (v === "left" && !datum.xPosInPercent) { + datum.xPosInPercent = value / state.current.width * 100; + } + }); + } + }, + /** + * Returns the position of the tooltip + * @param {string} tWidth Width value of tooltip element + * @param {string} tHeight Height value of tooltip element + * @param {object} currPos Current mouse position + * @returns {object} top, left value + * @private + */ + getTooltipPosition: function (tWidth, tHeight, currPos) { + var $$ = this; + var config = $$.config, scale = $$.scale, state = $$.state; + var width = state.width, height = state.height, current = state.current, isLegendRight = state.isLegendRight, inputType = state.inputType; + var hasGauge = $$.hasType("gauge") && !config.gauge_fullCircle; + var hasTreemap = state.hasTreemap; + var isRotated = config.axis_rotated; + var hasArcType = $$.hasArcType(); + var svgLeft = $$.getSvgLeft(true); + var chartRight = svgLeft + current.width - $$.getCurrentPaddingByDirection("right"); + var size = 20; + var x = currPos.x, y = currPos.y; + // Determine tooltip position + if (hasArcType) { + var raw = inputType === "touch" || $$.hasType("radar"); + if (!raw) { + x += (width - (isLegendRight ? $$.getLegendWidth() : 0)) / 2; + y += hasGauge ? height : height / 2; + } + } + else if (!hasTreemap) { + var padding = { + top: $$.getCurrentPaddingByDirection("top", true), + left: $$.getCurrentPaddingByDirection("left", true) + }; + if (isRotated) { + x += svgLeft + padding.left + size; + y = padding.top + currPos.xAxis + size; + chartRight -= svgLeft; + } + else { + x = svgLeft + padding.left + size + (scale.zoom ? x : currPos.xAxis); + y += padding.top - 5; + } + } + // when tooltip left + tWidth > chart's width + if ((x + tWidth + 15) > chartRight) { + x -= tWidth + (hasTreemap || hasArcType ? 0 : (isRotated ? size * 2 : 38)); + } + if (y + tHeight > current.height) { + var gap = hasTreemap ? 0 : 30; + y -= hasGauge ? tHeight * 3 : tHeight + gap; + } + var pos = { top: y, left: x }; + // make sure to not be positioned out of viewport + Object.keys(pos).forEach(function (v) { + if (pos[v] < 0) { + pos[v] = 0; + } + }); + return pos; + }, + /** + * Show the tooltip + * @param {object} selectedData Data object + * @param {SVGElement} eventTarget Event element + * @private + */ + showTooltip: function (selectedData, eventTarget) { + var $$ = this; + var config = $$.config, tooltip = $$.$el.tooltip; + var dataToShow = selectedData.filter(function (d) { return d && isValue($$.getBaseValue(d)); }); + if (!tooltip || dataToShow.length === 0 || !config.tooltip_show) { + return; + } + var datum = tooltip.datum(); + var dataStr = JSON.stringify(selectedData); + if (!datum || datum.current !== dataStr) { + var _a = selectedData.concat().sort()[0], index = _a.index, x = _a.x; + callFn(config.tooltip_onshow, $$.api, selectedData); + // set tooltip content + tooltip + .html($$.getTooltipHTML(selectedData, // data + $$.axis ? $$.axis.getXAxisTickFormat() : $$.categoryName.bind($$), // defaultTitleFormat + $$.getDefaultValueFormat(), // defaultValueFormat + $$.color // color + )) + .style("display", null) + .style("visibility", null) // for IE9 + .datum(datum = { + index: index, + x: x, + current: dataStr, + width: tooltip.property("offsetWidth"), + height: tooltip.property("offsetHeight") + }); + callFn(config.tooltip_onshown, $$.api, selectedData); + $$._handleLinkedCharts(true, index); + } + $$.setTooltipPosition(dataToShow, eventTarget); + }, + /** + * Adjust tooltip position on resize event + * @private + */ + bindTooltipResizePos: function () { + var $$ = this; + var resizeFunction = $$.resizeFunction, state = $$.state, tooltip = $$.$el.tooltip; + resizeFunction.add(function () { + if (tooltip.style("display") === "block") { + var current = state.current; + var _a = tooltip.datum(), width = _a.width, xPosInPercent = _a.xPosInPercent; + var value = current.width / 100 * xPosInPercent; + var diff = current.width - (value + width); + // if tooltip size overs current viewport size + if (diff < 0) { + value += diff; + } + tooltip.style("left", "".concat(value, "px")); + } + }); + }, + /** + * Hide the tooltip + * @param {boolean} force Force to hide + * @private + */ + hideTooltip: function (force) { + var _a; + var $$ = this; + var api = $$.api, config = $$.config, tooltip = $$.$el.tooltip; + if (tooltip && tooltip.style("display") !== "none" && (!config.tooltip_doNotHide || force)) { + var selectedData = JSON.parse((_a = tooltip.datum().current) !== null && _a !== void 0 ? _a : {}); + callFn(config.tooltip_onhide, api, selectedData); + // hide tooltip + tooltip + .style("display", "none") + .style("visibility", "hidden") // for IE9 + .datum(null); + callFn(config.tooltip_onhidden, api, selectedData); + } + }, + /** + * Toggle display for linked chart instances + * @param {boolean} show true: show, false: hide + * @param {number} index x Axis index + * @private + */ + _handleLinkedCharts: function (show, index) { + var $$ = this; + var charts = $$.charts, config = $$.config, event = $$.state.event; + // Prevent propagation among instances if isn't instantiated from the user's event + // https://github.com/naver/billboard.js/issues/1979 + if ((event === null || event === void 0 ? void 0 : event.isTrusted) && config.tooltip_linked && charts.length > 1) { + var linkedName_1 = config.tooltip_linked_name; + charts + .filter(function (c) { return c !== $$.api; }) + .forEach(function (c) { + var _a = c.internal, config = _a.config, $el = _a.$el; + var isLinked = config.tooltip_linked; + var name = config.tooltip_linked_name; + var isInDom = doc.body.contains($el.chart.node()); + if (isLinked && linkedName_1 === name && isInDom) { + var data = $el.tooltip.data()[0]; + var isNotSameIndex = index !== (data === null || data === void 0 ? void 0 : data.index); + try { + c.tooltip[show && isNotSameIndex ? "show" : "hide"]({ index: index }); + } + catch (e) { } + } + }); + } + }, + /** + * Update tooltip content on redraw + * - In a situation where tooltip is displayed and data load happens, it should reflect loaded data to tooltip + * @param {d3Selection} context Event rect element + * @param {number} index Data index + * @private + */ + updateTooltipOnRedraw: function (context, index) { + var _a; + var $$ = this; + var config = $$.config, _b = $$.$el, eventRect = _b.eventRect, svg = _b.svg, tooltip = _b.tooltip, _c = $$.state, event = _c.event, hasAxis = _c.hasAxis, hasRadar = _c.hasRadar, hasTreemap = _c.hasTreemap; + // Update tooltip, when tooltip is in shown state + if ((tooltip === null || tooltip === void 0 ? void 0 : tooltip.style("display")) === "block" && event) { + var rect = context !== null && context !== void 0 ? context : (_a = (hasRadar ? svg : eventRect)) === null || _a === void 0 ? void 0 : _a.node(); + // for Axis based & Radar + if (hasAxis || hasRadar) { + if ($$.isMultipleX()) { + $$.selectRectForMultipleXs(rect, false); + } + else { + var idx = index !== null && index !== void 0 ? index : $$.getDataIndexFromEvent(event); + if (index === -1) { + $$.api.tooltip.hide(); + } + else { + $$.selectRectForSingle(rect, idx); + $$.setExpand(idx, null, true); + } + } + // for Arc & Treemap + } + else { + var clientX_1 = event.clientX, clientY_1 = event.clientY; + setTimeout(function () { + var target = doc.elementFromPoint(clientX_1, clientY_1); + var data = select(target).datum(); + if (data) { + var d = $$.hasArcType() ? + $$.convertToArcData($$.updateAngle(data)) : data === null || data === void 0 ? void 0 : data.data; + hasTreemap && (target = svg.node()); + d && $$.showTooltip([d], target); + } + else { + $$.api.tooltip.hide(); + } + }, config.transition_duration); + } + } + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var transform = { + getTranslate: function (target, index) { + if (index === void 0) { index = 0; } + var $$ = this; + var config = $$.config, state = $$.state; + var isRotated = config.axis_rotated; + var padding = 0; + var x; + var y; + if (index && /^(x|y2?)$/.test(target)) { + padding = $$.getAxisSize(target) * index; + } + if (target === "main") { + x = asHalfPixel(state.margin.left); + y = asHalfPixel(state.margin.top); + } + else if (target === "context") { + x = asHalfPixel(state.margin2.left); + y = asHalfPixel(state.margin2.top); + } + else if (target === "legend") { + x = state.margin3.left; + y = state.margin3.top; + } + else if (target === "x") { + x = isRotated ? -padding : 0; + y = isRotated ? 0 : state.height + padding; + } + else if (target === "y") { + x = isRotated ? 0 : -padding; + y = isRotated ? state.height + padding : 0; + } + else if (target === "y2") { + x = isRotated ? 0 : state.width + padding; + y = isRotated ? 1 - padding : 0; + } + else if (target === "subX") { + x = 0; + y = isRotated ? 0 : state.height2; + } + else if (target === "arc") { + x = state.arcWidth / 2; + y = state.arcHeight / 2; + } + else if (target === "polar") { + x = state.arcWidth / 2; + y = state.arcHeight / 2; + } + else if (target === "radar") { + var width = $$.getRadarSize()[0]; + x = state.width / 2 - width; + y = asHalfPixel(state.margin.top); + } + return "translate(".concat(x, ", ").concat(y, ")"); + }, + transformMain: function (withTransition, transitions) { + var $$ = this; + var main = $$.$el.main, $T = $$.$T; + var xAxis = (transitions === null || transitions === void 0 ? void 0 : transitions.axisX) ? + transitions.axisX : + $T(main.select(".".concat($AXIS.axisX)), withTransition); + var yAxis = (transitions === null || transitions === void 0 ? void 0 : transitions.axisY) ? + transitions.axisY : + $T(main.select(".".concat($AXIS.axisY)), withTransition); + var y2Axis = (transitions === null || transitions === void 0 ? void 0 : transitions.axisY2) ? + transitions.axisY2 : + $T(main.select(".".concat($AXIS.axisY2)), withTransition); + $T(main, withTransition) + .attr("transform", $$.getTranslate("main")); + xAxis.attr("transform", $$.getTranslate("x")); + yAxis.attr("transform", $$.getTranslate("y")); + y2Axis.attr("transform", $$.getTranslate("y2")); + main.select(".".concat($ARC.chartArcs)) + .attr("transform", $$.getTranslate("arc")); + }, + transformAll: function (withTransition, transitions) { + var $$ = this; + var config = $$.config, _a = $$.state, hasAxis = _a.hasAxis, hasTreemap = _a.hasTreemap, $el = $$.$el; + !hasTreemap && $$.transformMain(withTransition, transitions); + hasAxis && config.subchart_show && + $$.transformContext(withTransition, transitions); + $el.legend && $$.transformLegend(withTransition); + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var typeInternals = { + /** + * Check if the given chart type is valid + * @param {string} type Chart type string + * @returns {boolean} + * @private + */ + isValidChartType: function (type) { + return !!(type && Object.values(TYPE).indexOf(type) > -1); + }, + setTargetType: function (targetIds, type) { + var $$ = this; + var config = $$.config, withoutFadeIn = $$.state.withoutFadeIn; + $$.mapToTargetIds(targetIds).forEach(function (id) { + withoutFadeIn[id] = (type === config.data_types[id]); + config.data_types[id] = type; + }); + if (!targetIds) { + config.data_type = type; + } + }, + /** + * Updte current used chart types + * @private + */ + updateTypesElements: function () { + var $$ = this; + var current = $$.state.current; + Object.keys(TYPE).forEach(function (v) { + var t = TYPE[v]; + var has = $$.hasType(t, null, true); + var idx = current.types.indexOf(t); + if (idx === -1 && has) { + current.types.push(t); + } + else if (idx > -1 && !has) { + current.types.splice(idx, 1); + } + }); + // Update current chart elements reference + $$.setChartElements(); + }, + /** + * Check if given chart types exists + * @param {string} type Chart type + * @param {Array} targetsValue Data array + * @param {boolean} checkFromData Force to check type cotains from data targets + * @returns {boolean} + * @private + */ + hasType: function (type, targetsValue, checkFromData) { + var _a; + if (checkFromData === void 0) { checkFromData = false; } + var $$ = this; + var config = $$.config, current = $$.state.current; + var types = config.data_types; + var targets = targetsValue || $$.data.targets; + var has = false; + if (!checkFromData && ((_a = current.types) === null || _a === void 0 ? void 0 : _a.indexOf(type)) > -1) { + has = true; + } + else if (targets === null || targets === void 0 ? void 0 : targets.length) { + targets.forEach(function (target) { + var t = types[target.id]; + if (t === type || (!t && type === "line")) { + has = true; + } + }); + } + else if (Object.keys(types).length) { + Object.keys(types).forEach(function (id) { + if (types[id] === type) { + has = true; + } + }); + } + else { + has = config.data_type === type; + } + return has; + }, + /** + * Check if contains given chart types + * @param {string} type Type key + * @param {object} targets Target data + * @param {Array} exclude Excluded types + * @returns {boolean} + * @private + */ + hasTypeOf: function (type, targets, exclude) { + var _this = this; + if (exclude === void 0) { exclude = []; } + if (type in TYPE_BY_CATEGORY) { + return !TYPE_BY_CATEGORY[type] + .filter(function (v) { return exclude.indexOf(v) === -1; }) + .every(function (v) { return !_this.hasType(v, targets); }); + } + return false; + }, + /** + * Check if given data is certain chart type + * @param {object} d Data object + * @param {string|Array} type chart type + * @returns {boolean} + * @private + */ + isTypeOf: function (d, type) { + var id = isString(d) ? d : d.id; + var dataType = this.config.data_types[id] || this.config.data_type; + return isArray(type) ? + type.indexOf(dataType) >= 0 : dataType === type; + }, + hasPointType: function () { + var $$ = this; + return $$.hasTypeOf("Line") || $$.hasType("bubble") || $$.hasType("scatter"); + }, + /** + * Check if contains arc types chart + * @param {object} targets Target data + * @param {Array} exclude Excluded types + * @returns {boolean} + * @private + */ + hasArcType: function (targets, exclude) { + return this.hasTypeOf("Arc", targets, exclude); + }, + hasMultiArcGauge: function () { + return this.hasType("gauge") && this.config.gauge_type === "multi"; + }, + isLineType: function (d) { + var id = isString(d) ? d : d.id; + return !this.config.data_types[id] || + this.isTypeOf(id, TYPE_BY_CATEGORY.Line); + }, + isStepType: function (d) { + return this.isTypeOf(d, TYPE_BY_CATEGORY.Step); + }, + isSplineType: function (d) { + return this.isTypeOf(d, TYPE_BY_CATEGORY.Spline); + }, + isAreaType: function (d) { + return this.isTypeOf(d, TYPE_BY_CATEGORY.Area); + }, + isAreaRangeType: function (d) { + return this.isTypeOf(d, TYPE_BY_CATEGORY.AreaRange); + }, + isBarType: function (d) { + return this.isTypeOf(d, "bar"); + }, + isBubbleType: function (d) { + return this.isTypeOf(d, "bubble"); + }, + isCandlestickType: function (d) { + return this.isTypeOf(d, "candlestick"); + }, + isScatterType: function (d) { + return this.isTypeOf(d, "scatter"); + }, + isTreemapType: function (d) { + return this.isTypeOf(d, "treemap"); + }, + isPieType: function (d) { + return this.isTypeOf(d, "pie"); + }, + isGaugeType: function (d) { + return this.isTypeOf(d, "gauge"); + }, + isDonutType: function (d) { + return this.isTypeOf(d, "donut"); + }, + isPolarType: function (d) { + return this.isTypeOf(d, "polar"); + }, + isRadarType: function (d) { + return this.isTypeOf(d, "radar"); + }, + isArcType: function (d) { + return this.isPieType(d) || + this.isDonutType(d) || + this.isGaugeType(d) || + this.isPolarType(d) || + this.isRadarType(d); + }, + // determine if is 'circle' data point + isCirclePoint: function (node) { + var config = this.config; + var pattern = config.point_pattern; + var isCircle = false; + if ((node === null || node === void 0 ? void 0 : node.tagName) === "circle") { + isCircle = true; + } + else { + isCircle = config.point_type === "circle" && + (!pattern || (isArray(pattern) && pattern.length === 0)); + } + return isCircle; + }, + lineData: function (d) { + return this.isLineType(d) ? [d] : []; + }, + arcData: function (d) { + return this.isArcType(d.data) ? [d] : []; + }, + /** + * Get data adapt for data label showing + * @param {object} d Data object + * @returns {Array} + * @private + */ + labelishData: function (d) { + return this.isBarType(d) || + this.isLineType(d) || + this.isScatterType(d) || + this.isBubbleType(d) || + this.isCandlestickType(d) || + this.isRadarType(d) || + this.isTreemapType(d) ? d.values.filter(function (v) { return isNumber(v.value) || Boolean(v.value); }) : []; + }, + barLineBubbleData: function (d) { + return this.isBarType(d) || this.isLineType(d) || this.isBubbleType(d) ? + d.values : []; + }, + // https://github.com/d3/d3-shape#curves + isInterpolationType: function (type) { + return [ + "basis", + "basis-closed", + "basis-open", + "bundle", + "cardinal", + "cardinal-closed", + "cardinal-open", + "catmull-rom", + "catmull-rom-closed", + "catmull-rom-open", + "linear", + "linear-closed", + "monotone-x", + "monotone-y", + "natural" + ].indexOf(type) >= 0; + } +}; + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + * @ignore + */ +/** + * Internal chart class. + * - Note: Instantiated internally, not exposed for public. + * @class ChartInternal + * @ignore + * @private + */ +var ChartInternal = /** @class */ (function () { + function ChartInternal(api) { + // data object + this.data = { + xs: {}, + targets: [] + }; + // scales + this.scale = { + x: null, + y: null, + y2: null, + subX: null, + subY: null, + subY2: null, + zoom: null + }; + // original values + this.org = { + xScale: null, + xDomain: null + }; + // format function + this.format = { + extraLineClasses: null, + xAxisTick: null, + dataTime: null, + defaultAxisTime: null, + axisTime: null // axisTimeFormat + }; + var $$ = this; + $$.api = api; // Chart class instance alias + $$.config = new Options(); + $$.cache = new Cache(); + var store = new Store(); + $$.$el = store.getStore("element"); + $$.state = store.getStore("state"); + $$.$T = $$.$T.bind($$); + } + /** + * Get the selection based on transition config + * @param {SVGElement|d3Selection} selection Target selection + * @param {boolean} force Force transition + * @param {string} name Transition name + * @returns {d3Selection} + * @private + */ + ChartInternal.prototype.$T = function (selection, force, name) { + var _a = this, config = _a.config, state = _a.state; + var duration = config.transition_duration; + var subchart = config.subchart_show; + var t = selection; + if (t) { + // in case of non d3 selection, wrap with d3 selection + if ("tagName" in t) { + t = select(t); + } + // do not transit on: + // - wheel zoom (state.zooming = true) + // - when has no subchart + // - initialization + // - resizing + var transit = ((force !== false && duration) || force) && + (!state.zooming || state.dragging) && + !state.resizing && + state.rendered && + !subchart; + t = (transit ? t.transition(name).duration(duration) : t); + } + return t; + }; + ChartInternal.prototype.beforeInit = function () { + var $$ = this; + $$.callPluginHook("$beforeInit"); + // can do something + callFn($$.config.onbeforeinit, $$.api); + }; + ChartInternal.prototype.afterInit = function () { + var $$ = this; + $$.callPluginHook("$afterInit"); + // can do something + callFn($$.config.onafterinit, $$.api); + }; + ChartInternal.prototype.init = function () { + var $$ = this; + var config = $$.config, state = $$.state, $el = $$.$el; + var useCssRule = config.boost_useCssRule; + checkModuleImport($$); + state.hasRadar = !state.hasAxis && $$.hasType("radar"); + state.hasTreemap = !state.hasAxis && $$.hasType("treemap"); + state.hasAxis = !$$.hasArcType() && !state.hasTreemap; + // datetime to be used for uniqueness + state.datetimeId = "bb-".concat(+new Date() * getRandom()); + if (useCssRule) { + // append style element + var styleEl = doc.createElement("style"); + // styleEl.id = styleId; + styleEl.type = "text/css"; + doc.head.appendChild(styleEl); + state.style = { + rootSelctor: ".".concat(state.datetimeId), + sheet: styleEl.sheet + }; + // used on .destroy() + $el.style = styleEl; + } + var bindto = { + element: config.bindto, + classname: "bb" + }; + if (isObject(config.bindto)) { + bindto.element = config.bindto.element || "#chart"; + bindto.classname = config.bindto.classname || bindto.classname; + } + // select bind element + $el.chart = isFunction(bindto.element.node) ? + config.bindto.element : select(bindto.element || []); + if ($el.chart.empty()) { + $el.chart = select(doc.body.appendChild(doc.createElement("div"))); + } + $el.chart.html("") + .classed(bindto.classname, true) + .classed(state.datetimeId, useCssRule) + .style("position", "relative"); + $$.initParams(); + $$.initToRender(); + }; + /** + * Initialize the rendering process + * @param {boolean} forced Force to render process + * @private + */ + ChartInternal.prototype.initToRender = function (forced) { + var $$ = this; + var config = $$.config, state = $$.state, chart = $$.$el.chart; + var isHidden = function () { return chart.style("display") === "none" || chart.style("visibility") === "hidden"; }; + var isLazy = config.render.lazy || isHidden(); + var MutationObserver = win.MutationObserver; + if (isLazy && MutationObserver && config.render.observe !== false && !forced) { + new MutationObserver(function (mutation, observer) { + if (!isHidden()) { + observer.disconnect(); + !state.rendered && $$.initToRender(true); + } + }).observe(chart.node(), { + attributes: true, + attributeFilter: ["class", "style"] + }); + } + if (!isLazy || forced) { + $$.convertData(config, function (res) { + $$.initWithData(res); + $$.afterInit(); + }); + } + }; + ChartInternal.prototype.initParams = function () { + var $$ = this; + var config = $$.config, format = $$.format, state = $$.state; + var isRotated = config.axis_rotated; + // color settings + $$.color = $$.generateColor(); + $$.levelColor = $$.generateLevelColor(); + // when 'padding=false' is set, disable axes and subchart. Because they are useless. + if (config.padding === false) { + config.axis_x_show = false; + config.axis_y_show = false; + config.axis_y2_show = false; + config.subchart_show = false; + } + if ($$.hasPointType()) { + $$.point = $$.generatePoint(); + } + if (state.hasAxis) { + $$.initClip(); + format.extraLineClasses = $$.generateExtraLineClass(); + format.dataTime = config.data_xLocaltime ? timeParse : utcParse; + format.axisTime = config.axis_x_localtime ? timeFormat : utcFormat; + var isDragZoom_1 = $$.config.zoom_enabled && $$.config.zoom_type === "drag"; + format.defaultAxisTime = function (d) { + var _a = $$.scale, x = _a.x, zoom = _a.zoom; + var isZoomed = isDragZoom_1 ? zoom : + zoom && x.orgDomain().toString() !== zoom.domain().toString(); + var specifier = (d.getMilliseconds() && ".%L") || + (d.getSeconds() && ".:%S") || + (d.getMinutes() && "%I:%M") || + (d.getHours() && "%I %p") || + (d.getDate() !== 1 && "%b %d") || + (isZoomed && d.getDate() === 1 && "%b\'%y") || + (d.getMonth() && "%-m/%-d") || "%Y"; + return format.axisTime(specifier)(d); + }; + } + state.isLegendRight = config.legend_position === "right"; + state.isLegendInset = config.legend_position === "inset"; + state.isLegendTop = config.legend_inset_anchor === "top-left" || + config.legend_inset_anchor === "top-right"; + state.isLegendLeft = config.legend_inset_anchor === "top-left" || + config.legend_inset_anchor === "bottom-left"; + state.rotatedPadding.top = $$.getResettedPadding(state.rotatedPadding.top); + state.rotatedPadding.right = isRotated && !config.axis_x_show ? 0 : 30; + state.inputType = convertInputType(config.interaction_inputType_mouse, config.interaction_inputType_touch); + }; + ChartInternal.prototype.initWithData = function (data) { + var _a, _b; + var $$ = this; + var config = $$.config, scale = $$.scale, state = $$.state, $el = $$.$el, org = $$.org; + var hasAxis = state.hasAxis, hasTreemap = state.hasTreemap; + var hasInteraction = config.interaction_enabled; + var hasPolar = $$.hasType("polar"); + // for arc type, set axes to not be shown + // $$.hasArcType() && ["x", "y", "y2"].forEach(id => (config[`axis_${id}_show`] = false)); + if (hasAxis) { + $$.axis = $$.getAxisInstance(); + config.zoom_enabled && $$.initZoom(); + } + // Init data as targets + $$.data.xs = {}; + $$.data.targets = $$.convertDataToTargets(data); + if (config.data_filter) { + $$.data.targets = $$.data.targets.filter(config.data_filter.bind($$.api)); + } + // Set targets to hide if needed + if (config.data_hide) { + $$.addHiddenTargetIds(config.data_hide === true ? + $$.mapToIds($$.data.targets) : config.data_hide); + } + if (config.legend_hide) { + $$.addHiddenLegendIds(config.legend_hide === true ? + $$.mapToIds($$.data.targets) : config.legend_hide); + } + // Init sizes and scales + $$.updateSizes(); + $$.updateScales(true); + // retrieve scale after the 'updateScales()' is called + if (hasAxis) { + var x = scale.x, y = scale.y, y2 = scale.y2, subX = scale.subX, subY = scale.subY, subY2 = scale.subY2; + // Set domains for each scale + if (x) { + x.domain(sortValue($$.getXDomain($$.data.targets), !config.axis_x_inverted)); + subX.domain(x.domain()); + // Save original x domain for zoom update + org.xDomain = x.domain(); + } + if (y) { + y.domain($$.getYDomain($$.data.targets, "y")); + subY.domain(y.domain()); + } + if (y2) { + y2.domain($$.getYDomain($$.data.targets, "y2")); + subY2 && subY2.domain(y2.domain()); + } + } + // -- Basic Elements -- + $el.svg = $el.chart.append("svg") + .style("overflow", "hidden") + .style("display", "block"); + if (hasInteraction && state.inputType) { + var isTouch = state.inputType === "touch"; + var onclick_1 = config.onclick, onover = config.onover, onout = config.onout; + $el.svg + .on("click", (onclick_1 === null || onclick_1 === void 0 ? void 0 : onclick_1.bind($$.api)) || null) + .on(isTouch ? "touchstart" : "mouseenter", (onover === null || onover === void 0 ? void 0 : onover.bind($$.api)) || null) + .on(isTouch ? "touchend" : "mouseleave", (onout === null || onout === void 0 ? void 0 : onout.bind($$.api)) || null); + } + config.svg_classname && $el.svg.attr("class", config.svg_classname); + // Define defs + var hasColorPatterns = (isFunction(config.color_tiles) && $$.patterns); + if (hasAxis || hasColorPatterns || hasPolar || hasTreemap || + config.data_labels_backgroundColors) { + $el.defs = $el.svg.append("defs"); + if (hasAxis) { + ["id", "idXAxis", "idYAxis", "idGrid"].forEach(function (v) { + $$.appendClip($el.defs, state.clip[v]); + }); + } + // Append data background color filter definition + $$.generateDataLabelBackgroundColorFilter(); + // set color patterns + if (hasColorPatterns) { + $$.patterns.forEach(function (p) { return $el.defs.append(function () { return p.node; }); }); + } + } + $$.updateSvgSize(); + // Bind resize event + $$.bindResize(); + // Define regions + var main = $el.svg.append("g") + .classed($COMMON.main, true) + .attr("transform", hasTreemap ? null : $$.getTranslate("main")); + $el.main = main; + // initialize subchart when subchart show option is set + config.subchart_show && $$.initSubchart(); + config.tooltip_show && $$.initTooltip(); + config.title_text && $$.initTitle(); + !hasTreemap && config.legend_show && $$.initLegend(); + // -- Main Region -- + // text when empty + if (config.data_empty_label_text) { + main.append("text") + .attr("class", "".concat($TEXT.text, " ").concat($COMMON.empty)) + .attr("text-anchor", "middle") // horizontal centering of text at x position in all browsers. + .attr("dominant-baseline", "middle"); // vertical centering of text at y position in all browsers, except IE. + } + if (hasAxis) { + // Regions + config.regions.length && $$.initRegion(); + // Add Axis here, when clipPath is 'false' + !config.clipPath && $$.axis.init(); + } + // Define g for chart area + main.append("g") + .classed($COMMON.chart, true) + .attr("clip-path", hasAxis ? state.clip.path : null); + $$.callPluginHook("$init"); + $$.initChartElements(); + if (hasAxis) { + // Cover whole with rects for events + hasInteraction && ((_a = $$.initEventRect) === null || _a === void 0 ? void 0 : _a.call($$)); + // Grids + $$.initGrid(); + // Add Axis here, when clipPath is 'true' + config.clipPath && ((_b = $$.axis) === null || _b === void 0 ? void 0 : _b.init()); + } + // Set targets + $$.updateTargets($$.data.targets); + // Draw with targets + $$.updateDimension(); + // oninit callback + callFn(config.oninit, $$.api); + // Set background + $$.setBackground(); + $$.redraw({ + withTransition: false, + withTransform: true, + withUpdateXDomain: true, + withUpdateOrgXDomain: true, + withTransitionForAxis: false, + initializing: true + }); + // data.onmin/max callback + if (config.data_onmin || config.data_onmax) { + var minMax = $$.getMinMaxData(); + callFn(config.data_onmin, $$.api, minMax.min); + callFn(config.data_onmax, $$.api, minMax.max); + } + config.tooltip_show && $$.initShowTooltip(); + state.rendered = true; + }; + /** + * Initialize chart elements + * @private + */ + ChartInternal.prototype.initChartElements = function () { + var $$ = this; + var _a = $$.state, hasAxis = _a.hasAxis, hasRadar = _a.hasRadar, hasTreemap = _a.hasTreemap; + var types = []; + if (hasAxis) { + var shapes = ["bar", "bubble", "candlestick", "line"]; + if ($$.config.bar_front) { + shapes.push(shapes.shift()); + } + shapes.forEach(function (v) { + var name = capitalize(v); + if ((v === "line" && $$.hasTypeOf(name)) || $$.hasType(v)) { + types.push(name); + } + }); + } + else if (hasTreemap) { + types.push("Treemap"); + } + else { + var hasPolar = $$.hasType("polar"); + if (!hasRadar) { + types.push("Arc", "Pie"); + } + if ($$.hasType("gauge")) { + types.push("Gauge"); + } + else if (hasRadar) { + types.push("Radar"); + } + else if (hasPolar) { + types.push("Polar"); + } + } + types.forEach(function (v) { + $$["init".concat(v)](); + }); + notEmpty($$.config.data_labels) && !$$.hasArcType(null, ["radar"]) && $$.initText(); + }; + /** + * Set chart elements + * @private + */ + ChartInternal.prototype.setChartElements = function () { + var $$ = this; + var _a = $$.$el, chart = _a.chart, svg = _a.svg, defs = _a.defs, main = _a.main, tooltip = _a.tooltip, legend = _a.legend, title = _a.title, grid = _a.grid, needle = _a.needle, arc = _a.arcs, circles = _a.circle, bars = _a.bar, candlestick = _a.candlestick, lines = _a.line, areas = _a.area, texts = _a.text; + // public + $$.api.$ = { + chart: chart, + svg: svg, + defs: defs, + main: main, + tooltip: tooltip, + legend: legend, + title: title, + grid: grid, + arc: arc, + circles: circles, + bar: { bars: bars }, + candlestick: candlestick, + line: { lines: lines, areas: areas }, + needle: needle, + text: { texts: texts } + }; + }; + /** + * Set background element/image + * @private + */ + ChartInternal.prototype.setBackground = function () { + var $$ = this; + var bg = $$.config.background, state = $$.state, svg = $$.$el.svg; + if (notEmpty(bg)) { + var element = svg.select("g") + .insert(bg.imgUrl ? "image" : "rect", ":first-child"); + if (bg.imgUrl) { + element.attr("href", bg.imgUrl); + } + else if (bg.color) { + element + .style("fill", bg.color) + .attr("clip-path", state.clip.path); + } + element + .attr("class", bg.class || null) + .attr("width", "100%") + .attr("height", "100%"); + } + }; + /** + * Update targeted element with given data + * @param {object} targets Data object formatted as 'target' + * @private + */ + ChartInternal.prototype.updateTargets = function (targets) { + var _a; + var $$ = this; + var _b = $$.state, hasAxis = _b.hasAxis, hasRadar = _b.hasRadar, hasTreemap = _b.hasTreemap; + var helper = function (type) { return $$["updateTargetsFor".concat(type)](targets.filter($$["is".concat(type, "Type")].bind($$))); }; + // Text + $$.updateTargetsForText(targets); + if (hasAxis) { + ["bar", "candlestick", "line"].forEach(function (v) { + var name = capitalize(v); + if ((v === "line" && $$.hasTypeOf(name)) || $$.hasType(v)) { + helper(name); + } + }); + // Sub Chart + $$.updateTargetsForSubchart && + $$.updateTargetsForSubchart(targets); + // Arc, Polar, Radar + } + else if ($$.hasArcType(targets)) { + var type = "Arc"; + if (hasRadar) { + type = "Radar"; + } + else if ($$.hasType("polar")) { + type = "Polar"; + } + helper(type); + // Arc, Polar, Radar + } + else if (hasTreemap) { + helper("Treemap"); + } + // Point types + var hasPointType = $$.hasType("bubble") || $$.hasType("scatter"); + if (hasPointType) { + (_a = $$.updateTargetForCircle) === null || _a === void 0 ? void 0 : _a.call($$); + } + // Fade-in each chart + $$.filterTargetsToShowAtInit(hasPointType); + }; + /** + * Display targeted elements at initialization + * @param {boolean} hasPointType whether has point type(bubble, scatter) or not + * @private + */ + ChartInternal.prototype.filterTargetsToShowAtInit = function (hasPointType) { + if (hasPointType === void 0) { hasPointType = false; } + var $$ = this; + var svg = $$.$el.svg, $T = $$.$T; + var selector = ".".concat($COMMON.target); + if (hasPointType) { + selector += ", .".concat($CIRCLE.chartCircles, " > .").concat($CIRCLE.circles); + } + $T(svg.selectAll(selector) + .filter(function (d) { return $$.isTargetToShow(d.id); })).style("opacity", null); + }; + ChartInternal.prototype.getWithOption = function (options) { + var withOptions = { + Dimension: true, + EventRect: true, + Legend: false, + Subchart: true, + Transform: false, + Transition: true, + TrimXDomain: true, + UpdateXAxis: "UpdateXDomain", + UpdateXDomain: false, + UpdateOrgXDomain: false, + TransitionForExit: "Transition", + TransitionForAxis: "Transition", + Y: true + }; + Object.keys(withOptions).forEach(function (key) { + var defVal = withOptions[key]; + if (isString(defVal)) { + defVal = withOptions[defVal]; + } + withOptions[key] = getOption(options, "with".concat(key), defVal); + }); + return withOptions; + }; + ChartInternal.prototype.initialOpacity = function (d) { + var $$ = this; + var withoutFadeIn = $$.state.withoutFadeIn; + var r = $$.getBaseValue(d) !== null && + withoutFadeIn[d.id] ? null : "0"; + return r; + }; + ChartInternal.prototype.bindResize = function () { + var $$ = this; + var config = $$.config, state = $$.state; + var resizeFunction = generateResize(config.resize_timer); + var list = []; + list.push(function () { return callFn(config.onresize, $$.api); }); + if (config.resize_auto) { + list.push(function () { + state.resizing = true; + // https://github.com/naver/billboard.js/issues/2650 + if (config.legend_show) { + $$.updateSizes(); + $$.updateLegend(); + } + $$.api.flush(false); + }); + } + list.push(function () { + callFn(config.onresized, $$.api); + state.resizing = false; + }); + // add resize functions + list.forEach(function (v) { return resizeFunction.add(v); }); + $$.resizeFunction = resizeFunction; + // attach resize event + win.addEventListener("resize", $$.resizeFunction = resizeFunction); + }; + /** + * Call plugin hook + * @param {string} phase The lifecycle phase + * @param {Array} args Arguments + * @private + */ + ChartInternal.prototype.callPluginHook = function (phase) { + var _this = this; + var args = []; + for (var _i = 1; _i < arguments.length; _i++) { + args[_i - 1] = arguments[_i]; + } + this.config.plugins.forEach(function (v) { + if (phase === "$beforeInit") { + v.$$ = _this; + _this.api.plugins.push(v); + } + v[phase].apply(v, args); + }); + }; + return ChartInternal; +}()); +extend(ChartInternal.prototype, [ + // common + dataConvert, + data$1, + dataLoad, + category, + classModule, + color, + domain, + interaction, + format, + legend$1, + redraw, + scale, + shape, + size, + style, + text, + title, + tooltip$1, + transform, + typeInternals +]); + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +/** + * Load configuration option + * @param {object} config User's generation config value + * @private + */ +function loadConfig(config) { + var thisConfig = this.config; + var target; + var keys; + var read; + var find = function () { + var key = keys.shift(); + if (key && target && isObjectType(target) && key in target) { + target = target[key]; + return find(); + } + else if (!key) { + return target; + } + return undefined; + }; + Object.keys(thisConfig).forEach(function (key) { + target = config; + keys = key.split("_"); + read = find(); + if (isDefined(read)) { + thisConfig[key] = read; + } + }); + // only should run in the ChartInternal context + if (this.api) { + this.state.orgConfig = config; + } +} + +/** + * Copyright (c) 2017 ~ present NAVER Corp. + * billboard.js project is licensed under the MIT license + */ +var apiChart = { + /** + * Resize the chart. + * @function resize + * @instance + * @memberof Chart + * @param {object} size This argument should include width and height in pixels. + * @param {number} [size.width] width value + * @param {number} [size.height] height value + * @example + * // Resize to 640x480 + * chart.resize({ + * width: 640, + * height: 480 + * }); + */ + resize: function (size) { + var $$ = this.internal; + var config = $$.config, state = $$.state; + if (state.rendered) { + config.size_width = size ? size.width : null; + config.size_height = size ? size.height : null; + state.resizing = true; + this.flush(false); + $$.resizeFunction(); + } + }, + /** + * Force to redraw. + * - **NOTE:** When zoom/subchart is used, the zoomed state will be resetted. + * @function flush + * @instance + * @memberof Chart + * @param {boolean} [soft] For soft redraw. + * @example + * chart.flush(); + * + * // for soft redraw + * chart.flush(true); + */ + flush: function (soft) { + var _a, _b; + var $$ = this.internal; + var state = $$.state, zoomResetBtn = $$.$el.zoomResetBtn; + if (state.rendered) { + // reset possible zoom scale when is called from resize event + // eslint-disable-next-line prefer-rest-params + if (state.resizing) { // arguments[1] is given when is called from resize + (_a = $$.brush) === null || _a === void 0 ? void 0 : _a.updateResize(); + } + else { + // re-update config info + (_b = $$.axis) === null || _b === void 0 ? void 0 : _b.setOrient(); + } + // hide possible reset zoom button + // https://github.com/naver/billboard.js/issues/2201 + zoomResetBtn === null || zoomResetBtn === void 0 ? void 0 : zoomResetBtn.style("display", "none"); + $$.scale.zoom = null; + soft ? $$.redraw({ + withTransform: true, + withUpdateXDomain: true, + withUpdateOrgXDomain: true, + withLegend: true + }) : $$.updateAndRedraw({ + withLegend: true, + withTransition: false, + withTransitionForTransform: false, + }); + // reset subchart selection & selection state + if (!state.resizing && $$.brush) { + $$.brush.getSelection().call($$.brush.move); + $$.unselectRect(); + } + } + else { + $$.initToRender(true); + } + }, + /** + * Reset the chart object and remove element and events completely. + * @function destroy + * @instance + * @memberof Chart + * @returns {null} + * @example + * chart.destroy(); + */ + destroy: function () { + var _this = this; + var $$ = this.internal; + var _a = $$.$el, chart = _a.chart, style = _a.style, svg = _a.svg; + if (notEmpty($$)) { + $$.callPluginHook("$willDestroy"); + $$.charts.splice($$.charts.indexOf(this), 1); + // detach events + $$.unbindAllEvents(); + // clear timers && pending transition + svg.select("*").interrupt(); + $$.resizeFunction.clear(); + win.removeEventListener("resize", $$.resizeFunction); + chart.classed("bb", false) + .style("position", null) + .selectChildren() + .remove(); + // remove