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:
+ * //
'
+ * }
+ *
+ * // 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 || "