UNPKG

highcharts

Version:
1,280 lines (1,273 loc) 195 kB
/** * @license Highcharts JS v10.0.0 (2022-03-07) * * (c) 2016-2021 Highsoft AS * Authors: Jon Arild Nygard * * License: www.highcharts.com/license */ (function (factory) { if (typeof module === 'object' && module.exports) { factory['default'] = factory; module.exports = factory; } else if (typeof define === 'function' && define.amd) { define('highcharts/modules/sunburst', ['highcharts'], function (Highcharts) { factory(Highcharts); factory.Highcharts = Highcharts; return factory; }); } else { factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined); } }(function (Highcharts) { 'use strict'; var _modules = Highcharts ? Highcharts._modules : {}; function _registerModule(obj, path, args, fn) { if (!obj.hasOwnProperty(path)) { obj[path] = fn.apply(null, args); if (typeof CustomEvent === 'function') { window.dispatchEvent( new CustomEvent( 'HighchartsModuleLoaded', { detail: { path: path, module: obj[path] } }) ); } } } _registerModule(_modules, 'Series/ColorMapMixin.js', [_modules['Core/Globals.js'], _modules['Core/Series/Point.js'], _modules['Core/Utilities.js']], function (H, Point, U) { /* * * * (c) 2010-2021 Torstein Honsi * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ // @todo cleanup & reduction - consider composition var noop = H.noop, seriesTypes = H.seriesTypes; var defined = U.defined, addEvent = U.addEvent; // Move points to the top of the z-index order when hovered addEvent(Point, 'afterSetState', function (e) { var point = this; if (point.moveToTopOnHover && point.graphic) { point.graphic.attr({ zIndex: e && e.state === 'hover' ? 1 : 0 }); } }); /** * Mixin for maps and heatmaps * * @private * @mixin Highcharts.colorMapPointMixin */ var PointMixin = { dataLabelOnNull: true, moveToTopOnHover: true, /* eslint-disable valid-jsdoc */ /** * Color points have a value option that determines whether or not it is * a null point * @private */ isValid: function () { // undefined is allowed return (this.value !== null && this.value !== Infinity && this.value !== -Infinity); } /* eslint-enable valid-jsdoc */ }; /** * @private * @mixin Highcharts.colorMapSeriesMixin */ var SeriesMixin = { pointArrayMap: ['value'], axisTypes: ['xAxis', 'yAxis', 'colorAxis'], trackerGroups: ['group', 'markerGroup', 'dataLabelsGroup'], getSymbol: noop, parallelArrays: ['x', 'y', 'value'], colorKey: 'value', pointAttribs: seriesTypes.column.prototype.pointAttribs, /* eslint-disable valid-jsdoc */ /** * Get the color attibutes to apply on the graphic * @private * @function Highcharts.colorMapSeriesMixin.colorAttribs * @param {Highcharts.Point} point * @return {Highcharts.SVGAttributes} * The SVG attributes */ colorAttribs: function (point) { var ret = {}; if (defined(point.color) && (!point.state || point.state === 'normal') // #15746 ) { ret[this.colorProp || 'fill'] = point.color; } return ret; } }; var ColorMapMixin = { PointMixin: PointMixin, SeriesMixin: SeriesMixin }; return ColorMapMixin; }); _registerModule(_modules, 'Series/Treemap/TreemapAlgorithmGroup.js', [], function () { /* * * * (c) 2014-2021 Highsoft AS * * Authors: Jon Arild Nygard / Oystein Moseng * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /* * * * Class * * */ var TreemapAlgorithmGroup = /** @class */ (function () { /* * * * Constructor * * */ function TreemapAlgorithmGroup(h, w, d, p) { this.height = h; this.width = w; this.plot = p; this.direction = d; this.startDirection = d; this.total = 0; this.nW = 0; this.lW = 0; this.nH = 0; this.lH = 0; this.elArr = []; this.lP = { total: 0, lH: 0, nH: 0, lW: 0, nW: 0, nR: 0, lR: 0, aspectRatio: function (w, h) { return Math.max((w / h), (h / w)); } }; } /* * * * Functions * * */ /* eslint-disable valid-jsdoc */ TreemapAlgorithmGroup.prototype.addElement = function (el) { this.lP.total = this.elArr[this.elArr.length - 1]; this.total = this.total + el; if (this.direction === 0) { // Calculate last point old aspect ratio this.lW = this.nW; this.lP.lH = this.lP.total / this.lW; this.lP.lR = this.lP.aspectRatio(this.lW, this.lP.lH); // Calculate last point new aspect ratio this.nW = this.total / this.height; this.lP.nH = this.lP.total / this.nW; this.lP.nR = this.lP.aspectRatio(this.nW, this.lP.nH); } else { // Calculate last point old aspect ratio this.lH = this.nH; this.lP.lW = this.lP.total / this.lH; this.lP.lR = this.lP.aspectRatio(this.lP.lW, this.lH); // Calculate last point new aspect ratio this.nH = this.total / this.width; this.lP.nW = this.lP.total / this.nH; this.lP.nR = this.lP.aspectRatio(this.lP.nW, this.nH); } this.elArr.push(el); }; TreemapAlgorithmGroup.prototype.reset = function () { this.nW = 0; this.lW = 0; this.elArr = []; this.total = 0; }; return TreemapAlgorithmGroup; }()); /* * * * Default Export * * */ return TreemapAlgorithmGroup; }); _registerModule(_modules, 'Series/DrawPointComposition.js', [], function () { /* * * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /* * * * Composition * * */ var DrawPointComposition; (function (DrawPointComposition) { /* * * * Declarations * * */ /* * * * Constants * * */ var composedClasses = []; /* * * * Functions * * */ /* eslint-disable valid-jsdoc */ /** * @private */ function compose(PointClass) { if (composedClasses.indexOf(PointClass) === -1) { composedClasses.push(PointClass); var pointProto = PointClass.prototype; pointProto.draw = draw; if (!pointProto.shouldDraw) { pointProto.shouldDraw = shouldDraw; } } return PointClass; } DrawPointComposition.compose = compose; /** * Handles the drawing of a component. * Can be used for any type of component that reserves the graphic property, * and provides a shouldDraw on its context. * * @private * * @todo add type checking. * @todo export this function to enable usage */ function draw(params) { var _this = this; var animatableAttribs = params.animatableAttribs, onComplete = params.onComplete, css = params.css, renderer = params.renderer; var animation = (this.series && this.series.chart.hasRendered) ? // Chart-level animation on updates void 0 : // Series-level animation on new points (this.series && this.series.options.animation); var graphic = this.graphic; params.attribs = params.attribs || {}; // Assigning class in dot notation does go well in IE8 // eslint-disable-next-line dot-notation params.attribs['class'] = this.getClassName(); if (this.shouldDraw()) { if (!graphic) { this.graphic = graphic = params.shapeType === 'text' ? renderer.text() : renderer[params.shapeType](params.shapeArgs || {}); graphic.add(params.group); } if (css) { graphic.css(css); } graphic .attr(params.attribs) .animate(animatableAttribs, params.isNew ? false : animation, onComplete); } else if (graphic) { var destroy_1 = function () { _this.graphic = graphic = (graphic && graphic.destroy()); if (typeof onComplete === 'function') { onComplete(); } }; // animate only runs complete callback if something was animated. if (Object.keys(animatableAttribs).length) { graphic.animate(animatableAttribs, void 0, function () { destroy_1(); }); } else { destroy_1(); } } } /** * @private */ function shouldDraw() { return !this.isNull; } })(DrawPointComposition || (DrawPointComposition = {})); /* * * * Default Export * * */ return DrawPointComposition; }); _registerModule(_modules, 'Series/Treemap/TreemapPoint.js', [_modules['Series/DrawPointComposition.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (DrawPointComposition, SeriesRegistry, U) { /* * * * (c) 2014-2021 Highsoft AS * * Authors: Jon Arild Nygard / Oystein Moseng * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var Point = SeriesRegistry.series.prototype.pointClass, _a = SeriesRegistry.seriesTypes, PiePoint = _a.pie.prototype.pointClass, ScatterPoint = _a.scatter.prototype.pointClass; var extend = U.extend, isNumber = U.isNumber, pick = U.pick; /* * * * Class * * */ var TreemapPoint = /** @class */ (function (_super) { __extends(TreemapPoint, _super); function TreemapPoint() { /* * * * Properties * * */ var _this = _super !== null && _super.apply(this, arguments) || this; _this.name = void 0; _this.node = void 0; _this.options = void 0; _this.series = void 0; _this.value = void 0; return _this; /* eslint-enable valid-jsdoc */ } /* * * * Functions * * */ /* eslint-disable valid-jsdoc */ TreemapPoint.prototype.getClassName = function () { var className = Point.prototype.getClassName.call(this), series = this.series, options = series.options; // Above the current level if (this.node.level <= series.nodeMap[series.rootNode].level) { className += ' highcharts-above-level'; } else if (!this.node.isLeaf && !pick(options.interactByLeaf, !options.allowTraversingTree)) { className += ' highcharts-internal-node-interactive'; } else if (!this.node.isLeaf) { className += ' highcharts-internal-node'; } return className; }; /** * A tree point is valid if it has han id too, assume it may be a parent * item. * * @private * @function Highcharts.Point#isValid */ TreemapPoint.prototype.isValid = function () { return Boolean(this.id || isNumber(this.value)); }; TreemapPoint.prototype.setState = function (state) { Point.prototype.setState.call(this, state); // Graphic does not exist when point is not visible. if (this.graphic) { this.graphic.attr({ zIndex: state === 'hover' ? 1 : 0 }); } }; TreemapPoint.prototype.shouldDraw = function () { return isNumber(this.plotY) && this.y !== null; }; return TreemapPoint; }(ScatterPoint)); extend(TreemapPoint.prototype, { setVisible: PiePoint.prototype.setVisible }); DrawPointComposition.compose(TreemapPoint); /* * * * Default Export * * */ return TreemapPoint; }); _registerModule(_modules, 'Series/Treemap/TreemapUtilities.js', [_modules['Core/Utilities.js']], function (U) { /* * * * (c) 2014-2021 Highsoft AS * * Authors: Jon Arild Nygard / Oystein Moseng * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ /* * * * Imports * * */ var objectEach = U.objectEach; /* * * * Namespace * * */ var TreemapUtilities; (function (TreemapUtilities) { TreemapUtilities.AXIS_MAX = 100; /* eslint-disable no-invalid-this, valid-jsdoc */ /** * @todo Similar to eachObject, this function is likely redundant */ function isBoolean(x) { return typeof x === 'boolean'; } TreemapUtilities.isBoolean = isBoolean; /** * @todo Similar to recursive, this function is likely redundant */ function eachObject(list, func, context) { context = context || this; objectEach(list, function (val, key) { func.call(context, val, key, list); }); } TreemapUtilities.eachObject = eachObject; /** * @todo find correct name for this function. * @todo Similar to reduce, this function is likely redundant */ function recursive(item, func, context) { if (context === void 0) { context = this; } var next; next = func.call(context, item); if (next !== false) { recursive(next, func, context); } } TreemapUtilities.recursive = recursive; })(TreemapUtilities || (TreemapUtilities = {})); /* * * * Default Export * * */ return TreemapUtilities; }); _registerModule(_modules, 'Series/TreeUtilities.js', [_modules['Core/Color/Color.js'], _modules['Core/Utilities.js']], function (Color, U) { /* * * * (c) 2014-2021 Highsoft AS * * Authors: Jon Arild Nygard / Oystein Moseng * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ var extend = U.extend, isArray = U.isArray, isNumber = U.isNumber, isObject = U.isObject, merge = U.merge, pick = U.pick; /* * * * Functions * * */ /* eslint-disable valid-jsdoc */ /** * @private */ function getColor(node, options) { var index = options.index, mapOptionsToLevel = options.mapOptionsToLevel, parentColor = options.parentColor, parentColorIndex = options.parentColorIndex, series = options.series, colors = options.colors, siblings = options.siblings, points = series.points, chartOptionsChart = series.chart.options.chart; var getColorByPoint, point, level, colorByPoint, colorIndexByPoint, color, colorIndex; /** * @private */ var variateColor = function (color) { var colorVariation = level && level.colorVariation; if (colorVariation && colorVariation.key === 'brightness' && index && siblings) { return Color.parse(color).brighten(colorVariation.to * (index / siblings)).get(); } return color; }; if (node) { point = points[node.i]; level = mapOptionsToLevel[node.level] || {}; getColorByPoint = point && level.colorByPoint; if (getColorByPoint) { colorIndexByPoint = point.index % (colors ? colors.length : chartOptionsChart.colorCount); colorByPoint = colors && colors[colorIndexByPoint]; } // Select either point color, level color or inherited color. if (!series.chart.styledMode) { color = pick(point && point.options.color, level && level.color, colorByPoint, parentColor && variateColor(parentColor), series.color); } colorIndex = pick(point && point.options.colorIndex, level && level.colorIndex, colorIndexByPoint, parentColorIndex, options.colorIndex); } return { color: color, colorIndex: colorIndex }; } /** * Creates a map from level number to its given options. * * @private * * @param {Object} params * Object containing parameters. * - `defaults` Object containing default options. The default options are * merged with the userOptions to get the final options for a specific * level. * - `from` The lowest level number. * - `levels` User options from series.levels. * - `to` The highest level number. * * @return {Highcharts.Dictionary<object>|null} * Returns a map from level number to its given options. */ function getLevelOptions(params) { var result = null, defaults, converted, i, from, to, levels; if (isObject(params)) { result = {}; from = isNumber(params.from) ? params.from : 1; levels = params.levels; converted = {}; defaults = isObject(params.defaults) ? params.defaults : {}; if (isArray(levels)) { converted = levels.reduce(function (obj, item) { var level, levelIsConstant, options; if (isObject(item) && isNumber(item.level)) { options = merge({}, item); levelIsConstant = pick(options.levelIsConstant, defaults.levelIsConstant); // Delete redundant properties. delete options.levelIsConstant; delete options.level; // Calculate which level these options apply to. level = item.level + (levelIsConstant ? 0 : from - 1); if (isObject(obj[level])) { merge(true, obj[level], options); // #16329 } else { obj[level] = options; } } return obj; }, {}); } to = isNumber(params.to) ? params.to : 1; for (i = 0; i <= to; i++) { result[i] = merge({}, defaults, isObject(converted[i]) ? converted[i] : {}); } } return result; } /** * @private * @todo Combine buildTree and buildNode with setTreeValues * @todo Remove logic from Treemap and make it utilize this mixin. */ function setTreeValues(tree, options) { var before = options.before, idRoot = options.idRoot, mapIdToNode = options.mapIdToNode, nodeRoot = mapIdToNode[idRoot], levelIsConstant = (options.levelIsConstant !== false), points = options.points, point = points[tree.i], optionsPoint = point && point.options || {}, children = []; var childrenTotal = 0; tree.levelDynamic = tree.level - (levelIsConstant ? 0 : nodeRoot.level); tree.name = pick(point && point.name, ''); tree.visible = (idRoot === tree.id || options.visible === true); if (typeof before === 'function') { tree = before(tree, options); } // First give the children some values tree.children.forEach(function (child, i) { var newOptions = extend({}, options); extend(newOptions, { index: i, siblings: tree.children.length, visible: tree.visible }); child = setTreeValues(child, newOptions); children.push(child); if (child.visible) { childrenTotal += child.val; } }); // Set the values var value = pick(optionsPoint.value, childrenTotal); tree.visible = value >= 0 && (childrenTotal > 0 || tree.visible); tree.children = children; tree.childrenTotal = childrenTotal; tree.isLeaf = tree.visible && !childrenTotal; tree.val = value; return tree; } /** * Update the rootId property on the series. Also makes sure that it is * accessible to exporting. * * @private * * @param {Object} series * The series to operate on. * * @return {string} * Returns the resulting rootId after update. */ function updateRootId(series) { var rootId, options; if (isObject(series)) { // Get the series options. options = isObject(series.options) ? series.options : {}; // Calculate the rootId. rootId = pick(series.rootNode, options.rootId, ''); // Set rootId on series.userOptions to pick it up in exporting. if (isObject(series.userOptions)) { series.userOptions.rootId = rootId; } // Set rootId on series to pick it up on next update. series.rootNode = rootId; } return rootId; } /* * * * Default Export * * */ var TreeUtilities = { getColor: getColor, getLevelOptions: getLevelOptions, setTreeValues: setTreeValues, updateRootId: updateRootId }; return TreeUtilities; }); _registerModule(_modules, 'Extensions/Breadcrumbs.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Utilities.js'], _modules['Core/FormatUtilities.js']], function (Chart, H, D, U, F) { /* * * * Highcharts Breadcrumbs module * * Authors: Grzegorz Blachlinski, Karol Kolodziej * * License: www.highcharts.com/license * * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!! * * */ var defaultOptions = D.defaultOptions; var format = F.format; var addEvent = U.addEvent, objectEach = U.objectEach, extend = U.extend, fireEvent = U.fireEvent, merge = U.merge, pick = U.pick, defined = U.defined, isString = U.isString; // Add language support. extend(defaultOptions.lang, /** * @optionparent lang */ { /** * @since 10.0.0 * @product highcharts */ mainBreadcrumb: 'Main' }); /** * The Breadcrumbs class * * @private * @class * @name Highcharts.Breadcrumbs * * @param {Highcharts.Chart} chart * Chart object * @param {Highcharts.Options} userOptions * User options */ var Breadcrumbs = /** @class */ (function () { function Breadcrumbs(chart, userOptions) { /* * * * Properties * * */ this.group = void 0; this.list = []; this.elementList = {}; this.isDirty = true; this.level = 0; this.options = void 0; var chartOptions = merge(chart.options.drilldown && chart.options.drilldown.drillUpButton, Breadcrumbs.defaultBreadcrumbsOptions, chart.options.navigation && chart.options.navigation.breadcrumbs, userOptions); this.chart = chart; this.options = chartOptions || {}; } /** * Update Breadcrumbs properties, like level and list. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#updateProperties * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.updateProperties = function (list) { this.setList(list); this.setLevel(); this.isDirty = true; }; /** * Set breadcrumbs list. * @function Highcharts.Breadcrumbs#setList * * @requires modules/breadcrumbs * * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. * @param {Highcharts.BreadcrumbsOptions} list * Breadcrumbs list. */ Breadcrumbs.prototype.setList = function (list) { this.list = list; }; /** * Calcule level on which chart currently is. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#setLevel * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.setLevel = function () { this.level = this.list.length && this.list.length - 1; }; /** * Get Breadcrumbs level * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#getLevel * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.getLevel = function () { return this.level; }; /** * Default button text formatter. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#getButtonText * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. * @param {Highcharts.Breadcrumbs} breadcrumb * Breadcrumb. * @return {string} * Formatted text. */ Breadcrumbs.prototype.getButtonText = function (breadcrumb) { var breadcrumbs = this, chart = breadcrumbs.chart, breadcrumbsOptions = breadcrumbs.options, lang = chart.options.lang, textFormat = pick(breadcrumbsOptions.format, breadcrumbsOptions.showFullPath ? '{level.name}' : '← {level.name}'), defaultText = lang && pick(lang.drillUpText, lang.mainBreadcrumb); var returnText = breadcrumbsOptions.formatter && breadcrumbsOptions.formatter(breadcrumb) || format(textFormat, { level: breadcrumb.levelOptions }, chart) || ''; if (((isString(returnText) && !returnText.length) || returnText === '← ') && defined(defaultText)) { returnText = !breadcrumbsOptions.showFullPath ? '← ' + defaultText : defaultText; } return returnText; }; /** * Redraw. * * @requires modules/breadcrums * * @function Highcharts.Breadcrumbs#redraw * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.redraw = function () { if (this.isDirty) { this.render(); } if (this.group) { this.group.align(); } this.isDirty = false; }; /** * Create a group, then draw breadcrumbs together with the separators. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#render * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.render = function () { var breadcrumbs = this, chart = breadcrumbs.chart, breadcrumbsOptions = breadcrumbs.options; // A main group for the breadcrumbs. if (!breadcrumbs.group && breadcrumbsOptions) { breadcrumbs.group = chart.renderer .g('breadcrumbs-group') .addClass('highcharts-no-tooltip highcharts-breadcrumbs') .attr({ zIndex: breadcrumbsOptions.zIndex }) .add(); } // Draw breadcrumbs. if (breadcrumbsOptions.showFullPath) { this.renderFullPathButtons(); } else { this.renderSingleButton(); } this.alignBreadcrumbsGroup(); }; /** * Draw breadcrumbs together with the separators. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#renderFullPathButtons * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.renderFullPathButtons = function () { // Make sure that only one type of button is visible. this.destroySingleButton(); this.resetElementListState(); this.updateListElements(); this.destroyListElements(); }; /** * Render Single button - when showFullPath is not used. The button is * similar to the old drillUpButton * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#renderSingleButton * @param {Highcharts.Breadcrumbs} this Breadcrumbs class. */ Breadcrumbs.prototype.renderSingleButton = function () { var breadcrumbs = this, chart = breadcrumbs.chart, list = breadcrumbs.list, breadcrumbsOptions = breadcrumbs.options, buttonSpacing = breadcrumbsOptions.buttonSpacing; // Make sure that only one type of button is visible. this.destroyListElements(); // Draw breadcrumbs. Inital position for calculating the breadcrumbs // group. var posX = breadcrumbs.group ? breadcrumbs.group.getBBox().width : buttonSpacing, posY = buttonSpacing; var previousBreadcrumb = list[list.length - 2]; if (!chart.drillUpButton && (this.level > 0)) { chart.drillUpButton = breadcrumbs.renderButton(previousBreadcrumb, posX, posY); } else if (chart.drillUpButton) { if (this.level > 0) { // Update button. this.updateSingleButton(); } else { this.destroySingleButton(); } } }; /** * Update group position based on align and it's width. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#renderSingleButton * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.alignBreadcrumbsGroup = function (xOffset) { var breadcrumbs = this; if (breadcrumbs.group) { var breadcrumbsOptions = breadcrumbs.options, buttonTheme = breadcrumbsOptions.buttonTheme, positionOptions = breadcrumbsOptions.position, alignTo = (breadcrumbsOptions.relativeTo === 'chart' || breadcrumbsOptions.relativeTo === 'spacingBox' ? void 0 : 'scrollablePlotBox'), bBox = breadcrumbs.group.getBBox(), additionalSpace = 2 * (buttonTheme.padding || 0) + breadcrumbsOptions.buttonSpacing; // Store positionOptions positionOptions.width = bBox.width + additionalSpace; positionOptions.height = bBox.height + additionalSpace; var newPositions = merge(positionOptions); // Add x offset if specified. if (xOffset) { newPositions.x += xOffset; } newPositions.y = pick(newPositions.y, this.yOffset, 0); breadcrumbs.group.align(newPositions, true, alignTo); } }; /** * Render a button. * * @requires modules/breadcrums * * @function Highcharts.Breadcrumbs#renderButton * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. * @param {Highcharts.Breadcrumbs} breadcrumb * Current breadcrumb * @param {Highcharts.Breadcrumbs} posX * Initial horizontal position * @param {Highcharts.Breadcrumbs} posY * Initial vertical position * @return {SVGElement|void} * Returns the SVG button */ Breadcrumbs.prototype.renderButton = function (breadcrumb, posX, posY) { var breadcrumbs = this, chart = this.chart, breadcrumbsOptions = breadcrumbs.options, buttonTheme = merge(breadcrumbsOptions.buttonTheme), states = buttonTheme.states; delete buttonTheme.states; var button = chart.renderer .button(breadcrumbs.getButtonText(breadcrumb), posX, posY, function (e) { // Extract events from button object and call var buttonEvents = breadcrumbsOptions.events && breadcrumbsOptions.events.click; var callDefaultEvent; if (buttonEvents) { callDefaultEvent = buttonEvents.call(breadcrumbs, e, breadcrumb); } // (difference in behaviour of showFullPath and drillUp) if (callDefaultEvent !== false) { // For single button we are not going to the button // level, but the one level up if (!breadcrumbsOptions.showFullPath) { e.newLevel = breadcrumbs.level - 1; } else { e.newLevel = breadcrumb.level; } fireEvent(breadcrumbs, 'up', e); } }, buttonTheme, states && states.hover, states && states.select, states && states.disabled) .addClass('highcharts-breadcrumbs-button') .add(breadcrumbs.group); if (!chart.styledMode) { button.attr(breadcrumbsOptions.style); } return button; }; /** * Render a separator. * * @requires modules/breadcrums * * @function Highcharts.Breadcrumbs#renderSeparator * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. * @param {Highcharts.Breadcrumbs} posX * Initial horizontal position * @param {Highcharts.Breadcrumbs} posY * Initial vertical position * @return {Highcharts.SVGElement} * Returns the SVG button */ Breadcrumbs.prototype.renderSeparator = function (posX, posY) { var breadcrumbs = this, chart = this.chart, breadcrumbsOptions = breadcrumbs.options, separatorOptions = breadcrumbsOptions.separator; var separator = chart.renderer .label(separatorOptions.text, posX, posY, void 0, void 0, void 0, false) .addClass('highcharts-breadcrumbs-separator') .add(breadcrumbs.group); if (!chart.styledMode) { separator.css(separatorOptions.style); } return separator; }; /** * Update. * @function Highcharts.Breadcrumbs#update * * @requires modules/breadcrumbs * * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. * @param {Highcharts.BreadcrumbsOptions} options * Breadcrumbs class. * @param {boolean} redraw * Redraw flag */ Breadcrumbs.prototype.update = function (options) { merge(true, this.options, options); this.destroy(); this.isDirty = true; }; /** * Update button text when the showFullPath set to false. * @function Highcharts.Breadcrumbs#updateSingleButton * * @requires modules/breadcrumbs * * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.updateSingleButton = function () { var chart = this.chart, currentBreadcrumb = this.list[this.level - 1]; if (chart.drillUpButton) { chart.drillUpButton.attr({ text: this.getButtonText(currentBreadcrumb) }); } }; /** * Destroy the chosen breadcrumbs group * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#destroy * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.destroy = function () { this.destroySingleButton(); // Destroy elements one by one. It's necessary beacause // g().destroy() does not remove added HTML this.destroyListElements(true); // Then, destroy the group itself. if (this.group) { this.group.destroy(); } this.group = void 0; }; /** * Destroy the elements' buttons and separators. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#destroyListElements * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.destroyListElements = function (force) { var elementList = this.elementList; objectEach(elementList, function (element, level) { if (force || !elementList[level].updated) { element = elementList[level]; element.button && element.button.destroy(); element.separator && element.separator.destroy(); delete element.button; delete element.separator; delete elementList[level]; } }); if (force) { this.elementList = {}; } }; /** * Destroy the single button if exists. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#destroySingleButton * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.destroySingleButton = function () { if (this.chart.drillUpButton) { this.chart.drillUpButton.destroy(); this.chart.drillUpButton = void 0; } }; /** * Reset state for all buttons in elementList. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#resetElementListState * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.resetElementListState = function () { objectEach(this.elementList, function (element) { element.updated = false; }); }; /** * Update rendered elements inside the elementList. * * @requires modules/breadcrumbs * * @function Highcharts.Breadcrumbs#updateListElements * @param {Highcharts.Breadcrumbs} this * Breadcrumbs class. */ Breadcrumbs.prototype.updateListElements = function () { var updateXPosition = function (element, spacing) { return element.getBBox().width + spacing; }, breadcrumbs = this, elementList = breadcrumbs.elementList, buttonSpacing = breadcrumbs.options.buttonSpacing, list = breadcrumbs.list; // Inital position for calculating the breadcrumbs group. var posX = breadcrumbs.group ? updateXPosition(breadcrumbs.group, buttonSpacing) : buttonSpacing, posY = buttonSpacing, currentBreadcrumb; list.forEach(function (breadcrumb, index) { var isLast = index === list.length - 1; var button, separator; if (elementList[breadcrumb.level]) { currentBreadcrumb = elementList[breadcrumb.level]; button = currentBreadcrumb.button; // Render a separator if it was not created before. if (!currentBreadcrumb.separator && !isLast) { // Add spacing for the next separator posX += buttonSpacing; currentBreadcrumb.separator = breadcrumbs.renderSeparator(posX,