| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987 | /** * @license Highcharts JS v7.0.2 (2019-01-17) * * (c) 2016-2019 Highsoft AS * Authors: Jon Arild Nygard * * License: www.highcharts.com/license */'use strict';(function (factory) {	if (typeof module === 'object' && module.exports) {		factory['default'] = factory;		module.exports = factory;	} else if (typeof define === 'function' && define.amd) {		define(function () {			return factory;		});	} else {		factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);	}}(function (Highcharts) {	var draw = (function () {		var isFn = function (x) {		    return typeof x === 'function';		};		/**		 * Handles the drawing of a point.		 *		 * @private		 * @function draw		 *		 * @param {object} params		 *        Parameters.		 *		 * @todo		 * - add type checking.		 */		var draw = function draw(params) {		    var point = this,		        graphic = point.graphic,		        animatableAttribs = params.animatableAttribs,		        onComplete = params.onComplete,		        css = params.css,		        renderer = params.renderer;		    if (point.shouldDraw()) {		        if (!graphic) {		            point.graphic = graphic =		                renderer[params.shapeType](params.shapeArgs).add(params.group);		        }		        graphic		            .css(css)		            .attr(params.attribs)		            .animate(		                animatableAttribs,		                params.isNew ? false : undefined,		                onComplete		            );		    } else if (graphic) {		        graphic.animate(animatableAttribs, undefined, function () {		            point.graphic = graphic = graphic.destroy();		            if (isFn(onComplete)) {		                onComplete();		            }		        });		    }		    if (graphic) {		        graphic.addClass(point.getClassName(), true);		    }		};		return draw;	}());	var result = (function (H) {		var extend = H.extend,		    isArray = H.isArray,		    isBoolean = function (x) {		        return typeof x === 'boolean';		    },		    isFn = function (x) {		        return typeof x === 'function';		    },		    isObject = H.isObject,		    isNumber = H.isNumber,		    merge = H.merge,		    pick = H.pick;		// TODO Combine buildTree and buildNode with setTreeValues		// TODO Remove logic from Treemap and make it utilize this mixin.		var setTreeValues = function setTreeValues(tree, options) {		    var before = options.before,		        idRoot = options.idRoot,		        mapIdToNode = options.mapIdToNode,		        nodeRoot = mapIdToNode[idRoot],		        levelIsConstant = (		            isBoolean(options.levelIsConstant) ?		                options.levelIsConstant :		                true		        ),		        points = options.points,		        point = points[tree.i],		        optionsPoint = point && point.options || {},		        childrenTotal = 0,		        children = [],		        value;		    extend(tree, {		        levelDynamic: tree.level - (levelIsConstant ? 0 : nodeRoot.level),		        name: pick(point && point.name, ''),		        visible: (		            idRoot === tree.id ||		            (isBoolean(options.visible) ? options.visible : false)		        )		    });		    if (isFn(before)) {		        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;		        }		    });		    tree.visible = childrenTotal > 0 || tree.visible;		    // Set the values		    value = pick(optionsPoint.value, childrenTotal);		    extend(tree, {		        children: children,		        childrenTotal: childrenTotal,		        isLeaf: tree.visible && !childrenTotal,		        val: value		    });		    return tree;		};		var getColor = 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,		        getColorByPoint,		        chartOptionsChart = series.chart.options.chart,		        point,		        level,		        colorByPoint,		        colorIndexByPoint,		        color,		        colorIndex;		    function variation(color) {		        var colorVariation = level && level.colorVariation;		        if (colorVariation) {		            if (colorVariation.key === 'brightness') {		                return H.color(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 && variation(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		 * @function getLevelOptions		 *		 * @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>}		 *         Returns a map from level number to its given options.		 */		var getLevelOptions = 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 = (		                        isBoolean(options.levelIsConstant) ?		                            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])) {		                        extend(obj[level], options);		                    } 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;		};		/**		 * Update the rootId property on the series. Also makes sure that it is		 * accessible to exporting.		 *		 * @private		 * @function updateRootId		 *		 * @param {object} series		 *        The series to operate on.		 *		 * @return {string}		 *         Returns the resulting rootId after update.		 */		var updateRootId = function (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;		};		var result = {		    getColor: getColor,		    getLevelOptions: getLevelOptions,		    setTreeValues: setTreeValues,		    updateRootId: updateRootId		};		return result;	}(Highcharts));	(function (H, mixinTreeSeries) {		/* *		 * (c) 2014-2019 Highsoft AS		 *		 * Authors: Jon Arild Nygard / Oystein Moseng		 *		 * License: www.highcharts.com/license		 */		var seriesType = H.seriesType,		    seriesTypes = H.seriesTypes,		    merge = H.merge,		    extend = H.extend,		    noop = H.noop,		    getColor = mixinTreeSeries.getColor,		    getLevelOptions = mixinTreeSeries.getLevelOptions,		    isArray = H.isArray,		    isBoolean = function (x) {		        return typeof x === 'boolean';		    },		    isNumber = H.isNumber,		    isObject = H.isObject,		    isString = H.isString,		    pick = H.pick,		    Series = H.Series,		    stableSort = H.stableSort,		    color = H.Color,		    eachObject = function (list, func, context) {		        context = context || this;		        H.objectEach(list, function (val, key) {		            func.call(context, val, key, list);		        });		    },		    // @todo find correct name for this function.		    // @todo Similar to reduce, this function is likely redundant		    recursive = function (item, func, context) {		        var next;		        context = context || this;		        next = func.call(context, item);		        if (next !== false) {		            recursive(next, func, context);		        }		    },		    updateRootId = mixinTreeSeries.updateRootId;		/**		 * @private		 * @class		 * @name Highcharts.seriesTypes.treemap		 *		 * @augments Highcharts.Series		 */		seriesType(		    'treemap',		    'scatter'		    /**		     * A treemap displays hierarchical data using nested rectangles. The data		     * can be laid out in varying ways depending on options.		     *		     * @sample highcharts/demo/treemap-large-dataset/		     *         Treemap		     *		     * @extends      plotOptions.scatter		     * @excluding    marker, jitter		     * @product      highcharts		     * @optionparent plotOptions.treemap		     */		    , {		        /**		         * When enabled the user can click on a point which is a parent and		         * zoom in on its children.		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-allowdrilltonode/		         *         Enabled		         *		         * @type      {boolean}		         * @default   false		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.allowDrillToNode		         */		        /**		         * When the series contains less points than the crop threshold, all		         * points are drawn, event if the points fall outside the visible plot		         * area at the current zoom. The advantage of drawing all points		         * (including markers and columns), is that animation is performed on		         * updates. On the other hand, when the series contains more points than		         * the crop threshold, the series data is cropped to only contain points		         * that fall within the plot area. The advantage of cropping away		         * invisible points is to increase performance on large series.		         *		         * @type      {number}		         * @default   300		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.cropThreshold		         */		        /**		         * This option decides if the user can interact with the parent nodes		         * or just the leaf nodes. When this option is undefined, it will be		         * true by default. However when allowDrillToNode is true, then it will		         * be false by default.		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-interactbyleaf-false/		         *         False		         * @sample {highcharts} highcharts/plotoptions/treemap-interactbyleaf-true-and-allowdrilltonode/		         *         InteractByLeaf and allowDrillToNode is true		         *		         * @type      {boolean}		         * @since     4.1.2		         * @product   highcharts		         * @apioption plotOptions.treemap.interactByLeaf		         */		        /**		         * The sort index of the point inside the treemap level.		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-sortindex/		         *         Sort by years		         *		         * @type      {number}		         * @since     4.1.10		         * @product   highcharts		         * @apioption plotOptions.treemap.sortIndex		         */		        /**		         * When using automatic point colors pulled from the `options.colors`		         * collection, this option determines whether the chart should receive		         * one color per series or one color per point.		         *		         * @see [series colors](#plotOptions.treemap.colors)		         *		         * @type      {boolean}		         * @default   false		         * @since     2.0		         * @product   highcharts		         * @apioption plotOptions.treemap.colorByPoint		         */		        /**		         * A series specific or series type specific color set to apply instead		         * of the global [colors](#colors) when		         * [colorByPoint](#plotOptions.treemap.colorByPoint) is true.		         *		         * @type      {Array<Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject>}		         * @since     3.0		         * @product   highcharts		         * @apioption plotOptions.treemap.colors		         */		        /**		         * Whether to display this series type or specific series item in the		         * legend.		         */		        showInLegend: false,		        /**		         * @ignore		         */		        marker: false,		        colorByPoint: false,		        /**		         * @extends plotOptions.heatmap.dataLabels		         * @since   4.1.0		         */		        dataLabels: {		            enabled: true,		            defer: false,		            verticalAlign: 'middle',		            formatter: function () {		                var point = this && this.point ? this.point : {},		                    name = isString(point.name) ? point.name : '';		                return name;		            },		            inside: true		        },		        tooltip: {		            headerFormat: '',		            pointFormat: '<b>{point.name}</b>: {point.value}<br/>'		        },		        /**		         * Whether to ignore hidden points when the layout algorithm runs.		         * If `false`, hidden points will leave open spaces.		         *		         * @since 5.0.8		         */		        ignoreHiddenPoint: true,		        /**		         * This option decides which algorithm is used for setting position		         * and dimensions of the points.		         *		         * @see [How to write your own algorithm](https://www.highcharts.com/docs/chart-and-series-types/treemap)		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-sliceanddice/		         *         SliceAndDice by default		         * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-stripes/		         *         Stripes		         * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-squarified/		         *         Squarified		         * @sample {highcharts} highcharts/plotoptions/treemap-layoutalgorithm-strip/		         *         Strip		         *		         * @since      4.1.0		         * @validvalue ["sliceAndDice", "stripes", "squarified", "strip"]		         */		        layoutAlgorithm: 'sliceAndDice',		        /**		         * Defines which direction the layout algorithm will start drawing.		         *		         * @since       4.1.0		         * @validvalue ["vertical", "horizontal"]		         */		        layoutStartingDirection: 'vertical',		        /**		         * Enabling this option will make the treemap alternate the drawing		         * direction between vertical and horizontal. The next levels starting		         * direction will always be the opposite of the previous.		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-alternatestartingdirection-true/		         *         Enabled		         *		         * @since 4.1.0		         */		        alternateStartingDirection: false,		        /**		         * Used together with the levels and allowDrillToNode options. When		         * set to false the first level visible when drilling is considered		         * to be level one. Otherwise the level will be the same as the tree		         * structure.		         *		         * @since 4.1.0		         */		        levelIsConstant: true,		        /**		         * Options for the button appearing when drilling down in a treemap.		         */		        drillUpButton: {		            /**		             * The position of the button.		             */		            position: {		                /**		                 * Vertical alignment of the button.		                 *		                 * @default    top		                 * @validvalue ["top", "middle", "bottom"]		                 * @product    highcharts		                 * @apioption  plotOptions.treemap.drillUpButton.position.verticalAlign		                 */		                /**		                 * Horizontal alignment of the button.		                 *		                 * @validvalue ["left", "center", "right"]		                 */		                align: 'right',		                /**		                 * Horizontal offset of the button.		                 */		                x: -10,		                /**		                 * Vertical offset of the button.		                 */		                y: 10		            }		        },		        /**		         * Set options on specific levels. Takes precedence over series options,		         * but not point options.		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-levels/		         *         Styling dataLabels and borders		         * @sample {highcharts} highcharts/demo/treemap-with-levels/		         *         Different layoutAlgorithm		         *		         * @type      {Array<*>}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels		         */		        /**		         * Can set a `borderColor` on all points which lies on the same level.		         *		         * @type      {Highcharts.ColorString}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.borderColor		         */		        /**		         * Set the dash style of the border of all the point which lies on the		         * level. See <a href"#plotoptions.scatter.dashstyle">		         * plotOptions.scatter.dashStyle</a> for possible options.		         *		         * @type      {string}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.borderDashStyle		         */		        /**		         * Can set the borderWidth on all points which lies on the same level.		         *		         * @type      {number}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.borderWidth		         */		        /**		         * Can set a color on all points which lies on the same level.		         *		         * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.color		         */		        /**		         * A configuration object to define how the color of a child varies from		         * the parent's color. The variation is distributed among the children		         * of node. For example when setting brightness, the brightness change		         * will range from the parent's original brightness on the first child,		         * to the amount set in the `to` setting on the last node. This allows a		         * gradient-like color scheme that sets children out from each other		         * while highlighting the grouping on treemaps and sectors on sunburst		         * charts.		         *		         * @sample highcharts/demo/sunburst/		         *         Sunburst with color variation		         *		         * @since     6.0.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.colorVariation		         */		        /**		         * The key of a color variation. Currently supports `brightness` only.		         *		         * @type       {string}		         * @since      6.0.0		         * @product    highcharts		         * @validvalue ["brightness"]		         * @apioption  plotOptions.treemap.levels.colorVariation.key		         */		        /**		         * The ending value of a color variation. The last sibling will receive		         * this value.		         *		         * @type      {number}		         * @since     6.0.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.colorVariation.to		         */		        /**		         * Can set the options of dataLabels on each point which lies on the		         * level.		         * [plotOptions.treemap.dataLabels](#plotOptions.treemap.dataLabels) for		         * possible values.		         *		         * @type      {object}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.dataLabels		         */		        /**		         * Can set the layoutAlgorithm option on a specific level.		         *		         * @type       {string}		         * @since      4.1.0		         * @product    highcharts		         * @validvalue ["sliceAndDice", "stripes", "squarified", "strip"]		         * @apioption  plotOptions.treemap.levels.layoutAlgorithm		         */		        /**		         * Can set the layoutStartingDirection option on a specific level.		         *		         * @type       {string}		         * @since      4.1.0		         * @product    highcharts		         * @validvalue ["vertical", "horizontal"]		         * @apioption  plotOptions.treemap.levels.layoutStartingDirection		         */		        /**		         * Decides which level takes effect from the options set in the levels		         * object.		         *		         * @sample {highcharts} highcharts/plotoptions/treemap-levels/		         *         Styling of both levels		         *		         * @type      {number}		         * @since     4.1.0		         * @product   highcharts		         * @apioption plotOptions.treemap.levels.level		         */		        // Presentational options		        /**		         * The color of the border surrounding each tree map item.		         *		         * @type {Highcharts.ColorString}		         */		        borderColor: '#e6e6e6',		        /**		         * The width of the border surrounding each tree map item.		         */		        borderWidth: 1,		        /**		         * The opacity of a point in treemap. When a point has children, the		         * visibility of the children is determined by the opacity.		         *		         * @since 4.2.4		         */		        opacity: 0.15,		        /**		         * A wrapper object for all the series options in specific states.		         *		         * @extends plotOptions.heatmap.states		         */		        states: {		            /**		             * Options for the hovered series		             *		             * @extends   plotOptions.heatmap.states.hover		             * @excluding halo		             */		            hover: {		                /**		                 * The border color for the hovered state.		                 */		                borderColor: '#999999',		                /**		                 * Brightness for the hovered point. Defaults to 0 if the		                 * heatmap series is loaded first, otherwise 0.1.		                 *		                 * @type    {number}		                 * @default undefined		                 */		                brightness: seriesTypes.heatmap ? 0 : 0.1,		                /**		                 * @extends plotOptions.heatmap.states.hover.halo		                 */		                halo: false,		                /**		                 * The opacity of a point in treemap. When a point has children,		                 * the visibility of the children is determined by the opacity.		                 *		                 * @since 4.2.4		                 */		                opacity: 0.75,		                /**		                 * The shadow option for hovered state.		                 */		                shadow: false		            }		        }		        // Prototype members		    }, {		        pointArrayMap: ['value'],		        directTouch: true,		        optionalAxis: 'colorAxis',		        getSymbol: noop,		        parallelArrays: ['x', 'y', 'value', 'colorValue'],		        colorKey: 'colorValue', // Point color option key		        trackerGroups: ['group', 'dataLabelsGroup'],		        /**		         * Creates an object map from parent id to childrens index.		         *		         * @private		         * @function Highcharts.Series#getListOfParents		         *		         * @param {Highcharts.SeriesTreemapDataOptions} data		         *        List of points set in options.		         *		         * @param {Array<string>} existingIds		         *        List of all point ids.		         *		         * @return {object}		         *         Map from parent id to children index in data.		         */		        getListOfParents: function (data, existingIds) {		            var arr = isArray(data) ? data : [],		                ids = isArray(existingIds) ? existingIds : [],		                listOfParents = arr.reduce(function (prev, curr, i) {		                    var parent = pick(curr.parent, '');		                    if (prev[parent] === undefined) {		                        prev[parent] = [];		                    }		                    prev[parent].push(i);		                    return prev;		                }, {		                    '': [] // Root of tree		                });		            // If parent does not exist, hoist parent to root of tree.		            eachObject(listOfParents, function (children, parent, list) {		                if ((parent !== '') && (ids.indexOf(parent) === -1)) {		                    children.forEach(function (child) {		                        list[''].push(child);		                    });		                    delete list[parent];		                }		            });		            return listOfParents;		        },		        // Creates a tree structured object from the series points		        getTree: function () {		            var series = this,		                allIds = this.data.map(function (d) {		                    return d.id;		                }),		                parentList = series.getListOfParents(this.data, allIds);		            series.nodeMap = [];		            return series.buildNode('', -1, 0, parentList, null);		        },		        init: function (chart, options) {		            var series = this,		                colorSeriesMixin = H.colorSeriesMixin;		            // If color series logic is loaded, add some properties		            if (H.colorSeriesMixin) {		                this.translateColors = colorSeriesMixin.translateColors;		                this.colorAttribs = colorSeriesMixin.colorAttribs;		                this.axisTypes = colorSeriesMixin.axisTypes;		            }		            Series.prototype.init.call(series, chart, options);		            if (series.options.allowDrillToNode) {		                H.addEvent(series, 'click', series.onClickDrillToNode);		            }		        },		        buildNode: function (id, i, level, list, parent) {		            var series = this,		                children = [],		                point = series.points[i],		                height = 0,		                node,		                child;		            // Actions		            ((list[id] || [])).forEach(function (i) {		                child = series.buildNode(		                    series.points[i].id,		                    i,		                    (level + 1),		                    list,		                    id		                );		                height = Math.max(child.height + 1, height);		                children.push(child);		            });		            node = {		                id: id,		                i: i,		                children: children,		                height: height,		                level: level,		                parent: parent,		                visible: false // @todo move this to better location		            };		            series.nodeMap[node.id] = node;		            if (point) {		                point.node = node;		            }		            return node;		        },		        setTreeValues: function (tree) {		            var series = this,		                options = series.options,		                idRoot = series.rootNode,		                mapIdToNode = series.nodeMap,		                nodeRoot = mapIdToNode[idRoot],		                levelIsConstant = (		                    isBoolean(options.levelIsConstant) ?		                        options.levelIsConstant :		                        true		                ),		                childrenTotal = 0,		                children = [],		                val,		                point = series.points[tree.i];		            // First give the children some values		            tree.children.forEach(function (child) {		                child = series.setTreeValues(child);		                children.push(child);		                if (!child.ignore) {		                    childrenTotal += child.val;		                }		            });		            // Sort the children		            stableSort(children, function (a, b) {		                return a.sortIndex - b.sortIndex;		            });		            // Set the values		            val = pick(point && point.options.value, childrenTotal);		            if (point) {		                point.value = val;		            }		            extend(tree, {		                children: children,		                childrenTotal: childrenTotal,		                // Ignore this node if point is not visible		                ignore: !(pick(point && point.visible, true) && (val > 0)),		                isLeaf: tree.visible && !childrenTotal,		                levelDynamic: (		                    tree.level - (levelIsConstant ? 0 : nodeRoot.level)		                ),		                name: pick(point && point.name, ''),		                sortIndex: pick(point && point.sortIndex, -val),		                val: val		            });		            return tree;		        },		        /**		         * Recursive function which calculates the area for all children of a		         * node.		         *		         * @private		         * @function Highcharts.Series#calculateChildrenAreas		         *		         * @param {object} node		         *        The node which is parent to the children.		         *		         * @param {object} area		         *        The rectangular area of the parent.		         */		        calculateChildrenAreas: function (parent, area) {		            var series = this,		                options = series.options,		                mapOptionsToLevel = series.mapOptionsToLevel,		                level = mapOptionsToLevel[parent.level + 1],		                algorithm = pick(		                    (		                        series[level &&		                    level.layoutAlgorithm] &&		                    level.layoutAlgorithm		                    ),		                    options.layoutAlgorithm		                ),		                alternate = options.alternateStartingDirection,		                childrenValues = [],		                children;		            // Collect all children which should be included		            children = parent.children.filter(function (n) {		                return !n.ignore;		            });		            if (level && level.layoutStartingDirection) {		                area.direction = level.layoutStartingDirection === 'vertical' ?		                    0 :		                    1;		            }		            childrenValues = series[algorithm](area, children);		            children.forEach(function (child, index) {		                var values = childrenValues[index];		                child.values = merge(values, {		                    val: child.childrenTotal,		                    direction: (alternate ? 1 - area.direction : area.direction)		                });		                child.pointValues = merge(values, {		                    x: (values.x / series.axisRatio),		                    width: (values.width / series.axisRatio)		                });		                // If node has children, then call method recursively		                if (child.children.length) {		                    series.calculateChildrenAreas(child, child.values);		                }		            });		        },		        setPointValues: function () {		            var series = this,		                xAxis = series.xAxis,		                yAxis = series.yAxis;		            series.points.forEach(function (point) {		                var node = point.node,		                    values = node.pointValues,		                    x1,		                    x2,		                    y1,		                    y2,		                    crispCorr = 0;		                // Get the crisp correction in classic mode. For this to work in		                // styled mode, we would need to first add the shape (without x,		                // y, width and height), then read the rendered stroke width		                // using point.graphic.strokeWidth(), then modify and apply the		                // shapeArgs. This applies also to column series, but the		                // downside is performance and code complexity.		                if (!series.chart.styledMode) {		                    crispCorr = (		                        (series.pointAttribs(point)['stroke-width'] || 0) % 2		                    ) / 2;		                }		                // Points which is ignored, have no values.		                if (values && node.visible) {		                    x1 = Math.round(		                        xAxis.translate(values.x, 0, 0, 0, 1)		                    ) - crispCorr;		                    x2 = Math.round(		                        xAxis.translate(values.x + values.width, 0, 0, 0, 1)		                    ) - crispCorr;		                    y1 = Math.round(		                        yAxis.translate(values.y, 0, 0, 0, 1)		                    ) - crispCorr;		                    y2 = Math.round(		                        yAxis.translate(values.y + values.height, 0, 0, 0, 1)		                    ) - crispCorr;		                    // Set point values		                    point.shapeType = 'rect';		                    point.shapeArgs = {		                        x: Math.min(x1, x2),		                        y: Math.min(y1, y2),		                        width: Math.abs(x2 - x1),		                        height: Math.abs(y2 - y1)		                    };		                    point.plotX =		                        point.shapeArgs.x + (point.shapeArgs.width / 2);		                    point.plotY =		                        point.shapeArgs.y + (point.shapeArgs.height / 2);		                } else {		                // Reset visibility		                    delete point.plotX;		                    delete point.plotY;		                }		            });		        },		        // Set the node's color recursively, from the parent down.		        setColorRecursive: function (		            node,		            parentColor,		            colorIndex,		            index,		            siblings		        ) {		            var series = this,		                chart = series && series.chart,		                colors = chart && chart.options && chart.options.colors,		                colorInfo,		                point;		            if (node) {		                colorInfo = getColor(node, {		                    colors: colors,		                    index: index,		                    mapOptionsToLevel: series.mapOptionsToLevel,		                    parentColor: parentColor,		                    parentColorIndex: colorIndex,		                    series: series,		                    siblings: siblings		                });		                point = series.points[node.i];		                if (point) {		                    point.color = colorInfo.color;		                    point.colorIndex = colorInfo.colorIndex;		                }		                // Do it all again with the children		                (node.children || []).forEach(function (child, i) {		                    series.setColorRecursive(		                        child,		                        colorInfo.color,		                        colorInfo.colorIndex,		                        i,		                        node.children.length		                    );		                });		            }		        },		        algorithmGroup: function (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));		                }		            };		            this.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);		            };		            this.reset = function () {		                this.nW = 0;		                this.lW = 0;		                this.elArr = [];		                this.total = 0;		            };		        },		        algorithmCalcPoints: function (		            directionChange, last, group, childrenArea		        ) {		            var pX,		                pY,		                pW,		                pH,		                gW = group.lW,		                gH = group.lH,		                plot = group.plot,		                keep,		                i = 0,		                end = group.elArr.length - 1;		            if (last) {		                gW = group.nW;		                gH = group.nH;		            } else {		                keep = group.elArr[group.elArr.length - 1];		            }		            group.elArr.forEach(function (p) {		                if (last || (i < end)) {		                    if (group.direction === 0) {		                        pX = plot.x;		                        pY = plot.y;		                        pW = gW;		                        pH = p / pW;		                    } else {		                        pX = plot.x;		                        pY = plot.y;		                        pH = gH;		                        pW = p / pH;		                    }		                    childrenArea.push({		                        x: pX,		                        y: pY,		                        width: pW,		                        height: pH		                    });		                    if (group.direction === 0) {		                        plot.y = plot.y + pH;		                    } else {		                        plot.x = plot.x + pW;		                    }		                }		                i = i + 1;		            });		            // Reset variables		            group.reset();		            if (group.direction === 0) {		                group.width = group.width - gW;		            } else {		                group.height = group.height - gH;		            }		            plot.y = plot.parent.y + (plot.parent.height - group.height);		            plot.x = plot.parent.x + (plot.parent.width - group.width);		            if (directionChange) {		                group.direction = 1 - group.direction;		            }		            // If not last, then add uncalculated element		            if (!last) {		                group.addElement(keep);		            }		        },		        algorithmLowAspectRatio: function (directionChange, parent, children) {		            var childrenArea = [],		                series = this,		                pTot,		                plot = {		                    x: parent.x,		                    y: parent.y,		                    parent: parent		                },		                direction = parent.direction,		                i = 0,		                end = children.length - 1,		                group = new this.algorithmGroup( // eslint-disable-line new-cap		                    parent.height,		                    parent.width,		                    direction,		                    plot		                );		            // Loop through and calculate all areas		            children.forEach(function (child) {		                pTot =		                    (parent.width * parent.height) * (child.val / parent.val);		                group.addElement(pTot);		                if (group.lP.nR > group.lP.lR) {		                    series.algorithmCalcPoints(		                        directionChange,		                        false,		                        group,		                        childrenArea,		                        plot		                    );		                }		                // If last child, then calculate all remaining areas		                if (i === end) {		                    series.algorithmCalcPoints(		                        directionChange,		                        true,		                        group,		                        childrenArea,		                        plot		                    );		                }		                i = i + 1;		            });		            return childrenArea;		        },		        algorithmFill: function (directionChange, parent, children) {		            var childrenArea = [],		                pTot,		                direction = parent.direction,		                x = parent.x,		                y = parent.y,		                width = parent.width,		                height = parent.height,		                pX,		                pY,		                pW,		                pH;		            children.forEach(function (child) {		                pTot =		                    (parent.width * parent.height) * (child.val / parent.val);		                pX = x;		                pY = y;		                if (direction === 0) {		                    pH = height;		                    pW = pTot / pH;		                    width = width - pW;		                    x = x + pW;		                } else {		                    pW = width;		                    pH = pTot / pW;		                    height = height - pH;		                    y = y + pH;		                }		                childrenArea.push({		                    x: pX,		                    y: pY,		                    width: pW,		                    height: pH		                });		                if (directionChange) {		                    direction = 1 - direction;		                }		            });		            return childrenArea;		        },		        strip: function (parent, children) {		            return this.algorithmLowAspectRatio(false, parent, children);		        },		        squarified: function (parent, children) {		            return this.algorithmLowAspectRatio(true, parent, children);		        },		        sliceAndDice: function (parent, children) {		            return this.algorithmFill(true, parent, children);		        },		        stripes: function (parent, children) {		            return this.algorithmFill(false, parent, children);		        },		        translate: function () {		            var series = this,		                options = series.options,		                // NOTE: updateRootId modifies series.		                rootId = updateRootId(series),		                rootNode,		                pointValues,		                seriesArea,		                tree,		                val;		            // Call prototype function		            Series.prototype.translate.call(series);		            // @todo Only if series.isDirtyData is true		            tree = series.tree = series.getTree();		            rootNode = series.nodeMap[rootId];		            series.mapOptionsToLevel = getLevelOptions({		                from: rootNode.level + 1,		                levels: options.levels,		                to: tree.height,		                defaults: {		                    levelIsConstant: series.options.levelIsConstant,		                    colorByPoint: options.colorByPoint		                }		            });		            if (		                rootId !== '' &&		            (!rootNode || !rootNode.children.length)		            ) {		                series.drillToNode('', false);		                rootId = series.rootNode;		                rootNode = series.nodeMap[rootId];		            }		            // Parents of the root node is by default visible		            recursive(series.nodeMap[series.rootNode], function (node) {		                var next = false,		                    p = node.parent;		                node.visible = true;		                if (p || p === '') {		                    next = series.nodeMap[p];		                }		                return next;		            });		            // Children of the root node is by default visible		            recursive(		                series.nodeMap[series.rootNode].children,		                function (children) {		                    var next = false;		                    children.forEach(function (child) {		                        child.visible = true;		                        if (child.children.length) {		                            next = (next || []).concat(child.children);		                        }		                    });		                    return next;		                }		            );		            series.setTreeValues(tree);		            // Calculate plotting values.		            series.axisRatio = (series.xAxis.len / series.yAxis.len);		            series.nodeMap[''].pointValues = pointValues =		            { x: 0, y: 0, width: 100, height: 100 };		            series.nodeMap[''].values = seriesArea = merge(pointValues, {		                width: (pointValues.width * series.axisRatio),		                direction: (		                    options.layoutStartingDirection === 'vertical' ? 0 : 1		                ),		                val: tree.val		            });		            series.calculateChildrenAreas(tree, seriesArea);		            // Logic for point colors		            if (series.colorAxis) {		                series.translateColors();		            } else if (!options.colorByPoint) {		                series.setColorRecursive(series.tree);		            }		            // Update axis extremes according to the root node.		            if (options.allowDrillToNode) {		                val = rootNode.pointValues;		                series.xAxis.setExtremes(val.x, val.x + val.width, false);		                series.yAxis.setExtremes(val.y, val.y + val.height, false);		                series.xAxis.setScale();		                series.yAxis.setScale();		            }		            // Assign values to points.		            series.setPointValues();		        },		        /**		         * Extend drawDataLabels with logic to handle custom options related to		         * the treemap series:		         *		         * - Points which is not a leaf node, has dataLabels disabled by		         *   default.		         *		         * - Options set on series.levels is merged in.		         *		         * - Width of the dataLabel is set to match the width of the point		         *   shape.		         *		         * @private		         * @function Highcharts.Series#drawDataLabels		         */		        drawDataLabels: function () {		            var series = this,		                mapOptionsToLevel = series.mapOptionsToLevel,		                points = series.points.filter(function (n) {		                    return n.node.visible;		                }),		                options,		                level;		            points.forEach(function (point) {		                level = mapOptionsToLevel[point.node.level];		                // Set options to new object to avoid problems with scope		                options = { style: {} };		                // If not a leaf, then label should be disabled as default		                if (!point.node.isLeaf) {		                    options.enabled = false;		                }		                // If options for level exists, include them as well		                if (level && level.dataLabels) {		                    options = merge(options, level.dataLabels);		                    series._hasPointLabels = true;		                }		                // Set dataLabel width to the width of the point shape.		                if (point.shapeArgs) {		                    options.style.width = point.shapeArgs.width;		                    if (point.dataLabel) {		                        point.dataLabel.css({		                            width: point.shapeArgs.width + 'px'		                        });		                    }		                }		                // Merge custom options with point options		                point.dlOptions = merge(options, point.options.dataLabels);		            });		            Series.prototype.drawDataLabels.call(this);		        },		        // Over the alignment method by setting z index		        alignDataLabel: function (point, dataLabel, labelOptions) {		            var style = labelOptions.style;		            // #8160: Prevent the label from exceeding the point's		            // boundaries in treemaps by applying ellipsis overflow.		            // The issue was happening when datalabel's text contained a		            // long sequence of characters without a whitespace.		            if (		                !H.defined(style.textOverflow) &&		                dataLabel.text &&		                dataLabel.getBBox().width > dataLabel.text.textWidth		            ) {		                dataLabel.css({		                    textOverflow: 'ellipsis',		                    // unit (px) is required when useHTML is true		                    width: style.width += 'px'		                });		            }		            seriesTypes.column.prototype.alignDataLabel.apply(this, arguments);		            if (point.dataLabel) {		            // point.node.zIndex could be undefined (#6956)		                point.dataLabel.attr({ zIndex: (point.node.zIndex || 0) + 1 });		            }		        },		        // Get presentational attributes		        pointAttribs: function (point, state) {		            var series = this,		                mapOptionsToLevel = (		                    isObject(series.mapOptionsToLevel) ?		                        series.mapOptionsToLevel :		                        {}		                ),		                level = point && mapOptionsToLevel[point.node.level] || {},		                options = this.options,		                attr,		                stateOptions = (state && options.states[state]) || {},		                className = (point && point.getClassName()) || '',		                opacity;		            // Set attributes by precedence. Point trumps level trumps series.		            // Stroke width uses pick because it can be 0.		            attr = {		                'stroke':		                (point && point.borderColor) ||		                level.borderColor ||		                stateOptions.borderColor ||		                options.borderColor,		                'stroke-width': pick(		                    point && point.borderWidth,		                    level.borderWidth,		                    stateOptions.borderWidth,		                    options.borderWidth		                ),		                'dashstyle':		                (point && point.borderDashStyle) ||		                level.borderDashStyle ||		                stateOptions.borderDashStyle ||		                options.borderDashStyle,		                'fill': (point && point.color) || this.color		            };		            // Hide levels above the current view		            if (className.indexOf('highcharts-above-level') !== -1) {		                attr.fill = 'none';		                attr['stroke-width'] = 0;		                // Nodes with children that accept interaction		            } else if (		                className.indexOf('highcharts-internal-node-interactive') !== -1		            ) {		                opacity = pick(stateOptions.opacity, options.opacity);		                attr.fill = color(attr.fill).setOpacity(opacity).get();		                attr.cursor = 'pointer';		                // Hide nodes that have children		            } else if (className.indexOf('highcharts-internal-node') !== -1) {		                attr.fill = 'none';		            } else if (state) {		            // Brighten and hoist the hover nodes		                attr.fill = color(attr.fill)		                    .brighten(stateOptions.brightness)		                    .get();		            }		            return attr;		        },		        // Extending ColumnSeries drawPoints		        drawPoints: function () {		            var series = this,		                points = series.points.filter(function (n) {		                    return n.node.visible;		                });		            points.forEach(function (point) {		                var groupKey = 'level-group-' + point.node.levelDynamic;		                if (!series[groupKey]) {		                    series[groupKey] = series.chart.renderer.g(groupKey)		                        .attr({		                        // @todo Set the zIndex based upon the number of levels,		                        // instead of using 1000		                            zIndex: 1000 - point.node.levelDynamic		                        })		                        .add(series.group);		                }		                point.group = series[groupKey];		            });		            // Call standard drawPoints		            seriesTypes.column.prototype.drawPoints.call(this);		            // In styled mode apply point.color. Use CSS, otherwise the fill		            // used in the style sheet will take precedence over the fill		            // attribute.		            if (this.colorAttribs && series.chart.styledMode) {		                // Heatmap is loaded		                this.points.forEach(function (point) {		                    if (point.graphic) {		                        point.graphic.css(this.colorAttribs(point));		                    }		                }, this);		            }		            // If drillToNode is allowed, set a point cursor on clickables & add		            // drillId to point		            if (series.options.allowDrillToNode) {		                points.forEach(function (point) {		                    if (point.graphic) {		                        point.drillId = series.options.interactByLeaf ?		                            series.drillToByLeaf(point) :		                            series.drillToByGroup(point);		                    }		                });		            }		        },		        // Add drilling on the suitable points		        onClickDrillToNode: function (event) {		            var series = this,		                point = event.point,		                drillId = point && point.drillId;		            // If a drill id is returned, add click event and cursor.		            if (isString(drillId)) {		                point.setState(''); // Remove hover		                series.drillToNode(drillId);		            }		        },		        /**		         * Finds the drill id for a parent node. Returns false if point should		         * not have a click event.		         *		         * @private		         * @function Highcharts.Series#drillToByGroup		         *		         * @param {object} point		         *		         * @return {boolean|string}		         *         Drill to id or false when point should not have a click		         *         event.		         */		        drillToByGroup: function (point) {		            var series = this,		                drillId = false;		            if ((point.node.level - series.nodeMap[series.rootNode].level) ===		                1 &&		                !point.node.isLeaf		            ) {		                drillId = point.id;		            }		            return drillId;		        },		        /**		         * Finds the drill id for a leaf node. Returns false if point should not		         * have a click event		         *		         * @private		         * @function Highcharts.Series#drillToByLeaf		         *		         * @param {object} point		         *		         * @return {boolean|string}		         *         Drill to id or false when point should not have a click		         *         event.		         */		        drillToByLeaf: function (point) {		            var series = this,		                drillId = false,		                nodeParent;		            if ((point.node.parent !== series.rootNode) &&		                point.node.isLeaf		            ) {		                nodeParent = point.node;		                while (!drillId) {		                    nodeParent = series.nodeMap[nodeParent.parent];		                    if (nodeParent.parent === series.rootNode) {		                        drillId = nodeParent.id;		                    }		                }		            }		            return drillId;		        },		        drillUp: function () {		            var series = this,		                node = series.nodeMap[series.rootNode];		            if (node && isString(node.parent)) {		                series.drillToNode(node.parent);		            }		        },		        drillToNode: function (id, redraw) {		            var series = this,		                nodeMap = series.nodeMap,		                node = nodeMap[id];		            series.idPreviousRoot = series.rootNode;		            series.rootNode = id;		            if (id === '') {		                series.drillUpButton = series.drillUpButton.destroy();		            } else {		                series.showDrillUpButton((node && node.name || id));		            }		            this.isDirty = true; // Force redraw		            if (pick(redraw, true)) {		                this.chart.redraw();		            }		        },		        showDrillUpButton: function (name) {		            var series = this,		                backText = (name || '< Back'),		                buttonOptions = series.options.drillUpButton,		                attr,		                states;		            if (buttonOptions.text) {		                backText = buttonOptions.text;		            }		            if (!this.drillUpButton) {		                attr = buttonOptions.theme;		                states = attr && attr.states;		                this.drillUpButton = this.chart.renderer.button(		                    backText,		                    null,		                    null,		                    function () {		                        series.drillUp();		                    },		                    attr,		                    states && states.hover,		                    states && states.select		                )		                    .addClass('highcharts-drillup-button')		                    .attr({		                        align: buttonOptions.position.align,		                        zIndex: 7		                    })		                    .add()		                    .align(		                        buttonOptions.position,		                        false,		                        buttonOptions.relativeTo || 'plotBox'		                    );		            } else {		                this.drillUpButton.placed = false;		                this.drillUpButton.attr({		                    text: backText		                })		                    .align();		            }		        },		        buildKDTree: noop,		        drawLegendSymbol: H.LegendSymbolMixin.drawRectangle,		        getExtremes: function () {		        // Get the extremes from the value data		            Series.prototype.getExtremes.call(this, this.colorValueData);		            this.valueMin = this.dataMin;		            this.valueMax = this.dataMax;		            // Get the extremes from the y data		            Series.prototype.getExtremes.call(this);		        },		        getExtremesFromAll: true,		        bindAxes: function () {		            var treeAxis = {		                endOnTick: false,		                gridLineWidth: 0,		                lineWidth: 0,		                min: 0,		                dataMin: 0,		                minPadding: 0,		                max: 100,		                dataMax: 100,		                maxPadding: 0,		                startOnTick: false,		                title: null,		                tickPositions: []		            };		            Series.prototype.bindAxes.call(this);		            H.extend(this.yAxis.options, treeAxis);		            H.extend(this.xAxis.options, treeAxis);		        },		        utils: {		            recursive: recursive		        }		        // Point class		    }, {		        getClassName: function () {		            var className = H.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.allowDrillToNode)		            ) {		                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		         */		        isValid: function () {		            return this.id || isNumber(this.value);		        },		        setState: function (state) {		            H.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		                });		            }		        },		        setVisible: seriesTypes.pie.prototype.pointClass.prototype.setVisible		    }		);		/**		 * A `treemap` series. If the [type](#series.treemap.type) option is		 * not specified, it is inherited from [chart.type](#chart.type).		 *		 * @extends   series,plotOptions.treemap		 * @excluding dataParser, dataURL, stack		 * @product   highcharts		 * @apioption series.treemap		 */		/**		 * An array of data points for the series. For the `treemap` series		 * type, points can be given in the following ways:		 *		 * 1.  An array of numerical values. In this case, the numerical values		 * will be interpreted as `value` options. Example:		 *		 *  ```js		 *  data: [0, 5, 3, 5]		 *  ```		 *		 * 2.  An array of objects with named values. The following snippet shows only a		 * few settings, see the complete options set below. If the total number of data		 * points exceeds the series' [turboThreshold](#series.treemap.turboThreshold),		 * this option is not available.		 *		 *  ```js		 *     data: [{		 *         value: 9,		 *         name: "Point2",		 *         color: "#00FF00"		 *     }, {		 *         value: 6,		 *         name: "Point1",		 *         color: "#FF00FF"		 *     }]		 *  ```		 *		 * @sample {highcharts} highcharts/chart/reflow-true/		 *         Numerical values		 * @sample {highcharts} highcharts/series/data-array-of-objects/		 *         Config objects		 *		 * @type      {Array<number|*>}		 * @extends   series.heatmap.data		 * @excluding x, y		 * @product   highcharts		 * @apioption series.treemap.data		 */		/**		 * The value of the point, resulting in a relative area of the point		 * in the treemap.		 *		 * @type      {number}		 * @product   highcharts		 * @apioption series.treemap.data.value		 */		/**		 * Serves a purpose only if a `colorAxis` object is defined in the chart		 * options. This value will decide which color the point gets from the		 * scale of the colorAxis.		 *		 * @type      {number}		 * @since     4.1.0		 * @product   highcharts		 * @apioption series.treemap.data.colorValue		 */		/**		 * Only for treemap. Use this option to build a tree structure. The		 * value should be the id of the point which is the parent. If no points		 * has a matching id, or this option is undefined, then the parent will		 * be set to the root.		 *		 * @sample {highcharts} highcharts/point/parent/		 *         Point parent		 * @sample {highcharts} highcharts/demo/treemap-with-levels/		 *         Example where parent id is not matching		 *		 * @type      {string}		 * @since     4.1.0		 * @product   highcharts		 * @apioption series.treemap.data.parent		 */	}(Highcharts, result));	(function (H, drawPoint, mixinTreeSeries) {		/* *		 *		 *  This module implements sunburst charts in Highcharts.		 *		 *  (c) 2016-2019 Highsoft AS		 *		 *  Authors: Jon Arild Nygard		 *		 *  License: www.highcharts.com/license		 *		 * */		var CenteredSeriesMixin = H.CenteredSeriesMixin,		    Series = H.Series,		    extend = H.extend,		    getCenter = CenteredSeriesMixin.getCenter,		    getColor = mixinTreeSeries.getColor,		    getLevelOptions = mixinTreeSeries.getLevelOptions,		    getStartAndEndRadians = CenteredSeriesMixin.getStartAndEndRadians,		    isBoolean = function (x) {		        return typeof x === 'boolean';		    },		    isNumber = H.isNumber,		    isObject = H.isObject,		    isString = H.isString,		    merge = H.merge,		    noop = H.noop,		    rad2deg = 180 / Math.PI,		    seriesType = H.seriesType,		    seriesTypes = H.seriesTypes,		    setTreeValues = mixinTreeSeries.setTreeValues,		    updateRootId = mixinTreeSeries.updateRootId;		// TODO introduce step, which should default to 1.		var range = function range(from, to) {		    var result = [],		        i;		    if (isNumber(from) && isNumber(to) && from <= to) {		        for (i = from; i <= to; i++) {		            result.push(i);		        }		    }		    return result;		};		/**		 * @private		 * @function calculateLevelSizes		 *		 * @param {object} levelOptions		 *        Map of level to its options.		 *		 * @param {object} params		 *        Object containing number parameters `innerRadius` and `outerRadius`.		 */		var calculateLevelSizes = function calculateLevelSizes(levelOptions, params) {		    var result,		        p = isObject(params) ? params : {},		        totalWeight = 0,		        diffRadius,		        levels,		        levelsNotIncluded,		        remainingSize,		        from,		        to;		    if (isObject(levelOptions)) {		        result = merge({}, levelOptions); // Copy levelOptions		        from = isNumber(p.from) ? p.from : 0;		        to = isNumber(p.to) ? p.to : 0;		        levels = range(from, to);		        levelsNotIncluded = Object.keys(result).filter(function (k) {		            return levels.indexOf(+k) === -1;		        });		        diffRadius = remainingSize = isNumber(p.diffRadius) ? p.diffRadius : 0;		        // Convert percentage to pixels.		        // Calculate the remaining size to divide between "weight" levels.		        // Calculate total weight to use in convertion from weight to pixels.		        levels.forEach(function (level) {		            var options = result[level],		                unit = options.levelSize.unit,		                value = options.levelSize.value;		            if (unit === 'weight') {		                totalWeight += value;		            } else if (unit === 'percentage') {		                options.levelSize = {		                    unit: 'pixels',		                    value: (value / 100) * diffRadius		                };		                remainingSize -= options.levelSize.value;		            } else if (unit === 'pixels') {		                remainingSize -= value;		            }		        });		        // Convert weight to pixels.		        levels.forEach(function (level) {		            var options = result[level],		                weight;		            if (options.levelSize.unit === 'weight') {		                weight = options.levelSize.value;		                result[level].levelSize = {		                    unit: 'pixels',		                    value: (weight / totalWeight) * remainingSize		                };		            }		        });		        // Set all levels not included in interval [from,to] to have 0 pixels.		        levelsNotIncluded.forEach(function (level) {		            result[level].levelSize = {		                value: 0,		                unit: 'pixels'		            };		        });		    }		    return result;		};		/**		 * Find a set of coordinates given a start coordinates, an angle, and a		 * distance.		 *		 * @private		 * @function getEndPoint		 *		 * @param {number} x		 *        Start coordinate x		 *		 * @param {number} y		 *        Start coordinate y		 *		 * @param {number} angle		 *        Angle in radians		 *		 * @param {number} distance		 *        Distance from start to end coordinates		 *		 * @return {Highcharts.SVGAttributes}		 *         Returns the end coordinates, x and y.		 */		var getEndPoint = function getEndPoint(x, y, angle, distance) {		    return {		        x: x + (Math.cos(angle) * distance),		        y: y + (Math.sin(angle) * distance)		    };		};		var layoutAlgorithm = function layoutAlgorithm(parent, children, options) {		    var startAngle = parent.start,		        range = parent.end - startAngle,		        total = parent.val,		        x = parent.x,		        y = parent.y,		        radius = (		            (		                options &&		                isObject(options.levelSize) &&		                isNumber(options.levelSize.value)		            ) ?		                options.levelSize.value :		                0		        ),		        innerRadius = parent.r,		        outerRadius = innerRadius + radius,		        slicedOffset = options && isNumber(options.slicedOffset) ?		            options.slicedOffset :		            0;		    return (children || []).reduce(function (arr, child) {		        var percentage = (1 / total) * child.val,		            radians = percentage * range,		            radiansCenter = startAngle + (radians / 2),		            offsetPosition = getEndPoint(x, y, radiansCenter, slicedOffset),		            values = {		                x: child.sliced ? offsetPosition.x : x,		                y: child.sliced ? offsetPosition.y : y,		                innerR: innerRadius,		                r: outerRadius,		                radius: radius,		                start: startAngle,		                end: startAngle + radians		            };		        arr.push(values);		        startAngle = values.end;		        return arr;		    }, []);		};		var getDlOptions = function getDlOptions(params) {		    // Set options to new object to avoid problems with scope		    var point = params.point,		        shape = isObject(params.shapeArgs) ? params.shapeArgs : {},		        optionsPoint = (		            isObject(params.optionsPoint) ?		                params.optionsPoint.dataLabels :		                {}		        ),		        optionsLevel = (		            isObject(params.level) ?		                params.level.dataLabels :		                {}		        ),		        options = merge({		            style: {}		        }, optionsLevel, optionsPoint),		        rotationRad,		        rotation,		        rotationMode = options.rotationMode;		    if (!isNumber(options.rotation)) {		        if (rotationMode === 'auto') {		            if (		                point.innerArcLength < 1 &&		                point.outerArcLength > shape.radius		            ) {		                rotationRad = 0;		            } else if (		                point.innerArcLength > 1 &&		                point.outerArcLength > 1.5 * shape.radius		            ) {		                rotationMode = 'parallel';		            } else {		                rotationMode = 'perpendicular';		            }		        }		        if (rotationMode !== 'auto') {		            rotationRad = (shape.end - (shape.end - shape.start) / 2);		        }		        if (rotationMode === 'parallel') {		            options.style.width = Math.min(		                shape.radius * 2.5,		                (point.outerArcLength + point.innerArcLength) / 2		            );		        } else {		            options.style.width = shape.radius;		        }		        if (		            rotationMode === 'perpendicular' &&		            point.series.chart.renderer.fontMetrics(options.style.fontSize).h >		            point.outerArcLength		        ) {		            options.style.width = 1;		        }		        // Apply padding (#8515)		        options.style.width = Math.max(		            options.style.width - 2 * (options.padding || 0),		            1		        );		        rotation = (rotationRad * rad2deg) % 180;		        if (rotationMode === 'parallel') {		            rotation -= 90;		        }		        // Prevent text from rotating upside down		        if (rotation > 90) {		            rotation -= 180;		        } else if (rotation < -90) {		            rotation += 180;		        }		        options.rotation = rotation;		    }		    // NOTE: alignDataLabel positions the data label differntly when rotation is		    // 0. Avoiding this by setting rotation to a small number.		    if (options.rotation === 0) {		        options.rotation = 0.001;		    }		    return options;		};		var getAnimation = function getAnimation(shape, params) {		    var point = params.point,		        radians = params.radians,		        innerR = params.innerR,		        idRoot = params.idRoot,		        idPreviousRoot = params.idPreviousRoot,		        shapeExisting = params.shapeExisting,		        shapeRoot = params.shapeRoot,		        shapePreviousRoot = params.shapePreviousRoot,		        visible = params.visible,		        from = {},		        to = {		            end: shape.end,		            start: shape.start,		            innerR: shape.innerR,		            r: shape.r,		            x: shape.x,		            y: shape.y		        };		    if (visible) {		        // Animate points in		        if (!point.graphic && shapePreviousRoot) {		            if (idRoot === point.id) {		                from = {		                    start: radians.start,		                    end: radians.end		                };		            } else {		                from = (shapePreviousRoot.end <= shape.start) ? {		                    start: radians.end,		                    end: radians.end		                } : {		                    start: radians.start,		                    end: radians.start		                };		            }		            // Animate from center and outwards.		            from.innerR = from.r = innerR;		        }		    } else {		        // Animate points out		        if (point.graphic) {		            if (idPreviousRoot === point.id) {		                to = {		                    innerR: innerR,		                    r: innerR		                };		            } else if (shapeRoot) {		                to = (shapeRoot.end <= shapeExisting.start) ?		                    {		                        innerR: innerR,		                        r: innerR,		                        start: radians.end,		                        end: radians.end		                    } : {		                        innerR: innerR,		                        r: innerR,		                        start: radians.start,		                        end: radians.start		                    };		            }		        }		    }		    return {		        from: from,		        to: to		    };		};		var getDrillId = function getDrillId(point, idRoot, mapIdToNode) {		    var drillId,		        node = point.node,		        nodeRoot;		    if (!node.isLeaf) {		        // When it is the root node, the drillId should be set to parent.		        if (idRoot === point.id) {		            nodeRoot = mapIdToNode[idRoot];		            drillId = nodeRoot.parent;		        } else {		            drillId = point.id;		        }		    }		    return drillId;		};		var cbSetTreeValuesBefore = function before(node, options) {		    var mapIdToNode = options.mapIdToNode,		        nodeParent = mapIdToNode[node.parent],		        series = options.series,		        chart = series.chart,		        points = series.points,		        point = points[node.i],		        colorInfo = getColor(node, {		            colors: chart && chart.options && chart.options.colors,		            colorIndex: series.colorIndex,		            index: options.index,		            mapOptionsToLevel: options.mapOptionsToLevel,		            parentColor: nodeParent && nodeParent.color,		            parentColorIndex: nodeParent && nodeParent.colorIndex,		            series: options.series,		            siblings: options.siblings		        });		    node.color = colorInfo.color;		    node.colorIndex = colorInfo.colorIndex;		    if (point) {		        point.color = node.color;		        point.colorIndex = node.colorIndex;		        // Set slicing on node, but avoid slicing the top node.		        node.sliced = (node.id !== options.idRoot) ? point.sliced : false;		    }		    return node;		};		/**		 * A Sunburst displays hierarchical data, where a level in the hierarchy is		 * represented by a circle. The center represents the root node of the tree.		 * The visualization bears a resemblance to both treemap and pie charts.		 *		 * @sample highcharts/demo/sunburst		 *         Sunburst chart		 *		 * @extends      plotOptions.pie		 * @excluding    allAreas, clip, colorAxis, compare, compareBase, dataGrouping,		 *               depth, endAngle, gapSize, gapUnit, ignoreHiddenPoint,		 *               innerSize, joinBy, legendType, linecap, minSize,		 *               navigatorOptions, pointRange		 * @product      highcharts		 * @optionparent plotOptions.sunburst		 */		var sunburstOptions = {		    /**		     * Set options on specific levels. Takes precedence over series options,		     * but not point options.		     *		     * @sample highcharts/demo/sunburst		     *         Sunburst chart		     *		     * @type      {Array<*>}		     * @apioption plotOptions.sunburst.levels		     */		    /**		     * Can set a `borderColor` on all points which lies on the same level.		     *		     * @type      {Highcharts.ColorString}		     * @apioption plotOptions.sunburst.levels.borderColor		     */		    /**		     * Can set a `borderWidth` on all points which lies on the same level.		     *		     * @type      {number}		     * @apioption plotOptions.sunburst.levels.borderWidth		     */		    /**		     * Can set a `borderDashStyle` on all points which lies on the same level.		     *		     * @type      {string}		     * @apioption plotOptions.sunburst.levels.borderDashStyle		     */		    /**		     * Can set a `color` on all points which lies on the same level.		     *		     * @type      {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}		     * @apioption plotOptions.sunburst.levels.color		     */		    /**		     * Can set a `colorVariation` on all points which lies on the same level.		     *		     * @apioption plotOptions.sunburst.levels.colorVariation		     */		    /**		     * The key of a color variation. Currently supports `brightness` only.		     *		     * @type      {string}		     * @apioption plotOptions.sunburst.levels.colorVariation.key		     */		    /**		     * The ending value of a color variation. The last sibling will receive this		     * value.		     *		     * @type      {number}		     * @apioption plotOptions.sunburst.levels.colorVariation.to		     */		    /**		     * Can set `dataLabels` on all points which lies on the same level.		     *		     * @type      {object}		     * @apioption plotOptions.sunburst.levels.dataLabels		     */		    /**		     * Can set a `levelSize` on all points which lies on the same level.		     *		     * @type      {object}		     * @apioption plotOptions.sunburst.levels.levelSize		     */		    /**		     * Can set a `rotation` on all points which lies on the same level.		     *		     * @type      {number}		     * @apioption plotOptions.sunburst.levels.rotation		     */		    /**		     * Can set a `rotationMode` on all points which lies on the same level.		     *		     * @type      {string}		     * @apioption plotOptions.sunburst.levels.rotationMode		     */		    /**		     * When enabled the user can click on a point which is a parent and		     * zoom in on its children.		     *		     * @sample highcharts/demo/sunburst		     *         Allow drill to node		     *		     * @type      {boolean}		     * @default   false		     * @apioption plotOptions.sunburst.allowDrillToNode		     */		    /**		     * The center of the sunburst chart relative to the plot area. Can be		     * percentages or pixel values.		     *		     * @sample {highcharts} highcharts/plotoptions/pie-center/		     *         Centered at 100, 100		     *		     * @type    {Array<number|string>}		     * @default ["50%", "50%"]		     * @product highcharts		     */		    center: ['50%', '50%'],		    colorByPoint: false,		    /**		     * @extends   plotOptions.series.dataLabels		     * @excluding align, allowOverlap, distance, staggerLines, step		     */		    dataLabels: {		        allowOverlap: true,		        defer: true,		        style: {		            textOverflow: 'ellipsis'		        },		        /**		         * Decides how the data label will be rotated relative to the perimeter		         * of the sunburst. Valid values are `auto`, `parallel` and		         * `perpendicular`. When `auto`, the best fit will be computed for the		         * point.		         *		         * The `series.rotation` option takes precedence over `rotationMode`.		         *		         * @since      6.0.0		         * @validvalue ["auto", "perpendicular", "parallel"]		         */		        rotationMode: 'auto'		    },		    /**		     * Which point to use as a root in the visualization.		     *		     * @type {string}		     */		    rootId: undefined,		    /**		     * Used together with the levels and `allowDrillToNode` options. When		     * set to false the first level visible when drilling is considered		     * to be level one. Otherwise the level will be the same as the tree		     * structure.		     */		    levelIsConstant: true,		    /**		     * Determines the width of the ring per level.		     *		     * @sample {highcharts} highcharts/plotoptions/sunburst-levelsize/		     *         Sunburst with various sizes per level		     *		     * @since 6.0.5		     */		    levelSize: {		        /**		         * The value used for calculating the width of the ring. Its' affect is		         * determined by `levelSize.unit`.		         *		         * @sample {highcharts} highcharts/plotoptions/sunburst-levelsize/		         *         Sunburst with various sizes per level		         */		        value: 1,		        /**		         * How to interpret `levelSize.value`.		         *		         * - `percentage` gives a width relative to result of outer radius minus		         *   inner radius.		         *		         * - `pixels` gives the ring a fixed width in pixels.		         *		         * - `weight` takes the remaining width after percentage and pixels, and		         *   distributes it accross all "weighted" levels. The value relative to		         *   the sum of all weights determines the width.		         *		         * @sample {highcharts} highcharts/plotoptions/sunburst-levelsize/		         *         Sunburst with various sizes per level		         *		         * @validvalue ["percentage", "pixels", "weight"]		         */		        unit: 'weight'		    },		    /**		     * If a point is sliced, moved out from the center, how many pixels		     * should it be moved?.		     *		     * @sample highcharts/plotoptions/sunburst-sliced		     *         Sliced sunburst		     *		     * @since 6.0.4		     */		    slicedOffset: 10		};		// Properties of the Sunburst series.		var sunburstSeries = {		    drawDataLabels: noop, // drawDataLabels is called in drawPoints		    drawPoints: function drawPoints() {		        var series = this,		            mapOptionsToLevel = series.mapOptionsToLevel,		            shapeRoot = series.shapeRoot,		            group = series.group,		            hasRendered = series.hasRendered,		            idRoot = series.rootNode,		            idPreviousRoot = series.idPreviousRoot,		            nodeMap = series.nodeMap,		            nodePreviousRoot = nodeMap[idPreviousRoot],		            shapePreviousRoot = nodePreviousRoot && nodePreviousRoot.shapeArgs,		            points = series.points,		            radians = series.startAndEndRadians,		            chart = series.chart,		            optionsChart = chart && chart.options && chart.options.chart || {},		            animation = (		                isBoolean(optionsChart.animation) ?		                    optionsChart.animation :		                    true		            ),		            positions = series.center,		            center = {		                x: positions[0],		                y: positions[1]		            },		            innerR = positions[3] / 2,		            renderer = series.chart.renderer,		            animateLabels,		            animateLabelsCalled = false,		            addedHack = false,		            hackDataLabelAnimation = !!(		                animation &&		                hasRendered &&		                idRoot !== idPreviousRoot &&		                series.dataLabelsGroup		            );		        if (hackDataLabelAnimation) {		            series.dataLabelsGroup.attr({ opacity: 0 });		            animateLabels = function () {		                var s = series;		                animateLabelsCalled = true;		                if (s.dataLabelsGroup) {		                    s.dataLabelsGroup.animate({		                        opacity: 1,		                        visibility: 'visible'		                    });		                }		            };		        }		        points.forEach(function (point) {		            var node = point.node,		                level = mapOptionsToLevel[node.level],		                shapeExisting = point.shapeExisting || {},		                shape = node.shapeArgs || {},		                animationInfo,		                onComplete,		                visible = !!(node.visible && node.shapeArgs);		            if (hasRendered && animation) {		                animationInfo = getAnimation(shape, {		                    center: center,		                    point: point,		                    radians: radians,		                    innerR: innerR,		                    idRoot: idRoot,		                    idPreviousRoot: idPreviousRoot,		                    shapeExisting: shapeExisting,		                    shapeRoot: shapeRoot,		                    shapePreviousRoot: shapePreviousRoot,		                    visible: visible		                });		            } else {		                // When animation is disabled, attr is called from animation.		                animationInfo = {		                    to: shape,		                    from: {}		                };		            }		            extend(point, {		                shapeExisting: shape, // Store for use in animation		                tooltipPos: [shape.plotX, shape.plotY],		                drillId: getDrillId(point, idRoot, nodeMap),		                name: '' + (point.name || point.id || point.index),		                plotX: shape.plotX, // used for data label position		                plotY: shape.plotY, // used for data label position		                value: node.val,		                isNull: !visible // used for dataLabels & point.draw		            });		            point.dlOptions = getDlOptions({		                point: point,		                level: level,		                optionsPoint: point.options,		                shapeArgs: shape		            });		            if (!addedHack && visible) {		                addedHack = true;		                onComplete = animateLabels;		            }		            point.draw({		                animatableAttribs: animationInfo.to,		                attribs: extend(		                    animationInfo.from,		                    !chart.styledMode && series.pointAttribs(		                        point,		                        point.selected && 'select'		                    )		                ),		                onComplete: onComplete,		                group: group,		                renderer: renderer,		                shapeType: 'arc',		                shapeArgs: shape		            });		        });		        // Draw data labels after points		        // TODO draw labels one by one to avoid addtional looping		        if (hackDataLabelAnimation && addedHack) {		            series.hasRendered = false;		            series.options.dataLabels.defer = true;		            Series.prototype.drawDataLabels.call(series);		            series.hasRendered = true;		            // If animateLabels is called before labels were hidden, then call		            // it again.		            if (animateLabelsCalled) {		                animateLabels();		            }		        } else {		            Series.prototype.drawDataLabels.call(series);		        }		    },		    pointAttribs: seriesTypes.column.prototype.pointAttribs,		    // The layout algorithm for the levels		    layoutAlgorithm: layoutAlgorithm,		    // Set the shape arguments on the nodes. Recursive from root down.		    setShapeArgs: function (parent, parentValues, mapOptionsToLevel) {		        var childrenValues = [],		            level = parent.level + 1,		            options = mapOptionsToLevel[level],		            // Collect all children which should be included		            children = parent.children.filter(function (n) {		                return n.visible;		            }),		            twoPi = 6.28; // Two times Pi.		        childrenValues = this.layoutAlgorithm(parentValues, children, options);		        children.forEach(function (child, index) {		            var values = childrenValues[index],		                angle = values.start + ((values.end - values.start) / 2),		                radius = values.innerR + ((values.r - values.innerR) / 2),		                radians = (values.end - values.start),		                isCircle = (values.innerR === 0 && radians > twoPi),		                center = (		                    isCircle ?		                        { x: values.x, y: values.y } :		                        getEndPoint(values.x, values.y, angle, radius)		                ),		                val = (		                    child.val ?		                        (		                            child.childrenTotal > child.val ?		                                child.childrenTotal :		                                child.val		                        ) :		                        child.childrenTotal		                );		            // The inner arc length is a convenience for data label filters.		            if (this.points[child.i]) {		                this.points[child.i].innerArcLength = radians * values.innerR;		                this.points[child.i].outerArcLength = radians * values.r;		            }		            child.shapeArgs = merge(values, {		                plotX: center.x,		                plotY: center.y + 4 * Math.abs(Math.cos(angle))		            });		            child.values = merge(values, {		                val: val		            });		            // If node has children, then call method recursively		            if (child.children.length) {		                this.setShapeArgs(child, child.values, mapOptionsToLevel);		            }		        }, this);		    },		    translate: function translate() {		        var series = this,		            options = series.options,		            positions = series.center = getCenter.call(series),		            radians = series.startAndEndRadians = getStartAndEndRadians(		                options.startAngle,		                options.endAngle		            ),		            innerRadius = positions[3] / 2,		            outerRadius = positions[2] / 2,		            diffRadius = outerRadius - innerRadius,		            // NOTE: updateRootId modifies series.		            rootId = updateRootId(series),		            mapIdToNode = series.nodeMap,		            mapOptionsToLevel,		            idTop,		            nodeRoot = mapIdToNode && mapIdToNode[rootId],		            nodeTop,		            tree,		            values;		        series.shapeRoot = nodeRoot && nodeRoot.shapeArgs;		        // Call prototype function		        Series.prototype.translate.call(series);		        // @todo Only if series.isDirtyData is true		        tree = series.tree = series.getTree();		        mapIdToNode = series.nodeMap;		        nodeRoot = mapIdToNode[rootId];		        idTop = isString(nodeRoot.parent) ? nodeRoot.parent : '';		        nodeTop = mapIdToNode[idTop];		        mapOptionsToLevel = getLevelOptions({		            from: nodeRoot.level > 0 ? nodeRoot.level : 1,		            levels: series.options.levels,		            to: tree.height,		            defaults: {		                colorByPoint: options.colorByPoint,		                dataLabels: options.dataLabels,		                levelIsConstant: options.levelIsConstant,		                levelSize: options.levelSize,		                slicedOffset: options.slicedOffset		            }		        });		        // NOTE consider doing calculateLevelSizes in a callback to		        // getLevelOptions		        mapOptionsToLevel = calculateLevelSizes(mapOptionsToLevel, {		            diffRadius: diffRadius,		            from: nodeRoot.level > 0 ? nodeRoot.level : 1,		            to: tree.height		        });		        // TODO Try to combine setTreeValues & setColorRecursive to avoid		        //  unnecessary looping.		        setTreeValues(tree, {		            before: cbSetTreeValuesBefore,		            idRoot: rootId,		            levelIsConstant: options.levelIsConstant,		            mapOptionsToLevel: mapOptionsToLevel,		            mapIdToNode: mapIdToNode,		            points: series.points,		            series: series		        });		        values = mapIdToNode[''].shapeArgs = {		            end: radians.end,		            r: innerRadius,		            start: radians.start,		            val: nodeRoot.val,		            x: positions[0],		            y: positions[1]		        };		        this.setShapeArgs(nodeTop, values, mapOptionsToLevel);		        // Set mapOptionsToLevel on series for use in drawPoints.		        series.mapOptionsToLevel = mapOptionsToLevel;		    },		    // Animate the slices in. Similar to the animation of polar charts.		    animate: function (init) {		        var chart = this.chart,		            center = [		                chart.plotWidth / 2,		                chart.plotHeight / 2		            ],		            plotLeft = chart.plotLeft,		            plotTop = chart.plotTop,		            attribs,		            group = this.group;		        // Initialize the animation		        if (init) {		            // Scale down the group and place it in the center		            attribs = {		                translateX: center[0] + plotLeft,		                translateY: center[1] + plotTop,		                scaleX: 0.001, // #1499		                scaleY: 0.001,		                rotation: 10,		                opacity: 0.01		            };		            group.attr(attribs);		        // Run the animation		        } else {		            attribs = {		                translateX: plotLeft,		                translateY: plotTop,		                scaleX: 1,		                scaleY: 1,		                rotation: 0,		                opacity: 1		            };		            group.animate(attribs, this.options.animation);		            // Delete this function to allow it only once		            this.animate = null;		        }		    },		    utils: {		        calculateLevelSizes: calculateLevelSizes,		        range: range		    }		};		// Properties of the Sunburst series.		var sunburstPoint = {		    draw: drawPoint,		    shouldDraw: function shouldDraw() {		        var point = this;		        return !point.isNull;		    }		};		/**		 * A `sunburst` series. If the [type](#series.sunburst.type) option is		 * not specified, it is inherited from [chart.type](#chart.type).		 *		 * @extends   series,plotOptions.sunburst		 * @excluding dataParser, dataURL, stack		 * @product   highcharts		 * @apioption series.sunburst		 */		/**		 * @type      {Array<number|*>}		 * @extends   series.treemap.data		 * @excluding x, y		 * @product   highcharts		 * @apioption series.sunburst.data		 */		/**		 * The value of the point, resulting in a relative area of the point		 * in the sunburst.		 *		 * @type      {number}		 * @since     6.0.0		 * @product   highcharts		 * @apioption series.sunburst.data.value		 */		/**		 * Use this option to build a tree structure. The value should be the id of the		 * point which is the parent. If no points has a matching id, or this option is		 * undefined, then the parent will be set to the root.		 *		 * @type      {string}		 * @since     6.0.0		 * @product   highcharts		 * @apioption series.treemap.data.parent		 */		/**		  * Whether to display a slice offset from the center. When a sunburst point is		  * sliced, its children are also offset.		  *		  * @sample highcharts/plotoptions/sunburst-sliced		  *         Sliced sunburst		  *		  * @type      {boolean}		  * @default   false		  * @since     6.0.4		  * @product   highcharts		  * @apioption series.sunburst.data.sliced		  */		/**		 * @private		 * @class		 * @name Highcharts.seriesTypes.sunburst		 *		 * @augments Highcharts.Series		 */		seriesType(		    'sunburst',		    'treemap',		    sunburstOptions,		    sunburstSeries,		    sunburstPoint		);	}(Highcharts, draw, result));	return (function () {	}());}));
 |