/**
 * @license Highcharts JS v11.4.0 (2024-03-04)
 *
 * Highcharts funnel module
 *
 * (c) 2010-2024 Kacper Madej
 *
 * License: www.highcharts.com/license
 */
(function (factory) {
    if (typeof module === 'object' && module.exports) {
        factory['default'] = factory;
        module.exports = factory;
    } else if (typeof define === 'function' && define.amd) {
        define('highcharts/modules/funnel3d', ['highcharts', 'highcharts/highcharts-3d', 'highcharts/modules/cylinder'], function (Highcharts) {
            factory(Highcharts);
            factory.Highcharts = Highcharts;
            return factory;
        });
    } else {
        factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
    }
}(function (Highcharts) {
    'use strict';
    var _modules = Highcharts ? Highcharts._modules : {};
    function _registerModule(obj, path, args, fn) {
        if (!obj.hasOwnProperty(path)) {
            obj[path] = fn.apply(null, args);

            if (typeof CustomEvent === 'function') {
                window.dispatchEvent(new CustomEvent(
                    'HighchartsModuleLoaded',
                    { detail: { path: path, module: obj[path] } }
                ));
            }
        }
    }
    _registerModule(_modules, 'Series/Funnel3D/SVGElement3DFunnel.js', [_modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Renderer/RendererRegistry.js'], _modules['Core/Utilities.js']], function (Color, H, RendererRegistry, U) {
        /* *
         *
         *  Highcharts funnel3d series module
         *
         *  (c) 2010-2024 Highsoft AS
         *
         *  Author: Kacper Madej
         *
         *  License: www.highcharts.com/license
         *
         *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
         *
         * */
        const { parse: color } = Color;
        const { charts } = H;
        const { Element3D: SVGElement3D } = RendererRegistry.getRendererType().prototype;
        const { merge } = U;
        /* *
         *
         *  Class
         *
         * */
        class SVGElement3DFunnel extends SVGElement3D {
            constructor() {
                /* *
                 *
                 *  Properties
                 *
                 * */
                super(...arguments);
                this.mainParts = ['top', 'bottom'];
                this.parts = [
                    'top', 'bottom',
                    'frontUpper', 'backUpper',
                    'frontLower', 'backLower',
                    'rightUpper', 'rightLower'
                ];
                this.sideGroups = [
                    'upperGroup', 'lowerGroup'
                ];
                this.sideParts = {
                    upperGroup: ['frontUpper', 'backUpper', 'rightUpper'],
                    lowerGroup: ['frontLower', 'backLower', 'rightLower']
                };
                this.pathType = 'funnel3d';
            }
            /* *
             *
             *  Functions
             *
             * */
            // override opacity and color setters to control opacity
            opacitySetter(value) {
                const funnel3d = this, opacity = parseFloat(value), parts = funnel3d.parts, chart = charts[funnel3d.renderer.chartIndex], filterId = 'group-opacity-' + opacity + '-' + chart.index;
                // use default for top and bottom
                funnel3d.parts = funnel3d.mainParts;
                funnel3d.singleSetterForParts('opacity', opacity);
                // restore
                funnel3d.parts = parts;
                if (!chart.renderer.filterId) {
                    chart.renderer.definition({
                        tagName: 'filter',
                        attributes: {
                            id: filterId
                        },
                        children: [{
                                tagName: 'feComponentTransfer',
                                children: [{
                                        tagName: 'feFuncA',
                                        attributes: {
                                            type: 'table',
                                            tableValues: '0 ' + opacity
                                        }
                                    }]
                            }]
                    });
                    for (const groupName of funnel3d.sideGroups) {
                        funnel3d[groupName].attr({
                            filter: 'url(#' + filterId + ')'
                        });
                    }
                    // styled mode
                    if (funnel3d.renderer.styledMode) {
                        chart.renderer.definition({
                            tagName: 'style',
                            textContent: '.highcharts-' + filterId +
                                ' {filter:url(#' + filterId + ')}'
                        });
                        for (const groupName of funnel3d.sideGroups) {
                            funnel3d[groupName].addClass('highcharts-' + filterId);
                        }
                    }
                }
                return funnel3d;
            }
            fillSetter(fill) {
                let fillColor = color(fill);
                // extract alpha channel to use the opacitySetter
                const funnel3d = this, alpha = fillColor.rgba[3], partsWithColor = {
                    // standard color for top and bottom
                    top: color(fill).brighten(0.1).get(),
                    bottom: color(fill).brighten(-0.2).get()
                };
                if (alpha < 1) {
                    fillColor.rgba[3] = 1;
                    fillColor = fillColor.get('rgb');
                    // set opacity through the opacitySetter
                    funnel3d.attr({
                        opacity: alpha
                    });
                }
                else {
                    // use default for full opacity
                    fillColor = fill;
                }
                // add gradient for sides
                if (!fillColor.linearGradient &&
                    !fillColor.radialGradient &&
                    funnel3d.gradientForSides) {
                    fillColor = {
                        linearGradient: { x1: 0, x2: 1, y1: 1, y2: 1 },
                        stops: [
                            [0, color(fill).brighten(-0.2).get()],
                            [0.5, fill],
                            [1, color(fill).brighten(-0.2).get()]
                        ]
                    };
                }
                // gradient support
                if (fillColor.linearGradient) {
                    // color in steps, as each gradient will generate a key
                    for (const sideGroupName of funnel3d.sideGroups) {
                        const box = funnel3d[sideGroupName].gradientBox, gradient = fillColor.linearGradient, alteredGradient = merge(fillColor, {
                            linearGradient: {
                                x1: box.x + gradient.x1 * box.width,
                                y1: box.y + gradient.y1 * box.height,
                                x2: box.x + gradient.x2 * box.width,
                                y2: box.y + gradient.y2 * box.height
                            }
                        });
                        for (const partName of funnel3d.sideParts[sideGroupName]) {
                            partsWithColor[partName] = alteredGradient;
                        }
                    }
                }
                else {
                    merge(true, partsWithColor, {
                        frontUpper: fillColor,
                        backUpper: fillColor,
                        rightUpper: fillColor,
                        frontLower: fillColor,
                        backLower: fillColor,
                        rightLower: fillColor
                    });
                    if (fillColor.radialGradient) {
                        for (const sideGroupName of funnel3d.sideGroups) {
                            const gradBox = funnel3d[sideGroupName].gradientBox, centerX = gradBox.x + gradBox.width / 2, centerY = gradBox.y + gradBox.height / 2, diameter = Math.min(gradBox.width, gradBox.height);
                            for (const partName of funnel3d.sideParts[sideGroupName]) {
                                funnel3d[partName].setRadialReference([
                                    centerX, centerY, diameter
                                ]);
                            }
                        }
                    }
                }
                funnel3d.singleSetterForParts('fill', null, partsWithColor);
                // fill for animation getter (#6776)
                funnel3d.color = funnel3d.fill = fill;
                // change gradientUnits to userSpaceOnUse for linearGradient
                if (fillColor.linearGradient) {
                    for (const part of [funnel3d.frontLower, funnel3d.frontUpper]) {
                        const elem = part.element, grad = (elem &&
                            funnel3d.renderer.gradients[elem.gradient]);
                        if (grad &&
                            grad.attr('gradientUnits') !== 'userSpaceOnUse') {
                            grad.attr({
                                gradientUnits: 'userSpaceOnUse'
                            });
                        }
                    }
                }
                return funnel3d;
            }
            adjustForGradient() {
                const funnel3d = this;
                let bbox;
                for (const sideGroupName of funnel3d.sideGroups) {
                    // use common extremes for groups for matching gradients
                    let topLeftEdge = {
                        x: Number.MAX_VALUE,
                        y: Number.MAX_VALUE
                    }, bottomRightEdge = {
                        x: -Number.MAX_VALUE,
                        y: -Number.MAX_VALUE
                    };
                    // get extremes
                    for (const partName of funnel3d.sideParts[sideGroupName]) {
                        const part = funnel3d[partName];
                        bbox = part.getBBox(true);
                        topLeftEdge = {
                            x: Math.min(topLeftEdge.x, bbox.x),
                            y: Math.min(topLeftEdge.y, bbox.y)
                        };
                        bottomRightEdge = {
                            x: Math.max(bottomRightEdge.x, bbox.x + bbox.width),
                            y: Math.max(bottomRightEdge.y, bbox.y + bbox.height)
                        };
                    }
                    // store for color fillSetter
                    funnel3d[sideGroupName].gradientBox = {
                        x: topLeftEdge.x,
                        width: bottomRightEdge.x - topLeftEdge.x,
                        y: topLeftEdge.y,
                        height: bottomRightEdge.y - topLeftEdge.y
                    };
                }
            }
            zIndexSetter() {
                // this.added won't work, because zIndex is set after the prop
                // is set, but before the graphic is really added
                if (this.finishedOnAdd) {
                    this.adjustForGradient();
                }
                // run default
                return this.renderer.Element.prototype.zIndexSetter.apply(this, arguments);
            }
            onAdd() {
                this.adjustForGradient();
                this.finishedOnAdd = true;
            }
        }
        /* *
         *
         *  Default Export
         *
         * */

        return SVGElement3DFunnel;
    });
    _registerModule(_modules, 'Series/Funnel3D/Funnel3DComposition.js', [_modules['Series/Funnel3D/SVGElement3DFunnel.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (SVGElement3DFunnel, H, U) {
        /* *
         *
         *  Highcharts funnel3d series module
         *
         *  (c) 2010-2024 Highsoft AS
         *
         *  Author: Kacper Madej
         *
         *  License: www.highcharts.com/license
         *
         *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
         *
         * */
        const { charts } = H;
        const { error, extend, merge } = U;
        /* *
         *
         *  Functions
         *
         * */
        /** @private */
        function compose(SVGRendererClass) {
            const rendererProto = SVGRendererClass.prototype;
            if (!rendererProto.funnel3d) {
                rendererProto.Element3D.types.funnel3d = SVGElement3DFunnel;
                extend(rendererProto, {
                    funnel3d: rendererFunnel3d,
                    funnel3dPath: rendererFunnel3dPath
                });
            }
        }
        /** @private */
        function rendererFunnel3d(shapeArgs) {
            const renderer = this, funnel3d = renderer.element3d('funnel3d', shapeArgs), styledMode = renderer.styledMode, 
            // hide stroke for Firefox
            strokeAttrs = {
                'stroke-width': 1,
                stroke: 'none'
            };
            // create groups for sides for opacity setter
            funnel3d.upperGroup = renderer.g('funnel3d-upper-group').attr({
                zIndex: funnel3d.frontUpper.zIndex
            }).add(funnel3d);
            for (const upperElem of [funnel3d.frontUpper, funnel3d.backUpper, funnel3d.rightUpper]) {
                if (!styledMode) {
                    upperElem.attr(strokeAttrs);
                }
                upperElem.add(funnel3d.upperGroup);
            }
            funnel3d.lowerGroup = renderer.g('funnel3d-lower-group').attr({
                zIndex: funnel3d.frontLower.zIndex
            }).add(funnel3d);
            for (const lowerElem of [funnel3d.frontLower, funnel3d.backLower, funnel3d.rightLower]) {
                if (!styledMode) {
                    lowerElem.attr(strokeAttrs);
                }
                lowerElem.add(funnel3d.lowerGroup);
            }
            funnel3d.gradientForSides = shapeArgs.gradientForSides;
            return funnel3d;
        }
        /**
         * Generates paths and zIndexes.
         * @private
         */
        function rendererFunnel3dPath(shapeArgs) {
            // Check getCylinderEnd for better error message if
            // the cylinder module is missing
            if (!this.getCylinderEnd) {
                error('A required Highcharts module is missing: cylinder.js', true, charts[this.chartIndex]);
            }
            const renderer = this, chart = charts[renderer.chartIndex], 
            // adjust angles for visible edges
            // based on alpha, selected through visual tests
            alphaCorrection = shapeArgs.alphaCorrection = 90 - Math.abs((chart.options.chart.options3d.alpha % 180) -
                90), 
            // set zIndexes of parts based on cuboid logic, for
            // consistency
            cuboidData = this.cuboidPath.call(renderer, merge(shapeArgs, {
                depth: shapeArgs.width,
                width: (shapeArgs.width + shapeArgs.bottom.width) / 2
            })), isTopFirst = cuboidData.isTop, isFrontFirst = !cuboidData.isFront, hasMiddle = !!shapeArgs.middle, 
            //
            top = renderer.getCylinderEnd(chart, merge(shapeArgs, {
                x: shapeArgs.x - shapeArgs.width / 2,
                z: shapeArgs.z - shapeArgs.width / 2,
                alphaCorrection: alphaCorrection
            })), bottomWidth = shapeArgs.bottom.width, bottomArgs = merge(shapeArgs, {
                width: bottomWidth,
                x: shapeArgs.x - bottomWidth / 2,
                z: shapeArgs.z - bottomWidth / 2,
                alphaCorrection: alphaCorrection
            }), bottom = renderer.getCylinderEnd(chart, bottomArgs, true);
            let middleWidth = bottomWidth, middleTopArgs = bottomArgs, middleTop = bottom, middleBottom = bottom, 
            // masking for cylinders or a missing part of a side shape
            useAlphaCorrection;
            if (hasMiddle) {
                middleWidth = shapeArgs.middle.width;
                middleTopArgs = merge(shapeArgs, {
                    y: (shapeArgs.y +
                        shapeArgs.middle.fraction * shapeArgs.height),
                    width: middleWidth,
                    x: shapeArgs.x - middleWidth / 2,
                    z: shapeArgs.z - middleWidth / 2
                });
                middleTop = renderer.getCylinderEnd(chart, middleTopArgs, false);
                middleBottom = renderer.getCylinderEnd(chart, middleTopArgs, false);
            }
            const ret = {
                top: top,
                bottom: bottom,
                frontUpper: renderer.getCylinderFront(top, middleTop),
                zIndexes: {
                    group: cuboidData.zIndexes.group,
                    top: isTopFirst !== 0 ? 0 : 3,
                    bottom: isTopFirst !== 1 ? 0 : 3,
                    frontUpper: isFrontFirst ? 2 : 1,
                    backUpper: isFrontFirst ? 1 : 2,
                    rightUpper: isFrontFirst ? 2 : 1
                }
            };
            ret.backUpper = renderer.getCylinderBack(top, middleTop);
            useAlphaCorrection = (Math.min(middleWidth, shapeArgs.width) /
                Math.max(middleWidth, shapeArgs.width)) !== 1;
            ret.rightUpper = renderer.getCylinderFront(renderer.getCylinderEnd(chart, merge(shapeArgs, {
                x: shapeArgs.x - shapeArgs.width / 2,
                z: shapeArgs.z - shapeArgs.width / 2,
                alphaCorrection: useAlphaCorrection ?
                    -alphaCorrection : 0
            }), false), renderer.getCylinderEnd(chart, merge(middleTopArgs, {
                alphaCorrection: useAlphaCorrection ?
                    -alphaCorrection : 0
            }), !hasMiddle));
            if (hasMiddle) {
                useAlphaCorrection = (Math.min(middleWidth, bottomWidth) /
                    Math.max(middleWidth, bottomWidth)) !== 1;
                merge(true, ret, {
                    frontLower: renderer.getCylinderFront(middleBottom, bottom),
                    backLower: renderer.getCylinderBack(middleBottom, bottom),
                    rightLower: renderer.getCylinderFront(renderer.getCylinderEnd(chart, merge(bottomArgs, {
                        alphaCorrection: useAlphaCorrection ?
                            -alphaCorrection : 0
                    }), true), renderer.getCylinderEnd(chart, merge(middleTopArgs, {
                        alphaCorrection: useAlphaCorrection ?
                            -alphaCorrection : 0
                    }), false)),
                    zIndexes: {
                        frontLower: isFrontFirst ? 2 : 1,
                        backLower: isFrontFirst ? 1 : 2,
                        rightLower: isFrontFirst ? 1 : 2
                    }
                });
            }
            return ret;
        }
        /* *
         *
         *  Default Export
         *
         * */
        const Funnel3DComposition = {
            compose
        };

        return Funnel3DComposition;
    });
    _registerModule(_modules, 'Series/Funnel3D/Funnel3DSeriesDefaults.js', [], function () {
        /* *
         *
         *  Imports
         *
         * */
        /* *
         *
         *  API Options
         *
         * */
        /**
         * A funnel3d is a 3d version of funnel series type. Funnel charts are
         * a type of chart often used to visualize stages in a sales project,
         * where the top are the initial stages with the most clients.
         *
         * It requires that the `highcharts-3d.js`, `cylinder.js` and
         * `funnel3d.js` module are loaded.
         *
         * @sample highcharts/demo/funnel3d/
         *         Funnel3d
         *
         * @extends      plotOptions.column
         * @excluding    allAreas, boostThreshold, colorAxis, compare, compareBase,
         *               dataSorting, boostBlending
         * @product      highcharts
         * @since        7.1.0
         * @requires     highcharts-3d
         * @requires     modules/cylinder
         * @requires     modules/funnel3d
         * @optionparent plotOptions.funnel3d
         */
        const Funnel3DSeriesDefaults = {
            /** @ignore-option */
            center: ['50%', '50%'],
            /**
             * The max width of the series compared to the width of the plot area,
             * or the pixel width if it is a number.
             *
             * @type    {number|string}
             * @sample  {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
             * @product highcharts
             */
            width: '90%',
            /**
             * The width of the neck, the lower part of the funnel. A number defines
             * pixel width, a percentage string defines a percentage of the plot
             * area width.
             *
             * @type    {number|string}
             * @sample  {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
             * @product highcharts
             */
            neckWidth: '30%',
            /**
             * The height of the series. If it is a number it defines
             * the pixel height, if it is a percentage string it is the percentage
             * of the plot area height.
             *
             * @type    {number|string}
             * @sample  {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
             * @product highcharts
             */
            height: '100%',
            /**
             * The height of the neck, the lower part of the funnel. A number
             * defines pixel width, a percentage string defines a percentage
             * of the plot area height.
             *
             * @type    {number|string}
             * @sample  {highcharts} highcharts/demo/funnel3d/ Funnel3d demo
             * @product highcharts
             */
            neckHeight: '25%',
            /**
             * A reversed funnel has the widest area down. A reversed funnel with
             * no neck width and neck height is a pyramid.
             *
             * @product highcharts
             */
            reversed: false,
            /**
             * By default sides fill is set to a gradient through this option being
             * set to `true`. Set to `false` to get solid color for the sides.
             *
             * @product highcharts
             */
            gradientForSides: true,
            animation: false,
            edgeWidth: 0,
            colorByPoint: true,
            showInLegend: false,
            dataLabels: {
                align: 'right',
                crop: false,
                inside: false,
                overflow: 'allow'
            }
        };
        /**
         * A `funnel3d` series. If the [type](#series.funnel3d.type) option is
         * not specified, it is inherited from [chart.type](#chart.type).
         *
         * @sample {highcharts} highcharts/demo/funnel3d/
         *         Funnel3d demo
         *
         * @since     7.1.0
         * @extends   series,plotOptions.funnel3d
         * @excluding allAreas,boostThreshold,colorAxis,compare,compareBase
         * @product   highcharts
         * @requires  highcharts-3d
         * @requires  modules/cylinder
         * @requires  modules/funnel3d
         * @apioption series.funnel3d
         */
        /**
         * An array of data points for the series. For the `funnel3d` 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 `y` options. The `x` values will be automatically
         * calculated, either starting at 0 and incremented by 1, or from `pointStart`
         * and `pointInterval` given in the series options. If the axis has
         * categories, these will be used. 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.funnel3d.turboThreshold),
         * this option is not available.
         *
         *  ```js
         *     data: [{
         *         y: 2,
         *         name: "Point2",
         *         color: "#00FF00"
         *     }, {
         *         y: 4,
         *         name: "Point1",
         *         color: "#FF00FF"
         *     }]
         *  ```
         *
         * @sample {highcharts} highcharts/chart/reflow-true/
         *         Numerical values
         * @sample {highcharts} highcharts/series/data-array-of-arrays/
         *         Arrays of numeric x and y
         * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
         *         Arrays of datetime x and y
         * @sample {highcharts} highcharts/series/data-array-of-name-value/
         *         Arrays of point.name and y
         * @sample {highcharts} highcharts/series/data-array-of-objects/
         *         Config objects
         *
         * @type      {Array<number|Array<number>|*>}
         * @extends   series.column.data
         * @product   highcharts
         * @apioption series.funnel3d.data
         */
        /**
         * By default sides fill is set to a gradient through this option being
         * set to `true`. Set to `false` to get solid color for the sides.
         *
         * @type      {boolean}
         * @product   highcharts
         * @apioption series.funnel3d.data.gradientForSides
         */
        ''; // detachs doclets above
        /* *
         *
         *  Default Export
         *
         * */

        return Funnel3DSeriesDefaults;
    });
    _registerModule(_modules, 'Series/Funnel3D/Funnel3DPoint.js', [_modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (SeriesRegistry, U) {
        /* *
         *
         *  Highcharts funnel3d series module
         *
         *  (c) 2010-2024 Highsoft AS
         *
         *  Author: Kacper Madej
         *
         *  License: www.highcharts.com/license
         *
         *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
         *
         * */
        const { seriesTypes: { column: ColumnSeries } } = SeriesRegistry;
        const { extend } = U;
        /* *
         *
         *  Class
         *
         * */
        class Funnel3DPoint extends ColumnSeries.prototype.pointClass {
        }
        extend(Funnel3DPoint.prototype, {
            shapeType: 'funnel3d'
        });
        /* *
         *
         *  Default Export
         *
         * */

        return Funnel3DPoint;
    });
    _registerModule(_modules, 'Series/Funnel3D/Funnel3DSeries.js', [_modules['Series/Funnel3D/Funnel3DComposition.js'], _modules['Series/Funnel3D/Funnel3DSeriesDefaults.js'], _modules['Series/Funnel3D/Funnel3DPoint.js'], _modules['Core/Globals.js'], _modules['Core/Math3D.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Funnel3DComposition, Funnel3DSeriesDefaults, Funnel3DPoint, H, Math3D, SeriesRegistry, U) {
        /* *
         *
         *  Highcharts funnel3d series module
         *
         *  (c) 2010-2024 Highsoft AS
         *
         *  Author: Kacper Madej
         *
         *  License: www.highcharts.com/license
         *
         *  !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
         *
         * */
        const { noop } = H;
        const { perspective } = Math3D;
        const { series: Series, seriesTypes: { column: ColumnSeries } } = SeriesRegistry;
        const { extend, merge, pick, relativeLength } = U;
        /* *
         *
         *  Class
         *
         * */
        /**
         * The funnel3d series type.
         *
         * @class
         * @name Highcharts.seriesTypes.funnel3d
         * @augments seriesTypes.column
         * @requires highcharts-3d
         * @requires modules/cylinder
         * @requires modules/funnel3d
         */
        class Funnel3DSeries extends ColumnSeries {
            /* *
             *
             *  Functions
             *
             * */
            /**
             * @private
             */
            alignDataLabel(point, _dataLabel, options) {
                const series = this, dlBoxRaw = point.dlBoxRaw, inverted = series.chart.inverted, below = point.plotY > pick(series.translatedThreshold, series.yAxis.len), inside = pick(options.inside, !!series.options.stacking), dlBox = {
                    x: dlBoxRaw.x,
                    y: dlBoxRaw.y,
                    height: 0
                };
                options.align = pick(options.align, !inverted || inside ? 'center' : below ? 'right' : 'left');
                options.verticalAlign = pick(options.verticalAlign, inverted || inside ? 'middle' : below ? 'top' : 'bottom');
                if (options.verticalAlign !== 'top') {
                    dlBox.y += dlBoxRaw.bottom /
                        (options.verticalAlign === 'bottom' ? 1 : 2);
                }
                dlBox.width = series.getWidthAt(dlBox.y);
                if (series.options.reversed) {
                    dlBox.width = dlBoxRaw.fullWidth - dlBox.width;
                }
                if (inside) {
                    dlBox.x -= dlBox.width / 2;
                }
                else {
                    // swap for inside
                    if (options.align === 'left') {
                        options.align = 'right';
                        dlBox.x -= dlBox.width * 1.5;
                    }
                    else if (options.align === 'right') {
                        options.align = 'left';
                        dlBox.x += dlBox.width / 2;
                    }
                    else {
                        dlBox.x -= dlBox.width / 2;
                    }
                }
                point.dlBox = dlBox;
                ColumnSeries.prototype.alignDataLabel.apply(series, arguments);
            }
            /**
             * Override default axis options with series required options for axes.
             * @private
             */
            bindAxes() {
                Series.prototype.bindAxes.apply(this, arguments);
                extend(this.xAxis.options, {
                    gridLineWidth: 0,
                    lineWidth: 0,
                    title: void 0,
                    tickPositions: []
                });
                merge(true, this.yAxis.options, {
                    gridLineWidth: 0,
                    title: void 0,
                    labels: {
                        enabled: false
                    }
                });
            }
            /**
             * @private
             */
            translate() {
                Series.prototype.translate.apply(this, arguments);
                const series = this, chart = series.chart, options = series.options, reversed = options.reversed, ignoreHiddenPoint = options.ignoreHiddenPoint, plotWidth = chart.plotWidth, plotHeight = chart.plotHeight, center = options.center, centerX = relativeLength(center[0], plotWidth), centerY = relativeLength(center[1], plotHeight), width = relativeLength(options.width, plotWidth), height = relativeLength(options.height, plotHeight), neckWidth = relativeLength(options.neckWidth, plotWidth), neckHeight = relativeLength(options.neckHeight, plotHeight), neckY = (centerY - height / 2) + height - neckHeight, points = series.points;
                let sum = 0, cumulative = 0, // start at top
                tempWidth, getWidthAt, fraction, tooltipPos, 
                //
                y1, y3, y5, 
                //
                h, shapeArgs; // @todo: Type it. It's an extended SVGAttributes.
                // Return the width at a specific y coordinate
                series.getWidthAt = getWidthAt = function (y) {
                    const top = (centerY - height / 2);
                    return (y > neckY || height === neckHeight) ?
                        neckWidth :
                        neckWidth + (width - neckWidth) *
                            (1 - (y - top) / (height - neckHeight));
                };
                // Expose
                series.center = [centerX, centerY, height];
                series.centerX = centerX;
                /*
                    * Individual point coordinate naming:
                    *
                    *  _________centerX,y1________
                    *  \                         /
                    *   \                       /
                    *    \                     /
                    *     \                   /
                    *      \                 /
                    *        ___centerX,y3___
                    *
                    * Additional for the base of the neck:
                    *
                    *       |               |
                    *       |               |
                    *       |               |
                    *        ___centerX,y5___
                    */
                // get the total sum
                for (const point of points) {
                    if (!ignoreHiddenPoint || point.visible !== false) {
                        sum += point.y;
                    }
                }
                for (const point of points) {
                    // set start and end positions
                    y5 = null;
                    fraction = sum ? point.y / sum : 0;
                    y1 = centerY - height / 2 + cumulative * height;
                    y3 = y1 + fraction * height;
                    tempWidth = getWidthAt(y1);
                    h = y3 - y1;
                    shapeArgs = {
                        // for fill setter
                        gradientForSides: pick(point.options.gradientForSides, options.gradientForSides),
                        x: centerX,
                        y: y1,
                        height: h,
                        width: tempWidth,
                        z: 1,
                        top: {
                            width: tempWidth
                        }
                    };
                    tempWidth = getWidthAt(y3);
                    shapeArgs.bottom = {
                        fraction: fraction,
                        width: tempWidth
                    };
                    // the entire point is within the neck
                    if (y1 >= neckY) {
                        shapeArgs.isCylinder = true;
                    }
                    else if (y3 > neckY) {
                        // the base of the neck
                        y5 = y3;
                        tempWidth = getWidthAt(neckY);
                        y3 = neckY;
                        shapeArgs.bottom.width = tempWidth;
                        shapeArgs.middle = {
                            fraction: h ? (neckY - y1) / h : 0,
                            width: tempWidth
                        };
                    }
                    if (reversed) {
                        shapeArgs.y = y1 = centerY + height / 2 -
                            (cumulative + fraction) * height;
                        if (shapeArgs.middle) {
                            shapeArgs.middle.fraction = 1 -
                                (h ? shapeArgs.middle.fraction : 0);
                        }
                        tempWidth = shapeArgs.width;
                        shapeArgs.width = shapeArgs.bottom.width;
                        shapeArgs.bottom.width = tempWidth;
                    }
                    point.shapeArgs = extend(point.shapeArgs, shapeArgs);
                    // for tooltips and data labels context
                    point.percentage = fraction * 100;
                    point.plotX = centerX;
                    if (reversed) {
                        point.plotY = centerY + height / 2 -
                            (cumulative + fraction / 2) * height;
                    }
                    else {
                        point.plotY = (y1 + (y5 || y3)) / 2;
                    }
                    // Placement of tooltips and data labels in 3D
                    tooltipPos = perspective([{
                            x: centerX,
                            y: point.plotY,
                            z: reversed ?
                                -(width - getWidthAt(point.plotY)) / 2 :
                                -(getWidthAt(point.plotY)) / 2
                        }], chart, true)[0];
                    point.tooltipPos = [tooltipPos.x, tooltipPos.y];
                    // base to be used when alignment options are known
                    point.dlBoxRaw = {
                        x: centerX,
                        width: getWidthAt(point.plotY),
                        y: y1,
                        bottom: shapeArgs.height || 0,
                        fullWidth: width
                    };
                    if (!ignoreHiddenPoint || point.visible !== false) {
                        cumulative += fraction;
                    }
                }
            }
        }
        /* *
         *
         *  Static Properties
         *
         * */
        Funnel3DSeries.compose = Funnel3DComposition.compose;
        Funnel3DSeries.defaultOptions = merge(ColumnSeries.defaultOptions, Funnel3DSeriesDefaults);
        extend(Funnel3DSeries.prototype, {
            pointClass: Funnel3DPoint,
            translate3dShapes: noop
        });
        SeriesRegistry.registerSeriesType('funnel3d', Funnel3DSeries);
        /* *
         *
         *  Default Export
         *
         * */

        return Funnel3DSeries;
    });
    _registerModule(_modules, 'masters/modules/funnel3d.src.js', [_modules['Core/Globals.js'], _modules['Series/Funnel3D/Funnel3DSeries.js'], _modules['Core/Renderer/RendererRegistry.js']], function (Highcharts, Funnel3DSeries, RendererRegistry) {

        Funnel3DSeries.compose(RendererRegistry.getRendererType());

        return Highcharts;
    });
}));