// o---------------------------------------------------------------------------------o
    // | This file is part of the RGraph package - you can learn more at:                |
    // |                                                                                 |
    // |                       https://www.rgraph.net/license.html                       |
    // |                                                                                 |
    // | RGraph is dual-licensed under the Open Source GPL license. That means that it's |
    // | free to use and there are no restrictions on what you can use RGraph for!       |
    // | If the GPL license does not suit you however, then there's an inexpensive       |
    // | commercial license option available. See the URL above for more details.        |
    // o---------------------------------------------------------------------------------o

    RGraph     = window.RGraph || {isrgraph:true,isRGraph:true,rgraph:true};
    RGraph.SVG = RGraph.SVG || {};

// Module pattern
(function (win, doc, undefined)
{
    RGraph.SVG.Funnel = function (conf)
    {
        //
        // A setter that the constructor uses (at the end)
        // to set all of the properties
        //
        // @param string name  The name of the property to set
        // @param string value The value to set the property to
        //
        this.set = function (name, value)
        {
            if (arguments.length === 1 && typeof name === 'object') {
                for (i in arguments[0]) {
                    if (typeof i === 'string') {
                        this.set(i, arguments[0][i]);
                    }
                }
            
            } else {

                // Go through all of the properties and make sure
                // that they're using the correct capitalisation
                name = this.properties_lowercase_map[name.toLowerCase()] || name;

                var ret = RGraph.SVG.commonSetter({
                    object: this,
                    name:   name,
                    value:  value
                });
                
                name  = ret.name;
                value = ret.value;

                this.properties[name] = value;

                // If setting the colors, update the originalColors
                // property too
                if (name === 'colors') {
                    this.originalColors = RGraph.SVG.arrayClone(value, true);
                    this.colorsParsed = false;
                }
            }

            return this;
        };








        //
        // A getter.
        // 
        // @param name  string The name of the property to get
        //
        this.get = function (name)
        {
            // Go through all of the properties and make sure
            // that they're using the correct capitalisation
            name = this.properties_lowercase_map[name.toLowerCase()] || name;

            return this.properties[name];
        };











        // Convert strings to numbers
        conf.data = RGraph.SVG.stringsToNumbers(conf.data);
        
        //if (typeof conf.data === 'string') {
        //    conf.data = conf.data.split(/,|\|/);
        //}

        //for (var i=0; i<conf.data.length; ++i) {
        //    if (typeof conf.data[i] === 'string') {
        //        conf.data[i] = parseFloat(conf.data[i]);
        //    }
        //}












        this.type            = 'funnel';
        this.id              = conf.id;
        this.uid             = RGraph.SVG.createUID();
        this.container       = document.getElementById(this.id);
        this.layers          = {}; // MUST be before the SVG element is created!
        this.svg             = RGraph.SVG.createSVG({object: this,container: this.container});
        this.svgAllGroup     = RGraph.SVG.createAllGroup(this);
        this.clipid          = null; // Used to clip the canvas
        this.isRGraph        = true;
        this.isrgraph        = true;
        this.rgraph          = true;
        this.width           = Number(this.svg.getAttribute('width'));
        this.height          = Number(this.svg.getAttribute('height'));
        this.data            = RGraph.SVG.arrayClone(conf.data, true);
        this.originalData    = RGraph.SVG.arrayClone(conf.data, true);
        this.coords          = [];
        this.colorsParsed    = false;
        this.originalColors  = {};
        this.gradientCounter = 1;
        this.nodes           = [];
        this.shadowNodes     = [];
        this.max             = 0;
        this.redraw          = false;
        this.highlight_node  = null;
        this.firstDraw       = true; // After the first draw this will be false






        // Add this object to the ObjectRegistry
        RGraph.SVG.OR.add(this);
        
        // Set the DIV container to be inline-block
        this.container.style.display = 'inline-block';
        
        // Determine the maximum value by going thru the data
        var obj = this;
        this.data.forEach(function (val, key, arr)
        {
            obj.max = Math.max(obj.max, val);
        });






        this.properties =
        {
            marginLeft:    35,
            marginRight:   35,
            marginTop:     35,
            marginBottom:  35,
            
            backgroundBars: false,
            backgroundBarsOpacity: 0.25,
            backgroundBarsColors: null,

            colorsStroke: 'white',
            colors: ['red', 'black', 'orange', 'green', '#6ff', '#ccc', 'pink', 'orange', 'cyan', 'maroon', 'olive', 'teal'],
            
            textColor:  'black',
            textFont:   'Arial, Verdana, sans-serif',
            textSize:   12,
            textBold:   false,
            textItalic: false,
            text:       null,

            labels:       [],
            labelsFont:   null,
            labelsSize:   null,
            labelsColor:  null,
            labelsBold:   null,
            labelsItalic: null,
            labelsBackground: null,
            labelsHalign: 'center',
            labelsPosition: 'section', // This can be section or edge
            labelsFormattedDecimals:  0,
            labelsFormattedPoint:     '.',
            labelsFormattedThousand:  ',',
            labelsFormattedUnitsPre:  '',
            labelsFormattedUnitsPost: '',

            linewidth: 1,
            
            tooltips:                        null,
            tooltipsOverride:                null,
            tooltipsEffect:                  'fade',
            tooltipsCssClass:                'RGraph_tooltip',
            tooltipsCss:                     null,
            tooltipsEvent:                   'click',
            tooltipsPersistent:              false,
            tooltipsFormattedThousand:       ',',
            tooltipsFormattedPoint:          '.',
            tooltipsFormattedDecimals:       0,
            tooltipsFormattedUnitsPre:       '',
            tooltipsFormattedUnitsPost:      '',
            tooltipsFormattedKeyColors:      null,
            tooltipsFormattedKeyColorsShape: 'square',
            tooltipsFormattedKeyLabels:      [],
            tooltipsFormattedTableHeaders:   null,
            tooltipsFormattedTableData:      null,
            tooltipsPointer:                 true,
            tooltipsPointerOffsetx:          0,
            tooltipsPointerOffsety:          0,
            tooltipsPositionStatic:          true,

            highlightStroke: 'rgba(0,0,0,0)',
            // Lighter than usual because the backgroundBars option can
            // mean highlight segments fade into the background
            highlightStroke: 'rgba(0,0,0,0)',
            highlightFill: 'rgba(255,255,255,0.7)',
            highlightLinewidth: 1,
            
            title: '',
            titleX:      null,
            titleY:      null,
            titleHalign: 'center',
            titleValign: null,
            titleSize:   null,
            titleColor:  null,
            titleFont:   null,
            titleBold:   null,
            titleItalic: null,
            
            titleSubtitle: null,
            titleSubtitleSize:   null,
            titleSubtitleColor:  '#aaa',
            titleSubtitleFont:   null,
            titleSubtitleBold:   null,
            titleSubtitleItalic: null,

            key:            null,
            keyColors:      null,
            keyOffsetx:     0,
            keyOffsety:     0,
            keyLabelsOffsetx: 0,
            keyLabelsOffsety: -1,
            keyLabelsFont:    null,
            keyLabelsSize:    null,
            keyLabelsColor:   null,
            keyLabelsBold:    null,
            keyLabelsItalic:  null,

            clip: null,
            
            zoom: false
        };

        //
        // Add the reverse look-up table  for property names
        // so that property names can be specified in any case.
        //
        this.properties_lowercase_map = [];
        for (var i in this.properties) {
            if (typeof i === 'string') {
                this.properties_lowercase_map[i.toLowerCase()] = i;
            }
        }


        //
        // Copy the global object properties to this instance
        //
        RGraph.SVG.getGlobals(this);






        //
        // "Decorate" the object with the generic effects if the effects library has been included
        //
        if (RGraph.SVG.FX && typeof RGraph.SVG.FX.decorate === 'function') {
            RGraph.SVG.FX.decorate(this);
        }





        // Add the responsive function to the object
        this.responsive = RGraph.SVG.responsive;






        var properties = this.properties;








        //
        // The draw method draws the Bar chart
        //
        this.draw = function ()
        {
            // Fire the beforedraw event
            RGraph.SVG.fireCustomEvent(this, 'onbeforedraw');









            // Should the first thing that's done in the.draw() function
            // except for the onbeforedraw event and the
            // installation of clipping.
            this.width  = Number(this.svg.getAttribute('width'));
            this.height = Number(this.svg.getAttribute('height'));












            // Reset the data back to the original values
            this.data = RGraph.SVG.arrayClone(this.originalData, true);



            // Reset the coords array to stop it growing
            this.coords = [];





            // Create the defs tag if necessary
            RGraph.SVG.createDefs(this);


            this.graphWidth  = this.width - properties.marginLeft - properties.marginRight;
            this.graphHeight = this.height - properties.marginTop - properties.marginBottom;

            //
            // Add the data to the .originalData array and work out the max value
            // 
            // 2/5/14 Now also use this loop to ensure that the data pieces
            //        are numbers
            //

            // Convert strings to numbers
            for (var i=0,len=this.data.length; i<len; ++i) {
                if (typeof this.data[i] === 'string') {
                    this.data[i] = RGraph.SVG.stringsToNumbers(this.data[i]);
                }
            }












            // Parse the colors for gradients
            RGraph.SVG.resetColorsToOriginalValues({object:this});
            this.parseColors();





            // Install clipping if requested
            if (this.properties.clip) {

                this.clipid = RGraph.SVG.installClipping(this);

                // Add the clip ID to the all group
                this.svgAllGroup.setAttribute(
                    'clip-path',
                    'url(#{1})'.format(this.clipid)
                );
            } else {
                // No clipping - so ensure that there's no clip-path
                // attribute
                this.clipid = null;
                this.svgAllGroup.removeAttribute('clip-path');
            }




            // This is the group that the background bars will
            // sit in
            this.nodes.backgroundBars = this.create('<g id="backgroundBars-group"></g>', this.svgAllGroup);


            

            // Draw the chart
            this.drawFunnel();
            
            
            
            // Draw the background bars
            this.drawBackgroundBars();






            // Draw the labels
            this.drawLabels();



            // Draw the title and subtitle
            RGraph.SVG.drawTitle(this);






            // Draw the key
            if (typeof properties.key !== null && RGraph.SVG.drawKey) {
                RGraph.SVG.drawKey(this);
            } else if (!RGraph.SVG.isNullish(properties.key)) {
                alert('The drawKey() function does not exist - have you forgotten to include the key library?');
            }



            // Create the shadow definition if needed
            //if (properties.shadow) {
            //    RGraph.SVG.setShadow({
            //        object:  this,
            //        offsetx: properties.shadowOffsetx,
            //        offsety: properties.shadowOffsety,
            //        blur:    properties.shadowBlur,
            //        color:   properties.shadowColor,
            //        id:      'dropShadow'
            //    });
            //}



            // Add the event listener that clears the highlight if
            // there is any. Must be MOUSEDOWN (ie before the click event)
            var obj = this;
            document.body.addEventListener('mousedown', function (e)
            {
                obj.hideHighlight(obj);
            }, false);








            //
            // Allow the addition of custom text via the
            // text: property.
            //
            RGraph.SVG.addCustomText(this);





            // Lastly - install the zoom event listeners if
            // requested
            if (this.properties.zoom) {
                RGraph.SVG.addZoom(this);
            }













            //
            // Fire the onfirstdraw event
            //
            if (this.firstDraw) {
                this.firstDraw = false;
                RGraph.SVG.fireCustomEvent(this, 'onfirstdraw');
            }
            
            
            


            // Fire the draw event
            RGraph.SVG.fireCustomEvent(this, 'ondraw');







            //
            // Install any inline responsive configuration. This
            // should be last in the draw function - even after
            // the draw events.
            //
            RGraph.SVG.installInlineResponsive(this);











            return this;
        };








        //
        // New create() shortcut function
        // For example:
        //    this.create('rect,x:0,y:0,width:100,height:100'[,parent]);
        //
        // @param str string The tag definition to parse and create
        // @param     object The (optional) parent element
        // @return    object The new tag
        //
        this.create = function (str)
        {
            var def = RGraph.SVG.create.parseStr(this, str);
            def.svg = this.svg;
            
            // By default the parent is the SVG tag - but if
            // requested then change it to the tag that has
            // been given
            if (arguments[1]) {
                def.parent = arguments[1];
            }

            return RGraph.SVG.create(def);
        };








        //
        // Draws the radar.
        //
        //@param opt object Options for the function (if any)
        //
        this.drawFunnel = function (opt)
        {
            // This is the center of the Funnel ONLY - not the whole chart
            var centerx = properties.marginLeft + (this.graphWidth / 2);

            // This first loop calculates the coordinates only - it DOES NOT
            // draw the Funnel on to the scene
            for (var i=0; i<(this.data.length - 1); ++i) {

                var value      = this.data[i],
                    nextValue  = this.data[i+1],
                    maxWidth   = this.graphWidth,
                    width      = (value / this.max) * this.graphWidth,
                    height     = this.graphHeight / (this.data.length - 1), // The heights are equal
                    nextWidth  = (nextValue / this.max) * this.graphWidth,
                    nextHeight = height;

                // The coordinates
                var x1 = centerx - (width / 2),
                    y1 = properties.marginTop + (height * i),
                    x2 = centerx + (width / 2),
                    y2 = properties.marginTop + (height * i);
                    x3 = centerx + (nextWidth / 2),
                    y3 = properties.marginTop + (height * (i+1)),
                    x4 = centerx - (nextWidth / 2),
                    y4 = properties.marginTop + (height * (i+1));

                // Store the coords
                this.coords.push({
                    x1: x1,
                    y1: y1,
                    x2: x2,
                    y2: y2,
                    x3: x3,
                    y3: y3,
                    x4: x4,
                    y4: y4,
                    widthTop: x2 - x1,
                    widthBottom: x3 - x4,
                    height: y3 - y2,
                    object: this
                    
                });
            }




            // Now go thru the coods and draw the shapes
            for (var i=0,len=this.coords.length,sequentialIndex=0; i<len; ++i,++sequentialIndex) {

                if (i < len) {
                    var coords = this.coords[i];
    
                    var path = RGraph.SVG.create({
                        svg: this.svg,
                        type: 'path',
                        parent: this.svgAllGroup,
                        attr: {
                            d: 'M {1} {2} L {3} {4} L {5} {6} L {7} {8} z'.format(
                                coords.x1,
                                coords.y1,
                                coords.x2,
                                coords.y2,
                                coords.x3,
                                coords.y3,
                                coords.x4,
                                coords.y4
                            ),
                            stroke: properties.colorsStroke,
                            fill: properties.colors[i],
                            'stroke-width': properties.linewidth,
                            'data-value': this.data[i],
                            'data-index': i
                        }
                    });





                    // Store a reference to the SVG path object just created
                    coords.element = path;












                    // Install tooltips event listener

                    // Add the tooltip data- attribute
                    if (!RGraph.SVG.isNullish(properties.tooltips) && (properties.tooltips[i] || typeof properties.tooltips === 'string') ) {

                        var obj = this;

                        //
                        // Add tooltip event listeners
                        //
                        (function (idx, seq)
                        {
                            path.addEventListener(properties.tooltipsEvent.replace(/^on/, ''), function (e)
                            {
                                obj.removeHighlight();

                                // Show the tooltip
                                RGraph.SVG.tooltip({
                                    object: obj,
                                    index: idx,
                                    group: null,
                                    sequentialIndex: seq,
                                    text: typeof properties.tooltips === 'string' ? properties.tooltips : properties.tooltips[seq],
                                    event: e
                                });
                                
                                // Highlight the rect that has been clicked on
                                obj.highlight(e.target);
                            }, false);

                            path.addEventListener('mousemove', function (e)
                            {
                                e.target.style.cursor = 'pointer'
                            }, false);
                        })(i, sequentialIndex);

                    } // end if
                } // end if
            } // end for
        };








        //
        // Redraws the chart if required
        //
        this.redrawFunnel = function ()
        {
        };








        //
        // Draws the background bars. This is called AFTER the .draw() function
        // and manages to draw the background bars behind the funnel by utilising
        // the background layers (or one of them at least)
        //
        this.drawBackgroundBars = function ()
        {
            if (properties.backgroundBars) {

                for (var i=0; i<this.coords.length; ++i) {

                    var coords = this.coords[i];

                    // Add the background bars to the group that
                    // was created for them. This means that they
                    // will appear at the back of the Funnel
                    // allowing tooltips to function correctly.
                    RGraph.SVG.create({
                        svg: this.svg,
                        type: 'rect',
                        parent: this.nodes.backgroundBars,
                        attr: {
                            x: 0,
                            y: coords.y1,
                            width: this.width,
                            height: coords.y3 - coords.y2,
                            fill: properties.backgroundBarsColors && typeof properties.backgroundBarsColors === 'object' && typeof properties.backgroundBarsColors[i] === 'string' ? properties.backgroundBarsColors[i] : properties.colors[i],
                            'fill-opacity': properties.backgroundBarsOpacity
                        }
                    });
                }
            }
        };








        //
        // Draw the labels
        //
        this.drawLabels = function ()
        {



            if (properties.labels && properties.labels.length) {
                //
                // If the labels option is a string then turn it
                // into an array.
                //
                if (typeof properties.labels === 'string') {
                    properties.labels = RGraph.SVG.arrayPad({
                        array:  [],
                        length: this.coords.length + 1,
                        value:  properties.labels
                    });
                }

                //
                // Label substitution
                //
                for (var i=0; i<properties.labels.length; ++i) {
                    properties.labels[i] = RGraph.SVG.labelSubstitution({
                        object:    this,
                        text:      properties.labels[i],
                        index:     i,
                        value:     this.data[i],
                        decimals:  properties.labelsFormattedDecimals  || 0,
                        unitsPre:  properties.labelsFormattedUnitsPre  || '',
                        unitsPost: properties.labelsFormattedUnitsPost || '',
                        thousand:  properties.labelsFormattedThousand  || ',',
                        point:     properties.labelsFormattedPoint     || '.'
                    });
                }
            }






            // Create the group that the labels are added to
            var labelsGroup = RGraph.SVG.create({
                svg: this.svg,
                parent: this.svgAllGroup,
                type: 'g'
            });
            
            // Get the text configuration for the labels
            var textConf = RGraph.SVG.getTextConf({
                object: this,
                prefix: 'labels'
            });
            
            // Determine the alignment
            if (properties.labelsHalign === 'left') {
                var x      = 15;
                var halign = 'left';
            
            } else if (properties.labelsHalign === 'right') {
                var x      = this.width - 15;
                var halign = 'right';
            
            } else {
                var x      = this.width / 2;
                var halign = 'center';
            }


            if (properties.labels && properties.labels.length) {
                if (properties.labelsPosition === 'section') {
                    
                    var sectionHeight = this.graphHeight / properties.labels.length;
                    
                    for (var i=0; i<properties.labels.length; ++i) {

                        RGraph.SVG.text({
                            
                            object:     this,
                            svg:        this.svg,
                            parent:     labelsGroup,
                            tag:        'labels',
                            
                            text:       typeof properties.labels[i] === 'string' || properties.labels[i] === 'number' ? properties.labels[i].toString() : '',
                            
                            x:          x,
                            y:          properties.marginTop + (sectionHeight / 2) + (i * sectionHeight),
                            
                            halign:     halign,
                            valign:     'center',
                            
                            background: properties.labelsBackground || 'rgba(255,255,255,0.5)',
                            padding:    2,
                            
                            color:      textConf.color,
                            size:       textConf.size,
                            bold:       textConf.bold,
                            italic:     textConf.italic,
                            font:       textConf.font
                        });
                    }

                // edge Positioning
                } else {

                    for (var i=0; i<properties.labels.length; ++i) {
                        RGraph.SVG.text({
                            
                            object:     this,
                            svg:        this.svg,
                            parent:     labelsGroup,
                            tag:        'labels',
                            
                            text:       typeof properties.labels[i] === 'string' || properties.labels[i] === 'number' ? properties.labels[i].toString() : '',
                            
                            x:          x,
                            y:          properties.marginTop + ((this.graphHeight / (properties.labels.length - 1) ) * i),
                            
                            halign:     halign,
                            valign:     'center',
                            
                            background: properties.labelsBackground || 'rgba(255,255,255,0.5)',
                            padding:    2,
                            
                            size:       textConf.size,
                            bold:       textConf.bold,
                            italic:     textConf.italic,
                            color:      textConf.color,
                            font:       textConf.font
                        });
                    }
                }
            }
        };








        //
        // This function can be used to highlight a segment on the chart
        // 
        // @param object circle The circle to highlight
        //
        this.highlight = function (path)
        {
            var path = path.getAttribute('d');

            var highlight = RGraph.SVG.create({
                svg: this.svg,
                parent: this.svgAllGroup,
                type: 'path',
                attr: {
                    d: path,
                    fill: properties.highlightFill,
                    stroke: properties.highlightStroke,
                    'stroke-width': properties.highlightLinewidth
                },
                style: {
                    pointerEvents: 'none'
                }
            });


            if (properties.tooltipsEvent === 'mousemove') {
                highlight.addEventListener('mouseout', function (e)
                {
                    highlight.parentNode.removeChild(highlight);
                    RGraph.SVG.hideTooltip();

                    RGraph.SVG.REG.set('highlight', null);
                }, false);
            }


            // Store the highlight rect in the registry so
            // it can be cleared later
            RGraph.SVG.REG.set('highlight', highlight);

        };








        //
        // This allows for easy specification of gradients
        //
        this.parseColors = function () 
        {
            // Save the original colors so that they can be restored when the canvas is reset
            if (!Object.keys(this.originalColors).length) {
                this.originalColors = {
                    colors:               RGraph.SVG.arrayClone(properties.colors, true),
                    highlightFill:        RGraph.SVG.arrayClone(properties.highlightFill, true),
                    backgroundBarsColors: RGraph.SVG.arrayClone(properties.backgroundBarsColors, true)
                }
            }
            
            
            // colors
            var colors = properties.colors;

            if (colors) {
                for (var i=0; i<colors.length; ++i) {
                    colors[i] = RGraph.SVG.parseColorLinear({
                        object: this,
                        color: colors[i],
                        direction:'horizontal'
                    });
                }
            }
            
            // backgroundBarsColors
            if (properties.backgroundBarsColors && properties.backgroundBarsColors.length) {
                for (var i=0; i<properties.backgroundBarsColors.length; ++i) {
                    properties.backgroundBarsColors[i] = RGraph.SVG.parseColorLinear({
                        object: this,
                        color: properties.backgroundBarsColors[i],
                        direction:'horizontal'
                    });
                }
            }
            
            // Highlight fill
            properties.highlightFill = RGraph.SVG.parseColorLinear({
                object: this,
                color: properties.highlightFill
            });
        };








        //
        // Using a function to add events makes it easier to facilitate method
        // chaining
        // 
        // @param string   type The type of even to add
        // @param function func 
        //
        this.on = function (type, func)
        {
            if (type.substr(0,2) !== 'on') {
                type = 'on' + type;
            }
            
            RGraph.SVG.addCustomEventListener(this, type, func);
    
            return this;
        };








        //
        // Used in chaining. Runs a function there and then - not waiting for
        // the events to fire (eg the onbeforedraw event)
        // 
        // @param function func The function to execute
        //
        this.exec = function (func)
        {
            func(this);
            
            return this;
        };








        //
        // Removes the tooltip highlight from the chart
        //
        this.removeHighlight =
        this.hideHighlight   = function ()
        {

            //var highlight = RGraph.SVG.REG.get('highlight');

            //if (highlight) {
            //    highlight.setAttribute('fill','transparent');
            //    highlight.setAttribute('stroke','transparent');
            //    
            //    RGraph.SVG.REG.set('highlight', null);
            //}
            
            RGraph.SVG.removeHighlight();
        };








        //
        // A worker function that handles Bar chart specific tooltip substitutions
        //
        this.tooltipSubstitutions = function (opt)
        {
            return {
                  index: opt.index,
                dataset: 0,
        sequentialIndex: opt.index,
                  value: this.data[opt.index],
                 values: [this.data[opt.index]]
            };
        };








        //
        // A worker function that returns the correct color/label/value
        //
        // @param object specific The indexes that are applicable
        // @param number index    The appropriate index
        //
        this.tooltipsFormattedCustom = function (specific, index, colors)
        {
            var color = colors[specific.index];
            var label = ( (typeof properties.tooltipsFormattedKeyLabels === 'object' && typeof properties.tooltipsFormattedKeyLabels[specific.index] === 'string') ? properties.tooltipsFormattedKeyLabels[specific.index] : '');

            return {
                label: label,
                color: color
            };
        };








        //
        // This allows for static tooltip positioning
        //
        this.positionTooltipStatic = function (args)
        {
            var obj      = args.object,
                e        = args.event,
                tooltip  = args.tooltip,
                index    = args.index,
                svgXY    = RGraph.SVG.getSVGXY(obj.svg),
                coords   = this.coords[args.index];

            // Position the tooltip in the X direction
            args.tooltip.style.left = (
                  svgXY[0]                       // The X coordinate of the canvas
                + coords.x1                      // The first X coordinate of the segment on the chart
                - (tooltip.offsetWidth / 2)      // Subtract half of the tooltip width
                + ((coords.x2 - coords.x1) / 2)
            ) + 'px';

            args.tooltip.style.top  = (
                  svgXY[1]                       // The Y coordinate of the canvas
                + coords.y1                      // The Y coordinate of the bar on the chart
                - tooltip.offsetHeight           // The height of the tooltip
                - 10                             // An arbitrary amount
            ) + 'px';
        };








        //
        // Set the options that the user has provided
        //
        for (i in conf.options) {
            if (typeof i === 'string') {
                this.set(i, conf.options[i]);
            }
        }
    };
    
    
    
    return this;




// End module pattern
})(window, document);