| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556 | 
							- /* *
 
-  * (c) 2010-2019 Torstein Honsi
 
-  *
 
-  * Support for old IE browsers (6, 7 and 8) in Highcharts v6+.
 
-  *
 
-  * License: www.highcharts.com/license
 
-  */
 
- 'use strict';
 
- import H from '../parts/Globals.js';
 
- import '../parts/Utilities.js';
 
- import '../parts/SvgRenderer.js';
 
- var VMLRenderer,
 
-     VMLRendererExtension,
 
-     VMLElement,
 
-     Chart = H.Chart,
 
-     createElement = H.createElement,
 
-     css = H.css,
 
-     defined = H.defined,
 
-     deg2rad = H.deg2rad,
 
-     discardElement = H.discardElement,
 
-     doc = H.doc,
 
-     erase = H.erase,
 
-     extend = H.extend,
 
-     extendClass = H.extendClass,
 
-     isArray = H.isArray,
 
-     isNumber = H.isNumber,
 
-     isObject = H.isObject,
 
-     merge = H.merge,
 
-     noop = H.noop,
 
-     pick = H.pick,
 
-     pInt = H.pInt,
 
-     svg = H.svg,
 
-     SVGElement = H.SVGElement,
 
-     SVGRenderer = H.SVGRenderer,
 
-     win = H.win;
 
- /**
 
-  * Path to the pattern image required by VML browsers in order to
 
-  * draw radial gradients.
 
-  *
 
-  * @type      {string}
 
-  * @default   http://code.highcharts.com/{version}/gfx/vml-radial-gradient.png
 
-  * @since     2.3.0
 
-  * @apioption global.VMLRadialGradientURL
 
-  */
 
- H.getOptions().global.VMLRadialGradientURL =
 
-     'http://code.highcharts.com/@product.version@/gfx/vml-radial-gradient.png';
 
- // Utilites
 
- if (doc && !doc.defaultView) {
 
-     H.getStyle = function (el, prop) {
 
-         var val,
 
-             alias = { width: 'clientWidth', height: 'clientHeight' }[prop];
 
-         if (el.style[prop]) {
 
-             return H.pInt(el.style[prop]);
 
-         }
 
-         if (prop === 'opacity') {
 
-             prop = 'filter';
 
-         }
 
-         // Getting the rendered width and height
 
-         if (alias) {
 
-             el.style.zoom = 1;
 
-             return Math.max(el[alias] - 2 * H.getStyle(el, 'padding'), 0);
 
-         }
 
-         val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b) {
 
-             return b.toUpperCase();
 
-         })];
 
-         if (prop === 'filter') {
 
-             val = val.replace(
 
-                 /alpha\(opacity=([0-9]+)\)/,
 
-                 function (a, b) {
 
-                     return b / 100;
 
-                 }
 
-             );
 
-         }
 
-         return val === '' ? 1 : H.pInt(val);
 
-     };
 
- }
 
- if (!svg) {
 
-     // Prevent wrapping from creating false offsetWidths in export in legacy IE.
 
-     // This applies only to charts for export, where IE runs the SVGRenderer
 
-     // instead of the VMLRenderer
 
-     // (#1079, #1063)
 
-     H.addEvent(SVGElement, 'afterInit', function () {
 
-         if (this.element.nodeName === 'text') {
 
-             this.css({
 
-                 position: 'absolute'
 
-             });
 
-         }
 
-     });
 
-     /**
 
-      * Old IE override for pointer normalize, adds chartX and chartY to event
 
-      * arguments.
 
-      *
 
-      * @ignore
 
-      * @function Highcharts.Pointer#normalize
 
-      *
 
-      * @param {global.Event} e
 
-      *
 
-      * @param {boolean} [chartPosition=false]
 
-      */
 
-     H.Pointer.prototype.normalize = function (e, chartPosition) {
 
-         e = e || win.event;
 
-         if (!e.target) {
 
-             e.target = e.srcElement;
 
-         }
 
-         // Get mouse position
 
-         if (!chartPosition) {
 
-             this.chartPosition = chartPosition = H.offset(this.chart.container);
 
-         }
 
-         return H.extend(e, {
 
-             // #2005, #2129: the second case is for IE10 quirks mode within
 
-             // framesets
 
-             chartX: Math.round(Math.max(e.x, e.clientX - chartPosition.left)),
 
-             chartY: Math.round(e.y)
 
-         });
 
-     };
 
-     /**
 
-      * Further sanitize the mock-SVG that is generated when exporting charts in
 
-      * oldIE.
 
-      *
 
-      * @private
 
-      * @function Highcharts.Chart#ieSanitizeSVG
 
-      */
 
-     Chart.prototype.ieSanitizeSVG = function (svg) {
 
-         svg = svg
 
-             .replace(/<IMG /g, '<image ')
 
-             .replace(/<(\/?)TITLE>/g, '<$1title>')
 
-             .replace(/height=([^" ]+)/g, 'height="$1"')
 
-             .replace(/width=([^" ]+)/g, 'width="$1"')
 
-             .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
 
-             .replace(/ id=([^" >]+)/g, ' id="$1"') // #4003
 
-             .replace(/class=([^" >]+)/g, 'class="$1"')
 
-             .replace(/ transform /g, ' ')
 
-             .replace(/:(path|rect)/g, '$1')
 
-             .replace(/style="([^"]+)"/g, function (s) {
 
-                 return s.toLowerCase();
 
-             });
 
-         return svg;
 
-     };
 
-     /**
 
-      * VML namespaces can't be added until after complete. Listening
 
-      * for Perini's doScroll hack is not enough.
 
-      *
 
-      * @private
 
-      * @function Highcharts.Chart#isReadyToRender
 
-      */
 
-     Chart.prototype.isReadyToRender = function () {
 
-         var chart = this;
 
-         // Note: win == win.top is required
 
-         if (
 
-             !svg &&
 
-             (
 
-                 win == win.top && // eslint-disable-line eqeqeq
 
-                 doc.readyState !== 'complete'
 
-             )
 
-         ) {
 
-             doc.attachEvent('onreadystatechange', function () {
 
-                 doc.detachEvent('onreadystatechange', chart.firstRender);
 
-                 if (doc.readyState === 'complete') {
 
-                     chart.firstRender();
 
-                 }
 
-             });
 
-             return false;
 
-         }
 
-         return true;
 
-     };
 
-     // IE compatibility hack for generating SVG content that it doesn't really
 
-     // understand. Used by the exporting module.
 
-     if (!doc.createElementNS) {
 
-         doc.createElementNS = function (ns, tagName) {
 
-             return doc.createElement(tagName);
 
-         };
 
-     }
 
-     /**
 
-      * Old IE polyfill for addEventListener, called from inside the addEvent
 
-      * function.
 
-      *
 
-      * @private
 
-      * @function Highcharts.addEventListenerPolyfill
 
-      *
 
-      * @param {string} type
 
-      *
 
-      * @param {Function} fn
 
-      */
 
-     H.addEventListenerPolyfill = function (type, fn) {
 
-         var el = this;
 
-         function wrappedFn(e) {
 
-             e.target = e.srcElement || win; // #2820
 
-             fn.call(el, e);
 
-         }
 
-         if (el.attachEvent) {
 
-             if (!el.hcEventsIE) {
 
-                 el.hcEventsIE = {};
 
-             }
 
-             // unique function string (#6746)
 
-             if (!fn.hcKey) {
 
-                 fn.hcKey = H.uniqueKey();
 
-             }
 
-             // Link wrapped fn with original fn, so we can get this in
 
-             // removeEvent
 
-             el.hcEventsIE[fn.hcKey] = wrappedFn;
 
-             el.attachEvent('on' + type, wrappedFn);
 
-         }
 
-     };
 
-     /**
 
-      * @private
 
-      * @function Highcharts.removeEventListenerPolyfill
 
-      *
 
-      * @param {string} type
 
-      *
 
-      * @param {Function} fn
 
-      */
 
-     H.removeEventListenerPolyfill = function (type, fn) {
 
-         if (this.detachEvent) {
 
-             fn = this.hcEventsIE[fn.hcKey];
 
-             this.detachEvent('on' + type, fn);
 
-         }
 
-     };
 
-     /**
 
-      * The VML element wrapper.
 
-      *
 
-      * @private
 
-      * @class
 
-      * @name Highcharts.VMLElement
 
-      *
 
-      * @augments Highcharts.SVGElement
 
-      */
 
-     VMLElement = {
 
-         docMode8: doc && doc.documentMode === 8,
 
-         /**
 
-          * Initialize a new VML element wrapper. It builds the markup as a
 
-          * string to minimize DOM traffic.
 
-          *
 
-          * @function Highcharts.VMLElement#init
 
-          *
 
-          * @param {object} renderer
 
-          *
 
-          * @param {object} nodeName
 
-          */
 
-         init: function (renderer, nodeName) {
 
-             var wrapper = this,
 
-                 markup = ['<', nodeName, ' filled="f" stroked="f"'],
 
-                 style = ['position: ', 'absolute', ';'],
 
-                 isDiv = nodeName === 'div';
 
-             // divs and shapes need size
 
-             if (nodeName === 'shape' || isDiv) {
 
-                 style.push('left:0;top:0;width:1px;height:1px;');
 
-             }
 
-             style.push('visibility: ', isDiv ? 'hidden' : 'visible');
 
-             markup.push(' style="', style.join(''), '"/>');
 
-             // create element with default attributes and style
 
-             if (nodeName) {
 
-                 markup = isDiv || nodeName === 'span' || nodeName === 'img' ?
 
-                     markup.join('') :
 
-                     renderer.prepVML(markup);
 
-                 wrapper.element = createElement(markup);
 
-             }
 
-             wrapper.renderer = renderer;
 
-         },
 
-         /**
 
-          * Add the node to the given parent
 
-          *
 
-          * @function Highcharts.VMLElement
 
-          *
 
-          * @param {object} parent
 
-          */
 
-         add: function (parent) {
 
-             var wrapper = this,
 
-                 renderer = wrapper.renderer,
 
-                 element = wrapper.element,
 
-                 box = renderer.box,
 
-                 inverted = parent && parent.inverted,
 
-                 // get the parent node
 
-                 parentNode = parent ?
 
-                     parent.element || parent :
 
-                     box;
 
-             if (parent) {
 
-                 this.parentGroup = parent;
 
-             }
 
-             // if the parent group is inverted, apply inversion on all children
 
-             if (inverted) { // only on groups
 
-                 renderer.invertChild(element, parentNode);
 
-             }
 
-             // append it
 
-             parentNode.appendChild(element);
 
-             // align text after adding to be able to read offset
 
-             wrapper.added = true;
 
-             if (wrapper.alignOnAdd && !wrapper.deferUpdateTransform) {
 
-                 wrapper.updateTransform();
 
-             }
 
-             // fire an event for internal hooks
 
-             if (wrapper.onAdd) {
 
-                 wrapper.onAdd();
 
-             }
 
-             // IE8 Standards can't set the class name before the element is
 
-             // appended
 
-             if (this.className) {
 
-                 this.attr('class', this.className);
 
-             }
 
-             return wrapper;
 
-         },
 
-         /**
 
-          * VML always uses htmlUpdateTransform
 
-          *
 
-          * @function Highcharts.VMLElement#updateTransform
 
-          */
 
-         updateTransform: SVGElement.prototype.htmlUpdateTransform,
 
-         /**
 
-          * Set the rotation of a span with oldIE's filter
 
-          *
 
-          * @function Highcharts.VMLElement#setSpanRotation
 
-          */
 
-         setSpanRotation: function () {
 
-             // Adjust for alignment and rotation. Rotation of useHTML content is
 
-             // not yet implemented but it can probably be implemented for
 
-             // Firefox 3.5+ on user request. FF3.5+ has support for CSS3
 
-             // transform. The getBBox method also needs to be updated to
 
-             // compensate for the rotation, like it currently does for SVG.
 
-             // Test case: https://jsfiddle.net/highcharts/Ybt44/
 
-             var rotation = this.rotation,
 
-                 costheta = Math.cos(rotation * deg2rad),
 
-                 sintheta = Math.sin(rotation * deg2rad);
 
-             css(this.element, {
 
-                 filter: rotation ? [
 
-                     'progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
 
-                     ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
 
-                     ', sizingMethod=\'auto expand\')'
 
-                 ].join('') : 'none'
 
-             });
 
-         },
 
-         /**
 
-          * Get the positioning correction for the span after rotating.
 
-          *
 
-          * @function Highcharts.VMLElement#getSpanCorrection
 
-          */
 
-         getSpanCorrection: function (
 
-             width,
 
-             baseline,
 
-             alignCorrection,
 
-             rotation,
 
-             align
 
-         ) {
 
-             var costheta = rotation ? Math.cos(rotation * deg2rad) : 1,
 
-                 sintheta = rotation ? Math.sin(rotation * deg2rad) : 0,
 
-                 height = pick(this.elemHeight, this.element.offsetHeight),
 
-                 quad,
 
-                 nonLeft = align && align !== 'left';
 
-             // correct x and y
 
-             this.xCorr = costheta < 0 && -width;
 
-             this.yCorr = sintheta < 0 && -height;
 
-             // correct for baseline and corners spilling out after rotation
 
-             quad = costheta * sintheta < 0;
 
-             this.xCorr += (
 
-                 sintheta *
 
-                 baseline *
 
-                 (quad ? 1 - alignCorrection : alignCorrection)
 
-             );
 
-             this.yCorr -= (
 
-                 costheta *
 
-                 baseline *
 
-                 (rotation ? (quad ? alignCorrection : 1 - alignCorrection) : 1)
 
-             );
 
-             // correct for the length/height of the text
 
-             if (nonLeft) {
 
-                 this.xCorr -= width * alignCorrection * (costheta < 0 ? -1 : 1);
 
-                 if (rotation) {
 
-                     this.yCorr -= (
 
-                         height *
 
-                         alignCorrection *
 
-                         (sintheta < 0 ? -1 : 1)
 
-                     );
 
-                 }
 
-                 css(this.element, {
 
-                     textAlign: align
 
-                 });
 
-             }
 
-         },
 
-         /**
 
-          * Converts a subset of an SVG path definition to its VML counterpart.
 
-          * Takes an array as the parameter and returns a string.
 
-          *
 
-          * @function Highcharts.VMLElement#pathToVML
 
-          */
 
-         pathToVML: function (value) {
 
-             // convert paths
 
-             var i = value.length,
 
-                 path = [];
 
-             while (i--) {
 
-                 // Multiply by 10 to allow subpixel precision.
 
-                 // Substracting half a pixel seems to make the coordinates
 
-                 // align with SVG, but this hasn't been tested thoroughly
 
-                 if (isNumber(value[i])) {
 
-                     path[i] = Math.round(value[i] * 10) - 5;
 
-                 } else if (value[i] === 'Z') { // close the path
 
-                     path[i] = 'x';
 
-                 } else {
 
-                     path[i] = value[i];
 
-                     // When the start X and end X coordinates of an arc are too
 
-                     // close, they are rounded to the same value above. In this
 
-                     // case, substract or add 1 from the end X and Y positions.
 
-                     // #186, #760, #1371, #1410.
 
-                     if (
 
-                         value.isArc &&
 
-                         (value[i] === 'wa' || value[i] === 'at')
 
-                     ) {
 
-                         // Start and end X
 
-                         if (path[i + 5] === path[i + 7]) {
 
-                             path[i + 7] += value[i + 7] > value[i + 5] ? 1 : -1;
 
-                         }
 
-                         // Start and end Y
 
-                         if (path[i + 6] === path[i + 8]) {
 
-                             path[i + 8] += value[i + 8] > value[i + 6] ? 1 : -1;
 
-                         }
 
-                     }
 
-                 }
 
-             }
 
-             return path.join(' ') || 'x';
 
-         },
 
-         /**
 
-          * Set the element's clipping to a predefined rectangle
 
-          *
 
-          * @function Highcharts.VMLElement#clip
 
-          *
 
-          * @param {object} clipRect
 
-          */
 
-         clip: function (clipRect) {
 
-             var wrapper = this,
 
-                 clipMembers,
 
-                 cssRet;
 
-             if (clipRect) {
 
-                 clipMembers = clipRect.members;
 
-                 // Ensure unique list of elements (#1258)
 
-                 erase(clipMembers, wrapper);
 
-                 clipMembers.push(wrapper);
 
-                 wrapper.destroyClip = function () {
 
-                     erase(clipMembers, wrapper);
 
-                 };
 
-                 cssRet = clipRect.getCSS(wrapper);
 
-             } else {
 
-                 if (wrapper.destroyClip) {
 
-                     wrapper.destroyClip();
 
-                 }
 
-                 cssRet = {
 
-                     clip: wrapper.docMode8 ? 'inherit' : 'rect(auto)'
 
-                 }; // #1214
 
-             }
 
-             return wrapper.css(cssRet);
 
-         },
 
-         /**
 
-          * Set styles for the element
 
-          *
 
-          * @function Highcharts.VMLElement#css
 
-          *
 
-          * @param {Highcharts.SVGAttributes} styles
 
-          */
 
-         css: SVGElement.prototype.htmlCss,
 
-         /**
 
-          * Removes a child either by removeChild or move to garbageBin.
 
-          * Issue 490; in VML removeChild results in Orphaned nodes according to
 
-          * sIEve, discardElement does not.
 
-          *
 
-          * @function Highcharts.VMLElement#safeRemoveChild
 
-          */
 
-         safeRemoveChild: function (element) {
 
-             // discardElement will detach the node from its parent before
 
-             // attaching it to the garbage bin. Therefore it is important that
 
-             // the node is attached and have parent.
 
-             if (element.parentNode) {
 
-                 discardElement(element);
 
-             }
 
-         },
 
-         /**
 
-          * Extend element.destroy by removing it from the clip members array
 
-          *
 
-          * @function Highcharts.VMLElement#destroy
 
-          */
 
-         destroy: function () {
 
-             if (this.destroyClip) {
 
-                 this.destroyClip();
 
-             }
 
-             return SVGElement.prototype.destroy.apply(this);
 
-         },
 
-         /**
 
-          * Add an event listener. VML override for normalizing event parameters.
 
-          *
 
-          * @function Highcharts.VMLElement#on
 
-          *
 
-          * @param {string} eventType
 
-          *
 
-          * @param {Function} handler
 
-          */
 
-         on: function (eventType, handler) {
 
-             // simplest possible event model for internal use
 
-             this.element['on' + eventType] = function () {
 
-                 var evt = win.event;
 
-                 evt.target = evt.srcElement;
 
-                 handler(evt);
 
-             };
 
-             return this;
 
-         },
 
-         /**
 
-          * In stacked columns, cut off the shadows so that they don't overlap
 
-          *
 
-          * @function Highcharts.VMLElement#cutOffPath
 
-          */
 
-         cutOffPath: function (path, length) {
 
-             var len;
 
-             // The extra comma tricks the trailing comma remover in
 
-             // "gulp scripts" task
 
-             path = path.split(/[ ,]/);
 
-             len = path.length;
 
-             if (len === 9 || len === 11) {
 
-                 path[len - 4] = path[len - 2] =
 
-                     pInt(path[len - 2]) - 10 * length;
 
-             }
 
-             return path.join(' ');
 
-         },
 
-         /**
 
-          * Apply a drop shadow by copying elements and giving them different
 
-          * strokes.
 
-          *
 
-          * @function Highcharts.VMLElement#shadow
 
-          *
 
-          * @param {boolean|Highcharts.ShadowOptionsObject} shadowOptions
 
-          *
 
-          * @param {boolean} group
 
-          *
 
-          * @param {boolean} cutOff
 
-          */
 
-         shadow: function (shadowOptions, group, cutOff) {
 
-             var shadows = [],
 
-                 i,
 
-                 element = this.element,
 
-                 renderer = this.renderer,
 
-                 shadow,
 
-                 elemStyle = element.style,
 
-                 markup,
 
-                 path = element.path,
 
-                 strokeWidth,
 
-                 modifiedPath,
 
-                 shadowWidth,
 
-                 shadowElementOpacity;
 
-             // some times empty paths are not strings
 
-             if (path && typeof path.value !== 'string') {
 
-                 path = 'x';
 
-             }
 
-             modifiedPath = path;
 
-             if (shadowOptions) {
 
-                 shadowWidth = pick(shadowOptions.width, 3);
 
-                 shadowElementOpacity =
 
-                     (shadowOptions.opacity || 0.15) / shadowWidth;
 
-                 for (i = 1; i <= 3; i++) {
 
-                     strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
 
-                     // Cut off shadows for stacked column items
 
-                     if (cutOff) {
 
-                         modifiedPath = this.cutOffPath(
 
-                             path.value,
 
-                             strokeWidth + 0.5
 
-                         );
 
-                     }
 
-                     markup = [
 
-                         '<shape isShadow="true" strokeweight="', strokeWidth,
 
-                         '" filled="false" path="', modifiedPath,
 
-                         '" coordsize="10 10" style="', element.style.cssText,
 
-                         '" />'
 
-                     ];
 
-                     shadow = createElement(
 
-                         renderer.prepVML(markup),
 
-                         null, {
 
-                             left: pInt(elemStyle.left) +
 
-                                 pick(shadowOptions.offsetX, 1),
 
-                             top: pInt(elemStyle.top) +
 
-                                 pick(shadowOptions.offsetY, 1)
 
-                         }
 
-                     );
 
-                     if (cutOff) {
 
-                         shadow.cutOff = strokeWidth + 1;
 
-                     }
 
-                     // apply the opacity
 
-                     markup = [
 
-                         '<stroke color="',
 
-                         shadowOptions.color || '#000000',
 
-                         '" opacity="', shadowElementOpacity * i, '"/>'];
 
-                     createElement(renderer.prepVML(markup), null, null, shadow);
 
-                     // insert it
 
-                     if (group) {
 
-                         group.element.appendChild(shadow);
 
-                     } else {
 
-                         element.parentNode.insertBefore(shadow, element);
 
-                     }
 
-                     // record it
 
-                     shadows.push(shadow);
 
-                 }
 
-                 this.shadows = shadows;
 
-             }
 
-             return this;
 
-         },
 
-         updateShadows: noop, // Used in SVG only
 
-         setAttr: function (key, value) {
 
-             if (this.docMode8) { // IE8 setAttribute bug
 
-                 this.element[key] = value;
 
-             } else {
 
-                 this.element.setAttribute(key, value);
 
-             }
 
-         },
 
-         getAttr: function (key) {
 
-             if (this.docMode8) { // IE8 setAttribute bug
 
-                 return this.element[key];
 
-             }
 
-             return this.element.getAttribute(key);
 
-         },
 
-         classSetter: function (value) {
 
-             // IE8 Standards mode has problems retrieving the className unless
 
-             // set like this. IE8 Standards can't set the class name before the
 
-             // element is appended.
 
-             (this.added ? this.element : this).className = value;
 
-         },
 
-         dashstyleSetter: function (value, key, element) {
 
-             var strokeElem = element.getElementsByTagName('stroke')[0] ||
 
-                 createElement(
 
-                     this.renderer.prepVML(['<stroke/>']),
 
-                     null,
 
-                     null,
 
-                     element
 
-                 );
 
-             strokeElem[key] = value || 'solid';
 
-             // Because changing stroke-width will change the dash length and
 
-             // cause an epileptic effect
 
-             this[key] = value;
 
-         },
 
-         dSetter: function (value, key, element) {
 
-             var i,
 
-                 shadows = this.shadows;
 
-             value = value || [];
 
-             // Used in getter for animation
 
-             this.d = value.join && value.join(' ');
 
-             element.path = value = this.pathToVML(value);
 
-             // update shadows
 
-             if (shadows) {
 
-                 i = shadows.length;
 
-                 while (i--) {
 
-                     shadows[i].path = shadows[i].cutOff ?
 
-                         this.cutOffPath(value, shadows[i].cutOff) :
 
-                         value;
 
-                 }
 
-             }
 
-             this.setAttr(key, value);
 
-         },
 
-         fillSetter: function (value, key, element) {
 
-             var nodeName = element.nodeName;
 
-             if (nodeName === 'SPAN') { // text color
 
-                 element.style.color = value;
 
-             } else if (nodeName !== 'IMG') { // #1336
 
-                 element.filled = value !== 'none';
 
-                 this.setAttr(
 
-                     'fillcolor',
 
-                     this.renderer.color(value, element, key, this)
 
-                 );
 
-             }
 
-         },
 
-         'fill-opacitySetter': function (value, key, element) {
 
-             createElement(
 
-                 this.renderer.prepVML(
 
-                     ['<', key.split('-')[0], ' opacity="', value, '"/>']
 
-                 ),
 
-                 null,
 
-                 null,
 
-                 element
 
-             );
 
-         },
 
-         // Don't bother - animation is too slow and filters introduce artifacts
 
-         opacitySetter: noop,
 
-         rotationSetter: function (value, key, element) {
 
-             var style = element.style;
 
-             this[key] = style[key] = value; // style is for #1873
 
-             // Correction for the 1x1 size of the shape container. Used in gauge
 
-             // needles.
 
-             style.left = -Math.round(Math.sin(value * deg2rad) + 1) + 'px';
 
-             style.top = Math.round(Math.cos(value * deg2rad)) + 'px';
 
-         },
 
-         strokeSetter: function (value, key, element) {
 
-             this.setAttr(
 
-                 'strokecolor',
 
-                 this.renderer.color(value, element, key, this)
 
-             );
 
-         },
 
-         'stroke-widthSetter': function (value, key, element) {
 
-             element.stroked = !!value; // VML "stroked" attribute
 
-             this[key] = value; // used in getter, issue #113
 
-             if (isNumber(value)) {
 
-                 value += 'px';
 
-             }
 
-             this.setAttr('strokeweight', value);
 
-         },
 
-         titleSetter: function (value, key) {
 
-             this.setAttr(key, value);
 
-         },
 
-         visibilitySetter: function (value, key, element) {
 
-             // Handle inherited visibility
 
-             if (value === 'inherit') {
 
-                 value = 'visible';
 
-             }
 
-             // Let the shadow follow the main element
 
-             if (this.shadows) {
 
-                 this.shadows.forEach(function (shadow) {
 
-                     shadow.style[key] = value;
 
-                 });
 
-             }
 
-             // Instead of toggling the visibility CSS property, move the div out
 
-             // of the viewport. This works around #61 and #586
 
-             if (element.nodeName === 'DIV') {
 
-                 value = value === 'hidden' ? '-999em' : 0;
 
-                 // In order to redraw, IE7 needs the div to be visible when
 
-                 // tucked away outside the viewport. So the visibility is
 
-                 // actually opposite of the expected value. This applies to the
 
-                 // tooltip only.
 
-                 if (!this.docMode8) {
 
-                     element.style[key] = value ? 'visible' : 'hidden';
 
-                 }
 
-                 key = 'top';
 
-             }
 
-             element.style[key] = value;
 
-         },
 
-         xSetter: function (value, key, element) {
 
-             this[key] = value; // used in getter
 
-             if (key === 'x') {
 
-                 key = 'left';
 
-             } else if (key === 'y') {
 
-                 key = 'top';
 
-             }
 
-             // clipping rectangle special
 
-             if (this.updateClipping) {
 
-                 // the key is now 'left' or 'top' for 'x' and 'y'
 
-                 this[key] = value;
 
-                 this.updateClipping();
 
-             } else {
 
-                 // normal
 
-                 element.style[key] = value;
 
-             }
 
-         },
 
-         zIndexSetter: function (value, key, element) {
 
-             element.style[key] = value;
 
-         },
 
-         fillGetter: function () {
 
-             return this.getAttr('fillcolor') || '';
 
-         },
 
-         strokeGetter: function () {
 
-             return this.getAttr('strokecolor') || '';
 
-         },
 
-         // #7850
 
-         classGetter: function () {
 
-             return this.getAttr('className') || '';
 
-         }
 
-     };
 
-     VMLElement['stroke-opacitySetter'] = VMLElement['fill-opacitySetter'];
 
-     H.VMLElement = VMLElement = extendClass(SVGElement, VMLElement);
 
-     // Some shared setters
 
-     VMLElement.prototype.ySetter =
 
-         VMLElement.prototype.widthSetter =
 
-         VMLElement.prototype.heightSetter =
 
-         VMLElement.prototype.xSetter;
 
-     /**
 
-      * The VML renderer
 
-      *
 
-      * @private
 
-      * @class
 
-      * @name Highcharts.VMLRenderer
 
-      *
 
-      * @augments Highcharts.SVGRenderer
 
-      */
 
-     VMLRendererExtension = { // inherit SVGRenderer
 
-         Element: VMLElement,
 
-         isIE8: win.navigator.userAgent.indexOf('MSIE 8.0') > -1,
 
-         /**
 
-          * Initialize the VMLRenderer.
 
-          *
 
-          * @function Highcharts.VMLRenderer#init
 
-          *
 
-          * @param {object} container
 
-          *
 
-          * @param {number} width
 
-          *
 
-          * @param {number} height
 
-          */
 
-         init: function (container, width, height) {
 
-             var renderer = this,
 
-                 boxWrapper,
 
-                 box,
 
-                 css;
 
-             renderer.alignedObjects = [];
 
-             boxWrapper = renderer.createElement('div')
 
-                 .css({ position: 'relative' });
 
-             box = boxWrapper.element;
 
-             container.appendChild(boxWrapper.element);
 
-             // generate the containing box
 
-             renderer.isVML = true;
 
-             renderer.box = box;
 
-             renderer.boxWrapper = boxWrapper;
 
-             renderer.gradients = {};
 
-             renderer.cache = {}; // Cache for numerical bounding boxes
 
-             renderer.cacheKeys = [];
 
-             renderer.imgCount = 0;
 
-             renderer.setSize(width, height, false);
 
-             // The only way to make IE6 and IE7 print is to use a global
 
-             // namespace. However, with IE8 the only way to make the dynamic
 
-             // shapes visible in screen and print mode seems to be to add the
 
-             // xmlns attribute and the behaviour style inline.
 
-             if (!doc.namespaces.hcv) {
 
-                 doc.namespaces.add('hcv', 'urn:schemas-microsoft-com:vml');
 
-                 // Setup default CSS (#2153, #2368, #2384)
 
-                 css = 'hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke' +
 
-                     '{ behavior:url(#default#VML); display: inline-block; } ';
 
-                 try {
 
-                     doc.createStyleSheet().cssText = css;
 
-                 } catch (e) {
 
-                     doc.styleSheets[0].cssText += css;
 
-                 }
 
-             }
 
-         },
 
-         /**
 
-          * Detect whether the renderer is hidden. This happens when one of the
 
-          * parent elements has display: none
 
-          *
 
-          * @function Highcharts.VMLRenderer#isHidden
 
-          */
 
-         isHidden: function () {
 
-             return !this.box.offsetWidth;
 
-         },
 
-         /**
 
-          * Define a clipping rectangle. In VML it is accomplished by storing the
 
-          * values for setting the CSS style to all associated members.
 
-          *
 
-          * @function Highcharts.VMLRenderer#clipRect
 
-          *
 
-          * @param {number} x
 
-          *
 
-          * @param {number} y
 
-          *
 
-          * @param {number} width
 
-          *
 
-          * @param {number} height
 
-          */
 
-         clipRect: function (x, y, width, height) {
 
-             // create a dummy element
 
-             var clipRect = this.createElement(),
 
-                 isObj = isObject(x);
 
-             // mimic a rectangle with its style object for automatic updating in
 
-             // attr
 
-             return extend(clipRect, {
 
-                 members: [],
 
-                 count: 0,
 
-                 left: (isObj ? x.x : x) + 1,
 
-                 top: (isObj ? x.y : y) + 1,
 
-                 width: (isObj ? x.width : width) - 1,
 
-                 height: (isObj ? x.height : height) - 1,
 
-                 getCSS: function (wrapper) {
 
-                     var element = wrapper.element,
 
-                         nodeName = element.nodeName,
 
-                         isShape = nodeName === 'shape',
 
-                         inverted = wrapper.inverted,
 
-                         rect = this,
 
-                         top = rect.top - (isShape ? element.offsetTop : 0),
 
-                         left = rect.left,
 
-                         right = left + rect.width,
 
-                         bottom = top + rect.height,
 
-                         ret = {
 
-                             clip: 'rect(' +
 
-                                 Math.round(inverted ? left : top) + 'px,' +
 
-                                 Math.round(inverted ? bottom : right) + 'px,' +
 
-                                 Math.round(inverted ? right : bottom) + 'px,' +
 
-                                 Math.round(inverted ? top : left) + 'px)'
 
-                         };
 
-                     // issue 74 workaround
 
-                     if (!inverted && wrapper.docMode8 && nodeName === 'DIV') {
 
-                         extend(ret, {
 
-                             width: right + 'px',
 
-                             height: bottom + 'px'
 
-                         });
 
-                     }
 
-                     return ret;
 
-                 },
 
-                 // used in attr and animation to update the clipping of all
 
-                 // members
 
-                 updateClipping: function () {
 
-                     clipRect.members.forEach(function (member) {
 
-                         // Member.element is falsy on deleted series, like in
 
-                         // stock/members/series-remove demo. Should be removed
 
-                         // from members, but this will do.
 
-                         if (member.element) {
 
-                             member.css(clipRect.getCSS(member));
 
-                         }
 
-                     });
 
-                 }
 
-             });
 
-         },
 
-         /**
 
-          * Take a color and return it if it's a string, make it a gradient if
 
-          * it's a gradient configuration object, and apply opacity.
 
-          *
 
-          * @function Highcharts.VMLRenderer#color
 
-          *
 
-          * @param {object} color
 
-          *        The color or config object
 
-          */
 
-         color: function (color, elem, prop, wrapper) {
 
-             var renderer = this,
 
-                 colorObject,
 
-                 regexRgba = /^rgba/,
 
-                 markup,
 
-                 fillType,
 
-                 ret = 'none';
 
-             // Check for linear or radial gradient
 
-             if (color && color.linearGradient) {
 
-                 fillType = 'gradient';
 
-             } else if (color && color.radialGradient) {
 
-                 fillType = 'pattern';
 
-             }
 
-             if (fillType) {
 
-                 var stopColor,
 
-                     stopOpacity,
 
-                     gradient = color.linearGradient || color.radialGradient,
 
-                     x1,
 
-                     y1,
 
-                     x2,
 
-                     y2,
 
-                     opacity1,
 
-                     opacity2,
 
-                     color1,
 
-                     color2,
 
-                     fillAttr = '',
 
-                     stops = color.stops,
 
-                     firstStop,
 
-                     lastStop,
 
-                     colors = [],
 
-                     addFillNode = function () {
 
-                         // Add the fill subnode. When colors attribute is used,
 
-                         // the meanings of opacity and o:opacity2 are reversed.
 
-                         markup = ['<fill colors="' + colors.join(',') +
 
-                             '" opacity="', opacity2, '" o:opacity2="',
 
-                         opacity1, '" type="', fillType, '" ', fillAttr,
 
-                         'focus="100%" method="any" />'];
 
-                         createElement(
 
-                             renderer.prepVML(markup),
 
-                             null,
 
-                             null,
 
-                             elem
 
-                         );
 
-                     };
 
-                 // Extend from 0 to 1
 
-                 firstStop = stops[0];
 
-                 lastStop = stops[stops.length - 1];
 
-                 if (firstStop[0] > 0) {
 
-                     stops.unshift([
 
-                         0,
 
-                         firstStop[1]
 
-                     ]);
 
-                 }
 
-                 if (lastStop[0] < 1) {
 
-                     stops.push([
 
-                         1,
 
-                         lastStop[1]
 
-                     ]);
 
-                 }
 
-                 // Compute the stops
 
-                 stops.forEach(function (stop, i) {
 
-                     if (regexRgba.test(stop[1])) {
 
-                         colorObject = H.color(stop[1]);
 
-                         stopColor = colorObject.get('rgb');
 
-                         stopOpacity = colorObject.get('a');
 
-                     } else {
 
-                         stopColor = stop[1];
 
-                         stopOpacity = 1;
 
-                     }
 
-                     // Build the color attribute
 
-                     colors.push((stop[0] * 100) + '% ' + stopColor);
 
-                     // Only start and end opacities are allowed, so we use the
 
-                     // first and the last
 
-                     if (!i) {
 
-                         opacity1 = stopOpacity;
 
-                         color2 = stopColor;
 
-                     } else {
 
-                         opacity2 = stopOpacity;
 
-                         color1 = stopColor;
 
-                     }
 
-                 });
 
-                 // Apply the gradient to fills only.
 
-                 if (prop === 'fill') {
 
-                     // Handle linear gradient angle
 
-                     if (fillType === 'gradient') {
 
-                         x1 = gradient.x1 || gradient[0] || 0;
 
-                         y1 = gradient.y1 || gradient[1] || 0;
 
-                         x2 = gradient.x2 || gradient[2] || 0;
 
-                         y2 = gradient.y2 || gradient[3] || 0;
 
-                         fillAttr = 'angle="' + (90 - Math.atan(
 
-                             (y2 - y1) / // y vector
 
-                             (x2 - x1) // x vector
 
-                         ) * 180 / Math.PI) + '"';
 
-                         addFillNode();
 
-                     // Radial (circular) gradient
 
-                     } else {
 
-                         var r = gradient.r,
 
-                             sizex = r * 2,
 
-                             sizey = r * 2,
 
-                             cx = gradient.cx,
 
-                             cy = gradient.cy,
 
-                             radialReference = elem.radialReference,
 
-                             bBox,
 
-                             applyRadialGradient = function () {
 
-                                 if (radialReference) {
 
-                                     bBox = wrapper.getBBox();
 
-                                     cx += (radialReference[0] - bBox.x) /
 
-                                         bBox.width - 0.5;
 
-                                     cy += (radialReference[1] - bBox.y) /
 
-                                         bBox.height - 0.5;
 
-                                     sizex *= radialReference[2] / bBox.width;
 
-                                     sizey *= radialReference[2] / bBox.height;
 
-                                 }
 
-                                 fillAttr = 'src="' +
 
-                                     H.getOptions().global.VMLRadialGradientURL +
 
-                                     '" ' +
 
-                                     'size="' + sizex + ',' + sizey + '" ' +
 
-                                     'origin="0.5,0.5" ' +
 
-                                     'position="' + cx + ',' + cy + '" ' +
 
-                                     'color2="' + color2 + '" ';
 
-                                 addFillNode();
 
-                             };
 
-                         // Apply radial gradient
 
-                         if (wrapper.added) {
 
-                             applyRadialGradient();
 
-                         } else {
 
-                             // We need to know the bounding box to get the size
 
-                             // and position right
 
-                             wrapper.onAdd = applyRadialGradient;
 
-                         }
 
-                         // The fill element's color attribute is broken in IE8
 
-                         // standards mode, so we need to set the parent shape's
 
-                         // fillcolor attribute instead.
 
-                         ret = color1;
 
-                     }
 
-                 // Gradients are not supported for VML stroke, return the first
 
-                 // color. #722.
 
-                 } else {
 
-                     ret = stopColor;
 
-                 }
 
-             // If the color is an rgba color, split it and add a fill node
 
-             // to hold the opacity component
 
-             } else if (regexRgba.test(color) && elem.tagName !== 'IMG') {
 
-                 colorObject = H.color(color);
 
-                 wrapper[prop + '-opacitySetter'](
 
-                     colorObject.get('a'),
 
-                     prop,
 
-                     elem
 
-                 );
 
-                 ret = colorObject.get('rgb');
 
-             } else {
 
-                 // 'stroke' or 'fill' node
 
-                 var propNodes = elem.getElementsByTagName(prop);
 
-                 if (propNodes.length) {
 
-                     propNodes[0].opacity = 1;
 
-                     propNodes[0].type = 'solid';
 
-                 }
 
-                 ret = color;
 
-             }
 
-             return ret;
 
-         },
 
-         /**
 
-          * Take a VML string and prepare it for either IE8 or IE6/IE7.
 
-          *
 
-          * @function Highcharts.VMLRenderer#prepVML
 
-          *
 
-          * @param {Array<*>} markup
 
-          *        A string array of the VML markup to prepare
 
-          */
 
-         prepVML: function (markup) {
 
-             var vmlStyle = 'display:inline-block;behavior:url(#default#VML);',
 
-                 isIE8 = this.isIE8;
 
-             markup = markup.join('');
 
-             if (isIE8) { // add xmlns and style inline
 
-                 markup = markup.replace(
 
-                     '/>',
 
-                     ' xmlns="urn:schemas-microsoft-com:vml" />'
 
-                 );
 
-                 if (markup.indexOf('style="') === -1) {
 
-                     markup = markup.replace(
 
-                         '/>',
 
-                         ' style="' + vmlStyle + '" />'
 
-                     );
 
-                 } else {
 
-                     markup = markup.replace('style="', 'style="' + vmlStyle);
 
-                 }
 
-             } else { // add namespace
 
-                 markup = markup.replace('<', '<hcv:');
 
-             }
 
-             return markup;
 
-         },
 
-         /**
 
-          * Create rotated and aligned text
 
-          *
 
-          * @function Highcharts.VMLRenderer#text
 
-          *
 
-          * @param {string} str
 
-          *
 
-          * @param {number} x
 
-          *
 
-          * @param {number} y
 
-          */
 
-         text: SVGRenderer.prototype.html,
 
-         /**
 
-          * Create and return a path element
 
-          *
 
-          * @function Highcharts.VMLRenderer#path
 
-          *
 
-          * @param {Highcharts.SVGPathArray} path
 
-          */
 
-         path: function (path) {
 
-             var attr = {
 
-                 // subpixel precision down to 0.1 (width and height = 1px)
 
-                 coordsize: '10 10'
 
-             };
 
-             if (isArray(path)) {
 
-                 attr.d = path;
 
-             } else if (isObject(path)) { // attributes
 
-                 extend(attr, path);
 
-             }
 
-             // create the shape
 
-             return this.createElement('shape').attr(attr);
 
-         },
 
-         /**
 
-          * Create and return a circle element. In VML circles are implemented as
 
-          * shapes, which is faster than v:oval
 
-          *
 
-          * @function Highcharts.VMLRenderer#circle
 
-          *
 
-          * @param {number} x
 
-          *
 
-          * @param {number} y
 
-          *
 
-          * @param {number} r
 
-          */
 
-         circle: function (x, y, r) {
 
-             var circle = this.symbol('circle');
 
-             if (isObject(x)) {
 
-                 r = x.r;
 
-                 y = x.y;
 
-                 x = x.x;
 
-             }
 
-             circle.isCircle = true; // Causes x and y to mean center (#1682)
 
-             circle.r = r;
 
-             return circle.attr({ x: x, y: y });
 
-         },
 
-         /**
 
-          * Create a group using an outer div and an inner v:group to allow
 
-          * rotating and flipping. A simple v:group would have problems with
 
-          * positioning child HTML elements and CSS clip.
 
-          *
 
-          * @function Highcharts.VMLRenderer#g
 
-          *
 
-          * @param {string} name
 
-          *        The name of the group
 
-          */
 
-         g: function (name) {
 
-             var wrapper,
 
-                 attribs;
 
-             // set the class name
 
-             if (name) {
 
-                 attribs = {
 
-                     'className': 'highcharts-' + name,
 
-                     'class': 'highcharts-' + name
 
-                 };
 
-             }
 
-             // the div to hold HTML and clipping
 
-             wrapper = this.createElement('div').attr(attribs);
 
-             return wrapper;
 
-         },
 
-         /**
 
-          * VML override to create a regular HTML image.
 
-          *
 
-          * @function Highcharts.VMLRenderer#image
 
-          *
 
-          * @param {string} src
 
-          *
 
-          * @param {number} x
 
-          *
 
-          * @param {number} y
 
-          *
 
-          * @param {number} width
 
-          *
 
-          * @param {number} height
 
-          */
 
-         image: function (src, x, y, width, height) {
 
-             var obj = this.createElement('img')
 
-                 .attr({ src: src });
 
-             if (arguments.length > 1) {
 
-                 obj.attr({
 
-                     x: x,
 
-                     y: y,
 
-                     width: width,
 
-                     height: height
 
-                 });
 
-             }
 
-             return obj;
 
-         },
 
-         /**
 
-          * For rectangles, VML uses a shape for rect to overcome bugs and
 
-          * rotation problems
 
-          *
 
-          * @function Highcharts.VMLRenderer#createElement
 
-          *
 
-          * @param {string} nodeName
 
-          */
 
-         createElement: function (nodeName) {
 
-             return nodeName === 'rect' ?
 
-                 this.symbol(nodeName) :
 
-                 SVGRenderer.prototype.createElement.call(this, nodeName);
 
-         },
 
-         /**
 
-          * In the VML renderer, each child of an inverted div (group) is
 
-          * inverted
 
-          *
 
-          * @function Highcharts.VMLRenderer#invertChild
 
-          *
 
-          * @param {object} element
 
-          *
 
-          * @param {object} parentNode
 
-          */
 
-         invertChild: function (element, parentNode) {
 
-             var ren = this,
 
-                 parentStyle = parentNode.style,
 
-                 imgStyle = element.tagName === 'IMG' && element.style; // #1111
 
-             css(element, {
 
-                 flip: 'x',
 
-                 left: pInt(parentStyle.width) -
 
-                     (imgStyle ? pInt(imgStyle.top) : 1),
 
-                 top: pInt(parentStyle.height) -
 
-                     (imgStyle ? pInt(imgStyle.left) : 1),
 
-                 rotation: -90
 
-             });
 
-             // Recursively invert child elements, needed for nested composite
 
-             // shapes like box plots and error bars. #1680, #1806.
 
-             element.childNodes.forEach(function (child) {
 
-                 ren.invertChild(child, element);
 
-             });
 
-         },
 
-         /**
 
-          * Symbol definitions that override the parent SVG renderer's symbols
 
-          *
 
-          * @name Highcharts.VMLRenderer#symbols
 
-          * @type {Highcharts.Dictionary<Function>}
 
-          */
 
-         symbols: {
 
-             // VML specific arc function
 
-             arc: function (x, y, w, h, options) {
 
-                 var start = options.start,
 
-                     end = options.end,
 
-                     radius = options.r || w || h,
 
-                     innerRadius = options.innerR,
 
-                     cosStart = Math.cos(start),
 
-                     sinStart = Math.sin(start),
 
-                     cosEnd = Math.cos(end),
 
-                     sinEnd = Math.sin(end),
 
-                     ret;
 
-                 if (end - start === 0) { // no angle, don't show it.
 
-                     return ['x'];
 
-                 }
 
-                 ret = [
 
-                     'wa', // clockwise arc to
 
-                     x - radius, // left
 
-                     y - radius, // top
 
-                     x + radius, // right
 
-                     y + radius, // bottom
 
-                     x + radius * cosStart, // start x
 
-                     y + radius * sinStart, // start y
 
-                     x + radius * cosEnd, // end x
 
-                     y + radius * sinEnd // end y
 
-                 ];
 
-                 if (options.open && !innerRadius) {
 
-                     ret.push(
 
-                         'e',
 
-                         'M',
 
-                         x, // - innerRadius,
 
-                         y // - innerRadius
 
-                     );
 
-                 }
 
-                 ret.push(
 
-                     'at', // anti clockwise arc to
 
-                     x - innerRadius, // left
 
-                     y - innerRadius, // top
 
-                     x + innerRadius, // right
 
-                     y + innerRadius, // bottom
 
-                     x + innerRadius * cosEnd, // start x
 
-                     y + innerRadius * sinEnd, // start y
 
-                     x + innerRadius * cosStart, // end x
 
-                     y + innerRadius * sinStart, // end y
 
-                     'x', // finish path
 
-                     'e' // close
 
-                 );
 
-                 ret.isArc = true;
 
-                 return ret;
 
-             },
 
-             // Add circle symbol path. This performs significantly faster than
 
-             // v:oval.
 
-             circle: function (x, y, w, h, wrapper) {
 
-                 if (wrapper && defined(wrapper.r)) {
 
-                     w = h = 2 * wrapper.r;
 
-                 }
 
-                 // Center correction, #1682
 
-                 if (wrapper && wrapper.isCircle) {
 
-                     x -= w / 2;
 
-                     y -= h / 2;
 
-                 }
 
-                 // Return the path
 
-                 return [
 
-                     'wa', // clockwisearcto
 
-                     x, // left
 
-                     y, // top
 
-                     x + w, // right
 
-                     y + h, // bottom
 
-                     x + w, // start x
 
-                     y + h / 2, // start y
 
-                     x + w, // end x
 
-                     y + h / 2, // end y
 
-                     'e' // close
 
-                 ];
 
-             },
 
-             /**
 
-              * Add rectangle symbol path which eases rotation and omits arcsize
 
-              * problems compared to the built-in VML roundrect shape. When
 
-              * borders are not rounded, use the simpler square path, else use
 
-              * the callout path without the arrow.
 
-              */
 
-             rect: function (x, y, w, h, options) {
 
-                 return SVGRenderer.prototype.symbols[
 
-                     !defined(options) || !options.r ? 'square' : 'callout'
 
-                 ].call(0, x, y, w, h, options);
 
-             }
 
-         }
 
-     };
 
-     H.VMLRenderer = VMLRenderer = function () {
 
-         this.init.apply(this, arguments);
 
-     };
 
-     VMLRenderer.prototype = merge(SVGRenderer.prototype, VMLRendererExtension);
 
-     // general renderer
 
-     H.Renderer = VMLRenderer;
 
- }
 
- SVGRenderer.prototype.getSpanWidth = function (wrapper, tspan) {
 
-     var renderer = this,
 
-         bBox = wrapper.getBBox(true),
 
-         actualWidth = bBox.width;
 
-     // Old IE cannot measure the actualWidth for SVG elements (#2314)
 
-     if (!svg && renderer.forExport) {
 
-         actualWidth = renderer.measureSpanWidth(
 
-             tspan.firstChild.data,
 
-             wrapper.styles
 
-         );
 
-     }
 
-     return actualWidth;
 
- };
 
- // This method is used with exporting in old IE, when emulating SVG (see #2314)
 
- SVGRenderer.prototype.measureSpanWidth = function (text, styles) {
 
-     var measuringSpan = doc.createElement('span'),
 
-         offsetWidth,
 
-         textNode = doc.createTextNode(text);
 
-     measuringSpan.appendChild(textNode);
 
-     css(measuringSpan, styles);
 
-     this.box.appendChild(measuringSpan);
 
-     offsetWidth = measuringSpan.offsetWidth;
 
-     discardElement(measuringSpan); // #2463
 
-     return offsetWidth;
 
- };
 
 
  |