oldie.src.js 119 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772
  1. /**
  2. * @license Highcharts JS v9.1.0 (2021-05-04)
  3. *
  4. * Old IE (v6, v7, v8) module for Highcharts v6+.
  5. *
  6. * (c) 2010-2021 Highsoft AS
  7. * Author: Torstein Honsi
  8. *
  9. * License: www.highcharts.com/license
  10. */
  11. 'use strict';
  12. (function (factory) {
  13. if (typeof module === 'object' && module.exports) {
  14. factory['default'] = factory;
  15. module.exports = factory;
  16. } else if (typeof define === 'function' && define.amd) {
  17. define('highcharts/modules/oldie', ['highcharts'], function (Highcharts) {
  18. factory(Highcharts);
  19. factory.Highcharts = Highcharts;
  20. return factory;
  21. });
  22. } else {
  23. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  24. }
  25. }(function (Highcharts) {
  26. var _modules = Highcharts ? Highcharts._modules : {};
  27. function _registerModule(obj, path, args, fn) {
  28. if (!obj.hasOwnProperty(path)) {
  29. obj[path] = fn.apply(null, args);
  30. }
  31. }
  32. _registerModule(_modules, 'Extensions/Math3D.js', [_modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (H, U) {
  33. /* *
  34. *
  35. * (c) 2010-2021 Torstein Honsi
  36. *
  37. * License: www.highcharts.com/license
  38. *
  39. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  40. *
  41. * */
  42. var pick = U.pick;
  43. // Mathematical Functionility
  44. var deg2rad = H.deg2rad;
  45. /* eslint-disable max-len */
  46. /**
  47. * Apply 3-D rotation
  48. * Euler Angles (XYZ):
  49. * cosA = cos(Alfa|Roll)
  50. * cosB = cos(Beta|Pitch)
  51. * cosG = cos(Gamma|Yaw)
  52. *
  53. * Composite rotation:
  54. * | cosB * cosG | cosB * sinG | -sinB |
  55. * | sinA * sinB * cosG - cosA * sinG | sinA * sinB * sinG + cosA * cosG | sinA * cosB |
  56. * | cosA * sinB * cosG + sinA * sinG | cosA * sinB * sinG - sinA * cosG | cosA * cosB |
  57. *
  58. * Now, Gamma/Yaw is not used (angle=0), so we assume cosG = 1 and sinG = 0, so
  59. * we get:
  60. * | cosB | 0 | - sinB |
  61. * | sinA * sinB | cosA | sinA * cosB |
  62. * | cosA * sinB | - sinA | cosA * cosB |
  63. *
  64. * But in browsers, y is reversed, so we get sinA => -sinA. The general result
  65. * is:
  66. * | cosB | 0 | - sinB | | x | | px |
  67. * | - sinA * sinB | cosA | - sinA * cosB | x | y | = | py |
  68. * | cosA * sinB | sinA | cosA * cosB | | z | | pz |
  69. *
  70. * @private
  71. * @function rotate3D
  72. */
  73. /* eslint-enable max-len */
  74. /**
  75. * @private
  76. * @param {number} x
  77. * X coordinate
  78. * @param {number} y
  79. * Y coordinate
  80. * @param {number} z
  81. * Z coordinate
  82. * @param {Highcharts.Rotation3dObject} angles
  83. * Rotation angles
  84. * @return {Highcharts.Rotation3dObject}
  85. * Rotated position
  86. */
  87. function rotate3D(x, y, z, angles) {
  88. return {
  89. x: angles.cosB * x - angles.sinB * z,
  90. y: -angles.sinA * angles.sinB * x + angles.cosA * y -
  91. angles.cosB * angles.sinA * z,
  92. z: angles.cosA * angles.sinB * x + angles.sinA * y +
  93. angles.cosA * angles.cosB * z
  94. };
  95. }
  96. /**
  97. * Perspective3D function is available in global Highcharts scope because is
  98. * needed also outside of perspective() function (#8042).
  99. * @private
  100. * @function Highcharts.perspective3D
  101. *
  102. * @param {Highcharts.Position3DObject} coordinate
  103. * 3D position
  104. *
  105. * @param {Highcharts.Position3DObject} origin
  106. * 3D root position
  107. *
  108. * @param {number} distance
  109. * Perspective distance
  110. *
  111. * @return {Highcharts.PositionObject}
  112. * Perspective 3D Position
  113. *
  114. * @requires highcharts-3d
  115. */
  116. function perspective3D(coordinate, origin, distance) {
  117. var projection = ((distance > 0) && (distance < Number.POSITIVE_INFINITY)) ?
  118. distance / (coordinate.z + origin.z + distance) :
  119. 1;
  120. return {
  121. x: coordinate.x * projection,
  122. y: coordinate.y * projection
  123. };
  124. }
  125. H.perspective3D = perspective3D;
  126. /**
  127. * Transforms a given array of points according to the angles in chart.options.
  128. *
  129. * @private
  130. * @function Highcharts.perspective
  131. *
  132. * @param {Array<Highcharts.Position3DObject>} points
  133. * The array of points
  134. *
  135. * @param {Highcharts.Chart} chart
  136. * The chart
  137. *
  138. * @param {boolean} [insidePlotArea]
  139. * Whether to verify that the points are inside the plotArea
  140. *
  141. * @param {boolean} [useInvertedPersp]
  142. * Whether to use inverted perspective in calculations
  143. *
  144. * @return {Array<Highcharts.Position3DObject>}
  145. * An array of transformed points
  146. *
  147. * @requires highcharts-3d
  148. */
  149. function perspective(points, chart, insidePlotArea, useInvertedPersp) {
  150. var options3d = chart.options.chart.options3d,
  151. /* The useInvertedPersp argument is used for
  152. * inverted charts with already inverted elements,
  153. * such as dataLabels or tooltip positions.
  154. */
  155. inverted = pick(useInvertedPersp,
  156. insidePlotArea ? chart.inverted : false),
  157. origin = {
  158. x: chart.plotWidth / 2,
  159. y: chart.plotHeight / 2,
  160. z: options3d.depth / 2,
  161. vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
  162. },
  163. scale = chart.scale3d || 1,
  164. beta = deg2rad * options3d.beta * (inverted ? -1 : 1),
  165. alpha = deg2rad * options3d.alpha * (inverted ? -1 : 1),
  166. angles = {
  167. cosA: Math.cos(alpha),
  168. cosB: Math.cos(-beta),
  169. sinA: Math.sin(alpha),
  170. sinB: Math.sin(-beta)
  171. };
  172. if (!insidePlotArea) {
  173. origin.x += chart.plotLeft;
  174. origin.y += chart.plotTop;
  175. }
  176. // Transform each point
  177. return points.map(function (point) {
  178. var rotated = rotate3D((inverted ? point.y : point.x) - origin.x, (inverted ? point.x : point.y) - origin.y, (point.z || 0) - origin.z,
  179. angles),
  180. // Apply perspective
  181. coordinate = perspective3D(rotated,
  182. origin,
  183. origin.vd);
  184. // Apply translation
  185. coordinate.x = coordinate.x * scale + origin.x;
  186. coordinate.y = coordinate.y * scale + origin.y;
  187. coordinate.z = rotated.z * scale + origin.z;
  188. return {
  189. x: (inverted ? coordinate.y : coordinate.x),
  190. y: (inverted ? coordinate.x : coordinate.y),
  191. z: coordinate.z
  192. };
  193. });
  194. }
  195. H.perspective = perspective;
  196. /**
  197. * Calculate a distance from camera to points - made for calculating zIndex of
  198. * scatter points.
  199. *
  200. * @private
  201. * @function Highcharts.pointCameraDistance
  202. *
  203. * @param {Highcharts.Dictionary<number>} coordinates
  204. * Coordinates of the specific point
  205. *
  206. * @param {Highcharts.Chart} chart
  207. * Related chart
  208. *
  209. * @return {number}
  210. * Distance from camera to point
  211. *
  212. * @requires highcharts-3d
  213. */
  214. function pointCameraDistance(coordinates, chart) {
  215. var options3d = chart.options.chart.options3d,
  216. cameraPosition = {
  217. x: chart.plotWidth / 2,
  218. y: chart.plotHeight / 2,
  219. z: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0) +
  220. options3d.depth
  221. },
  222. // Added support for objects with plotX or x coordinates.
  223. distance = Math.sqrt(Math.pow(cameraPosition.x - pick(coordinates.plotX,
  224. coordinates.x), 2) +
  225. Math.pow(cameraPosition.y - pick(coordinates.plotY,
  226. coordinates.y), 2) +
  227. Math.pow(cameraPosition.z - pick(coordinates.plotZ,
  228. coordinates.z), 2));
  229. return distance;
  230. }
  231. H.pointCameraDistance = pointCameraDistance;
  232. /**
  233. * Calculate area of a 2D polygon using Shoelace algorithm
  234. * https://en.wikipedia.org/wiki/Shoelace_formula
  235. *
  236. * @private
  237. * @function Highcharts.shapeArea
  238. *
  239. * @param {Array<Highcharts.PositionObject>} vertexes
  240. * 2D Polygon
  241. *
  242. * @return {number}
  243. * Calculated area
  244. *
  245. * @requires highcharts-3d
  246. */
  247. function shapeArea(vertexes) {
  248. var area = 0,
  249. i,
  250. j;
  251. for (i = 0; i < vertexes.length; i++) {
  252. j = (i + 1) % vertexes.length;
  253. area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
  254. }
  255. return area / 2;
  256. }
  257. H.shapeArea = shapeArea;
  258. /**
  259. * Calculate area of a 3D polygon after perspective projection
  260. *
  261. * @private
  262. * @function Highcharts.shapeArea3d
  263. *
  264. * @param {Array<Highcharts.Position3DObject>} vertexes
  265. * 3D Polygon
  266. *
  267. * @param {Highcharts.Chart} chart
  268. * Related chart
  269. *
  270. * @param {boolean} [insidePlotArea]
  271. * Whether to verify that the points are inside the plotArea
  272. *
  273. * @return {number}
  274. * Calculated area
  275. *
  276. * @requires highcharts-3d
  277. */
  278. function shapeArea3D(vertexes, chart, insidePlotArea) {
  279. return shapeArea(perspective(vertexes, chart, insidePlotArea));
  280. }
  281. H.shapeArea3d = shapeArea3D;
  282. var mathModule = {
  283. perspective: perspective,
  284. perspective3D: perspective3D,
  285. pointCameraDistance: pointCameraDistance,
  286. shapeArea: shapeArea,
  287. shapeArea3D: shapeArea3D
  288. };
  289. return mathModule;
  290. });
  291. _registerModule(_modules, 'Core/Renderer/SVG/SVGElement3D.js', [_modules['Core/Color/Color.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Utilities.js']], function (Color, SVGElement, U) {
  292. /* *
  293. *
  294. * (c) 2010-2021 Torstein Honsi
  295. *
  296. * Extensions to the SVGRenderer class to enable 3D shapes
  297. *
  298. * License: www.highcharts.com/license
  299. *
  300. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  301. *
  302. * */
  303. var color = Color.parse;
  304. var defined = U.defined,
  305. merge = U.merge,
  306. objectEach = U.objectEach,
  307. pick = U.pick;
  308. /* *
  309. *
  310. * Namespace
  311. *
  312. * */
  313. var SVGElement3D;
  314. (function (SVGElement3D) {
  315. /* *
  316. *
  317. * Functions
  318. *
  319. * */
  320. /* eslint-disable valid-jsdoc */
  321. SVGElement3D.base = {
  322. /**
  323. * The init is used by base - renderer.Element
  324. * @private
  325. */
  326. initArgs: function (args) {
  327. var elem3d = this,
  328. renderer = elem3d.renderer,
  329. paths = renderer[elem3d.pathType + 'Path'](args),
  330. zIndexes = paths.zIndexes;
  331. // build parts
  332. elem3d.parts.forEach(function (part) {
  333. elem3d[part] = renderer.path(paths[part]).attr({
  334. 'class': 'highcharts-3d-' + part,
  335. zIndex: zIndexes[part] || 0
  336. }).add(elem3d);
  337. });
  338. elem3d.attr({
  339. 'stroke-linejoin': 'round',
  340. zIndex: zIndexes.group
  341. });
  342. // store original destroy
  343. elem3d.originalDestroy = elem3d.destroy;
  344. elem3d.destroy = elem3d.destroyParts;
  345. // Store information if any side of element was rendered by force.
  346. elem3d.forcedSides = paths.forcedSides;
  347. },
  348. /**
  349. * Single property setter that applies options to each part
  350. * @private
  351. */
  352. singleSetterForParts: function (prop, val, values, verb, duration, complete) {
  353. var elem3d = this,
  354. newAttr = {},
  355. optionsToApply = [null,
  356. null, (verb || 'attr'),
  357. duration,
  358. complete],
  359. hasZIndexes = values && values.zIndexes;
  360. if (!values) {
  361. newAttr[prop] = val;
  362. optionsToApply[0] = newAttr;
  363. }
  364. else {
  365. // It is needed to deal with the whole group zIndexing
  366. // in case of graph rotation
  367. if (hasZIndexes && hasZIndexes.group) {
  368. this.attr({
  369. zIndex: hasZIndexes.group
  370. });
  371. }
  372. objectEach(values, function (partVal, part) {
  373. newAttr[part] = {};
  374. newAttr[part][prop] = partVal;
  375. // include zIndexes if provided
  376. if (hasZIndexes) {
  377. newAttr[part].zIndex = values.zIndexes[part] || 0;
  378. }
  379. });
  380. optionsToApply[1] = newAttr;
  381. }
  382. return elem3d.processParts.apply(elem3d, optionsToApply);
  383. },
  384. /**
  385. * Calls function for each part. Used for attr, animate and destroy.
  386. * @private
  387. */
  388. processParts: function (props, partsProps, verb, duration, complete) {
  389. var elem3d = this;
  390. elem3d.parts.forEach(function (part) {
  391. // if different props for different parts
  392. if (partsProps) {
  393. props = pick(partsProps[part], false);
  394. }
  395. // only if something to set, but allow undefined
  396. if (props !== false) {
  397. elem3d[part][verb](props, duration, complete);
  398. }
  399. });
  400. return elem3d;
  401. },
  402. /**
  403. * Destroy all parts
  404. * @private
  405. */
  406. destroyParts: function () {
  407. this.processParts(null, null, 'destroy');
  408. return this.originalDestroy();
  409. }
  410. };
  411. SVGElement3D.cuboid = merge(SVGElement3D.base, {
  412. parts: ['front', 'top', 'side'],
  413. pathType: 'cuboid',
  414. attr: function (args, val, complete, continueAnimation) {
  415. // Resolve setting attributes by string name
  416. if (typeof args === 'string' && typeof val !== 'undefined') {
  417. var key = args;
  418. args = {};
  419. args[key] = val;
  420. }
  421. if (args.shapeArgs || defined(args.x)) {
  422. return this.singleSetterForParts('d', null, this.renderer[this.pathType + 'Path'](args.shapeArgs || args));
  423. }
  424. return SVGElement.prototype.attr.call(this, args, void 0, complete, continueAnimation);
  425. },
  426. animate: function (args, duration, complete) {
  427. if (defined(args.x) && defined(args.y)) {
  428. var paths = this.renderer[this.pathType + 'Path'](args),
  429. forcedSides = paths.forcedSides;
  430. this.singleSetterForParts('d', null, paths, 'animate', duration, complete);
  431. this.attr({
  432. zIndex: paths.zIndexes.group
  433. });
  434. // If sides that are forced to render changed, recalculate
  435. // colors.
  436. if (forcedSides !== this.forcedSides) {
  437. this.forcedSides = forcedSides;
  438. SVGElement3D.cuboid.fillSetter.call(this, this.fill);
  439. }
  440. }
  441. else {
  442. SVGElement.prototype.animate.call(this, args, duration, complete);
  443. }
  444. return this;
  445. },
  446. fillSetter: function (fill) {
  447. var elem3d = this;
  448. elem3d.forcedSides = elem3d.forcedSides || [];
  449. elem3d.singleSetterForParts('fill', null, {
  450. front: fill,
  451. // Do not change color if side was forced to render.
  452. top: color(fill).brighten(elem3d.forcedSides.indexOf('top') >= 0 ? 0 : 0.1).get(),
  453. side: color(fill).brighten(elem3d.forcedSides.indexOf('side') >= 0 ? 0 : -0.1).get()
  454. });
  455. // fill for animation getter (#6776)
  456. elem3d.color = elem3d.fill = fill;
  457. return elem3d;
  458. }
  459. });
  460. /* eslint-enable valid-jsdoc */
  461. })(SVGElement3D || (SVGElement3D = {}));
  462. return SVGElement3D;
  463. });
  464. _registerModule(_modules, 'Core/Renderer/SVG/SVGRenderer3D.js', [_modules['Core/Animation/AnimationUtilities.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Extensions/Math3D.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGElement3D.js'], _modules['Core/Renderer/SVG/SVGRenderer.js'], _modules['Core/Utilities.js']], function (A, Color, H, Math3D, SVGElement, SVGElement3D, SVGRenderer, U) {
  465. /* *
  466. *
  467. * (c) 2010-2021 Torstein Honsi
  468. *
  469. * Extensions to the SVGRenderer class to enable 3D shapes
  470. *
  471. * License: www.highcharts.com/license
  472. *
  473. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  474. *
  475. * */
  476. var animObject = A.animObject;
  477. var color = Color.parse;
  478. var charts = H.charts,
  479. deg2rad = H.deg2rad;
  480. var perspective = Math3D.perspective,
  481. shapeArea = Math3D.shapeArea;
  482. var defined = U.defined,
  483. extend = U.extend,
  484. merge = U.merge,
  485. pick = U.pick;
  486. /* *
  487. *
  488. * Constants
  489. *
  490. * */
  491. var cos = Math.cos,
  492. sin = Math.sin,
  493. PI = Math.PI,
  494. dFactor = (4 * (Math.sqrt(2) - 1) / 3) / (PI / 2);
  495. /* *
  496. *
  497. * Functions
  498. *
  499. * */
  500. /* eslint-disable valid-jsdoc */
  501. /**
  502. * Method to construct a curved path. Can 'wrap' around more then 180 degrees.
  503. * @private
  504. */
  505. function curveTo(cx, cy, rx, ry, start, end, dx, dy) {
  506. var result = [],
  507. arcAngle = end - start;
  508. if ((end > start) && (end - start > Math.PI / 2 + 0.0001)) {
  509. result = result.concat(curveTo(cx, cy, rx, ry, start, start + (Math.PI / 2), dx, dy));
  510. result = result.concat(curveTo(cx, cy, rx, ry, start + (Math.PI / 2), end, dx, dy));
  511. return result;
  512. }
  513. if ((end < start) && (start - end > Math.PI / 2 + 0.0001)) {
  514. result = result.concat(curveTo(cx, cy, rx, ry, start, start - (Math.PI / 2), dx, dy));
  515. result = result.concat(curveTo(cx, cy, rx, ry, start - (Math.PI / 2), end, dx, dy));
  516. return result;
  517. }
  518. return [[
  519. 'C',
  520. cx + (rx * Math.cos(start)) -
  521. ((rx * dFactor * arcAngle) * Math.sin(start)) + dx,
  522. cy + (ry * Math.sin(start)) +
  523. ((ry * dFactor * arcAngle) * Math.cos(start)) + dy,
  524. cx + (rx * Math.cos(end)) +
  525. ((rx * dFactor * arcAngle) * Math.sin(end)) + dx,
  526. cy + (ry * Math.sin(end)) -
  527. ((ry * dFactor * arcAngle) * Math.cos(end)) + dy,
  528. cx + (rx * Math.cos(end)) + dx,
  529. cy + (ry * Math.sin(end)) + dy
  530. ]];
  531. }
  532. /* *
  533. *
  534. * Composition
  535. *
  536. * */
  537. SVGRenderer.prototype.elements3d = SVGElement3D;
  538. SVGRenderer.prototype.toLinePath = function (points, closed) {
  539. var result = [];
  540. // Put "L x y" for each point
  541. points.forEach(function (point) {
  542. result.push(['L', point.x, point.y]);
  543. });
  544. if (points.length) {
  545. // Set the first element to M
  546. result[0][0] = 'M';
  547. // If it is a closed line, add Z
  548. if (closed) {
  549. result.push(['Z']);
  550. }
  551. }
  552. return result;
  553. };
  554. SVGRenderer.prototype.toLineSegments = function (points) {
  555. var result = [],
  556. m = true;
  557. points.forEach(function (point) {
  558. result.push(m ? ['M', point.x, point.y] : ['L', point.x, point.y]);
  559. m = !m;
  560. });
  561. return result;
  562. };
  563. // A 3-D Face is defined by it's 3D vertexes, and is only visible if it's
  564. // vertexes are counter-clockwise (Back-face culling). It is used as a
  565. // polyhedron Element
  566. SVGRenderer.prototype.face3d = function (args) {
  567. var renderer = this,
  568. ret = this.createElement('path');
  569. ret.vertexes = [];
  570. ret.insidePlotArea = false;
  571. ret.enabled = true;
  572. /* eslint-disable no-invalid-this */
  573. ret.attr = function (hash) {
  574. if (typeof hash === 'object' &&
  575. (defined(hash.enabled) ||
  576. defined(hash.vertexes) ||
  577. defined(hash.insidePlotArea))) {
  578. this.enabled = pick(hash.enabled, this.enabled);
  579. this.vertexes = pick(hash.vertexes, this.vertexes);
  580. this.insidePlotArea = pick(hash.insidePlotArea, this.insidePlotArea);
  581. delete hash.enabled;
  582. delete hash.vertexes;
  583. delete hash.insidePlotArea;
  584. var chart = charts[renderer.chartIndex],
  585. vertexes2d = perspective(this.vertexes,
  586. chart,
  587. this.insidePlotArea),
  588. path = renderer.toLinePath(vertexes2d,
  589. true),
  590. area = shapeArea(vertexes2d);
  591. hash.d = path;
  592. hash.visibility = (this.enabled && area > 0) ? 'visible' : 'hidden';
  593. }
  594. return SVGElement.prototype.attr.apply(this, arguments);
  595. };
  596. ret.animate = function (params) {
  597. if (typeof params === 'object' &&
  598. (defined(params.enabled) ||
  599. defined(params.vertexes) ||
  600. defined(params.insidePlotArea))) {
  601. this.enabled = pick(params.enabled, this.enabled);
  602. this.vertexes = pick(params.vertexes, this.vertexes);
  603. this.insidePlotArea = pick(params.insidePlotArea, this.insidePlotArea);
  604. delete params.enabled;
  605. delete params.vertexes;
  606. delete params.insidePlotArea;
  607. var chart = charts[renderer.chartIndex],
  608. vertexes2d = perspective(this.vertexes,
  609. chart,
  610. this.insidePlotArea),
  611. path = renderer.toLinePath(vertexes2d,
  612. true),
  613. area = shapeArea(vertexes2d),
  614. visibility = (this.enabled && area > 0) ? 'visible' : 'hidden';
  615. params.d = path;
  616. this.attr('visibility', visibility);
  617. }
  618. return SVGElement.prototype.animate.apply(this, arguments);
  619. };
  620. /* eslint-enable no-invalid-this */
  621. return ret.attr(args);
  622. };
  623. // A Polyhedron is a handy way of defining a group of 3-D faces. It's only
  624. // attribute is `faces`, an array of attributes of each one of it's Face3D
  625. // instances.
  626. SVGRenderer.prototype.polyhedron = function (args) {
  627. var renderer = this,
  628. result = this.g(),
  629. destroy = result.destroy;
  630. if (!this.styledMode) {
  631. result.attr({
  632. 'stroke-linejoin': 'round'
  633. });
  634. }
  635. result.faces = [];
  636. /* eslint-disable no-invalid-this */
  637. // destroy all children
  638. result.destroy = function () {
  639. for (var i = 0; i < result.faces.length; i++) {
  640. result.faces[i].destroy();
  641. }
  642. return destroy.call(this);
  643. };
  644. result.attr = function (hash, val, complete, continueAnimation) {
  645. if (typeof hash === 'object' && defined(hash.faces)) {
  646. while (result.faces.length > hash.faces.length) {
  647. result.faces.pop().destroy();
  648. }
  649. while (result.faces.length < hash.faces.length) {
  650. result.faces.push(renderer.face3d().add(result));
  651. }
  652. for (var i = 0; i < hash.faces.length; i++) {
  653. if (renderer.styledMode) {
  654. delete hash.faces[i].fill;
  655. }
  656. result.faces[i].attr(hash.faces[i], null, complete, continueAnimation);
  657. }
  658. delete hash.faces;
  659. }
  660. return SVGElement.prototype.attr.apply(this, arguments);
  661. };
  662. result.animate = function (params, duration, complete) {
  663. if (params && params.faces) {
  664. while (result.faces.length > params.faces.length) {
  665. result.faces.pop().destroy();
  666. }
  667. while (result.faces.length < params.faces.length) {
  668. result.faces.push(renderer.face3d().add(result));
  669. }
  670. for (var i = 0; i < params.faces.length; i++) {
  671. result.faces[i].animate(params.faces[i], duration, complete);
  672. }
  673. delete params.faces;
  674. }
  675. return SVGElement.prototype.animate.apply(this, arguments);
  676. };
  677. /* eslint-enable no-invalid-this */
  678. return result.attr(args);
  679. };
  680. /**
  681. * return result, generalization
  682. * @private
  683. * @requires highcharts-3d
  684. */
  685. SVGRenderer.prototype.element3d = function (type, shapeArgs) {
  686. // base
  687. var ret = this.g();
  688. // extend
  689. extend(ret, this.elements3d[type]);
  690. // init
  691. ret.initArgs(shapeArgs);
  692. // return
  693. return ret;
  694. };
  695. // generelized, so now use simply
  696. SVGRenderer.prototype.cuboid = function (shapeArgs) {
  697. return this.element3d('cuboid', shapeArgs);
  698. };
  699. // Generates a cuboid path and zIndexes
  700. SVGRenderer.prototype.cuboidPath = function (shapeArgs) {
  701. var x = shapeArgs.x || 0,
  702. y = shapeArgs.y || 0,
  703. z = shapeArgs.z || 0,
  704. // For side calculation (right/left)
  705. // there is a need for height (and other shapeArgs arguments)
  706. // to be at least 1px
  707. h = shapeArgs.height || 0,
  708. w = shapeArgs.width || 0,
  709. d = shapeArgs.depth || 0,
  710. chart = charts[this.chartIndex],
  711. front,
  712. back,
  713. top,
  714. bottom,
  715. left,
  716. right,
  717. shape,
  718. path1,
  719. path2,
  720. path3,
  721. isFront,
  722. isTop,
  723. isRight,
  724. options3d = chart.options.chart.options3d,
  725. alpha = options3d.alpha,
  726. // Priority for x axis is the biggest,
  727. // because of x direction has biggest influence on zIndex
  728. incrementX = 1000000,
  729. // y axis has the smallest priority in case of our charts
  730. // (needs to be set because of stacking)
  731. incrementY = 10,
  732. incrementZ = 100,
  733. zIndex = 0,
  734. // The 8 corners of the cube
  735. pArr = [{
  736. x: x,
  737. y: y,
  738. z: z
  739. }, {
  740. x: x + w,
  741. y: y,
  742. z: z
  743. }, {
  744. x: x + w,
  745. y: y + h,
  746. z: z
  747. }, {
  748. x: x,
  749. y: y + h,
  750. z: z
  751. }, {
  752. x: x,
  753. y: y + h,
  754. z: z + d
  755. }, {
  756. x: x + w,
  757. y: y + h,
  758. z: z + d
  759. }, {
  760. x: x + w,
  761. y: y,
  762. z: z + d
  763. }, {
  764. x: x,
  765. y: y,
  766. z: z + d
  767. }],
  768. forcedSides = [],
  769. pickShape;
  770. // apply perspective
  771. pArr = perspective(pArr, chart, shapeArgs.insidePlotArea);
  772. /**
  773. * helper method to decide which side is visible
  774. * @private
  775. */
  776. function mapSidePath(i) {
  777. // Added support for 0 value in columns, where height is 0
  778. // but the shape is rendered.
  779. // Height is used from 1st to 6th element of pArr
  780. if (h === 0 && i > 1 && i < 6) { // [2, 3, 4, 5]
  781. return {
  782. x: pArr[i].x,
  783. // when height is 0 instead of cuboid we render plane
  784. // so it is needed to add fake 10 height to imitate cuboid
  785. // for side calculation
  786. y: pArr[i].y + 10,
  787. z: pArr[i].z
  788. };
  789. }
  790. // It is needed to calculate dummy sides (front/back) for breaking
  791. // points in case of x and depth values. If column has side,
  792. // it means that x values of front and back side are different.
  793. if (pArr[0].x === pArr[7].x && i >= 4) { // [4, 5, 6, 7]
  794. return {
  795. x: pArr[i].x + 10,
  796. // when height is 0 instead of cuboid we render plane
  797. // so it is needed to add fake 10 height to imitate cuboid
  798. // for side calculation
  799. y: pArr[i].y,
  800. z: pArr[i].z
  801. };
  802. }
  803. // Added dummy depth
  804. if (d === 0 && i < 2 || i > 5) { // [0, 1, 6, 7]
  805. return {
  806. x: pArr[i].x,
  807. // when height is 0 instead of cuboid we render plane
  808. // so it is needed to add fake 10 height to imitate cuboid
  809. // for side calculation
  810. y: pArr[i].y,
  811. z: pArr[i].z + 10
  812. };
  813. }
  814. return pArr[i];
  815. }
  816. /**
  817. * method creating the final side
  818. * @private
  819. */
  820. function mapPath(i) {
  821. return pArr[i];
  822. }
  823. /**
  824. * First value - path with specific face
  825. * Second value - added information about side for later calculations.
  826. * Possible second values are 0 for path1, 1 for path2 and -1 for no path
  827. * chosen.
  828. * Third value - string containing information about current side
  829. * of cuboid for forcing side rendering.
  830. * @private
  831. */
  832. pickShape = function (verticesIndex1, verticesIndex2, side) {
  833. var ret = [[], -1],
  834. // An array of vertices for cuboid face
  835. face1 = verticesIndex1.map(mapPath),
  836. face2 = verticesIndex2.map(mapPath),
  837. // dummy face is calculated the same way as standard face,
  838. // but if cuboid height is 0 additional height is added so it is
  839. // possible to use this vertices array for visible face calculation
  840. dummyFace1 = verticesIndex1.map(mapSidePath),
  841. dummyFace2 = verticesIndex2.map(mapSidePath);
  842. if (shapeArea(face1) < 0) {
  843. ret = [face1, 0];
  844. }
  845. else if (shapeArea(face2) < 0) {
  846. ret = [face2, 1];
  847. }
  848. else if (side) {
  849. forcedSides.push(side);
  850. if (shapeArea(dummyFace1) < 0) {
  851. ret = [face1, 0];
  852. }
  853. else if (shapeArea(dummyFace2) < 0) {
  854. ret = [face2, 1];
  855. }
  856. else {
  857. ret = [face1, 0]; // force side calculation.
  858. }
  859. }
  860. return ret;
  861. };
  862. // front or back
  863. front = [3, 2, 1, 0];
  864. back = [7, 6, 5, 4];
  865. shape = pickShape(front, back, 'front');
  866. path1 = shape[0];
  867. isFront = shape[1];
  868. // top or bottom
  869. top = [1, 6, 7, 0];
  870. bottom = [4, 5, 2, 3];
  871. shape = pickShape(top, bottom, 'top');
  872. path2 = shape[0];
  873. isTop = shape[1];
  874. // side
  875. right = [1, 2, 5, 6];
  876. left = [0, 7, 4, 3];
  877. shape = pickShape(right, left, 'side');
  878. path3 = shape[0];
  879. isRight = shape[1];
  880. /* New block used for calculating zIndex. It is basing on X, Y and Z
  881. position of specific columns. All zIndexes (for X, Y and Z values) are
  882. added to the final zIndex, where every value has different priority. The
  883. biggest priority is in X and Z directions, the lowest index is for
  884. stacked columns (Y direction and the same X and Z positions). Big
  885. differences between priorities is made because we need to ensure that
  886. even for big changes in Y and Z parameters all columns will be drawn
  887. correctly. */
  888. if (isRight === 1) {
  889. // It is needed to connect value with current chart width
  890. // for big chart size.
  891. zIndex += incrementX * (chart.plotWidth - x);
  892. }
  893. else if (!isRight) {
  894. zIndex += incrementX * x;
  895. }
  896. zIndex += incrementY * (!isTop ||
  897. // Numbers checked empirically
  898. (alpha >= 0 && alpha <= 180 || alpha < 360 && alpha > 357.5) ?
  899. chart.plotHeight - y : 10 + y);
  900. if (isFront === 1) {
  901. zIndex += incrementZ * (z);
  902. }
  903. else if (!isFront) {
  904. zIndex += incrementZ * (1000 - z);
  905. }
  906. return {
  907. front: this.toLinePath(path1, true),
  908. top: this.toLinePath(path2, true),
  909. side: this.toLinePath(path3, true),
  910. zIndexes: {
  911. group: Math.round(zIndex)
  912. },
  913. forcedSides: forcedSides,
  914. // additional info about zIndexes
  915. isFront: isFront,
  916. isTop: isTop
  917. }; // #4774
  918. };
  919. // SECTORS //
  920. SVGRenderer.prototype.arc3d = function (attribs) {
  921. var wrapper = this.g(), renderer = wrapper.renderer, customAttribs = ['x', 'y', 'r', 'innerR', 'start', 'end', 'depth'];
  922. /**
  923. * Get custom attributes. Don't mutate the original object and return an
  924. * object with only custom attr.
  925. * @private
  926. */
  927. function suckOutCustom(params) {
  928. var hasCA = false,
  929. ca = {},
  930. key;
  931. params = merge(params); // Don't mutate the original object
  932. for (key in params) {
  933. if (customAttribs.indexOf(key) !== -1) {
  934. ca[key] = params[key];
  935. delete params[key];
  936. hasCA = true;
  937. }
  938. }
  939. return hasCA ? [ca, params] : false;
  940. }
  941. attribs = merge(attribs);
  942. attribs.alpha = (attribs.alpha || 0) * deg2rad;
  943. attribs.beta = (attribs.beta || 0) * deg2rad;
  944. // Create the different sub sections of the shape
  945. wrapper.top = renderer.path();
  946. wrapper.side1 = renderer.path();
  947. wrapper.side2 = renderer.path();
  948. wrapper.inn = renderer.path();
  949. wrapper.out = renderer.path();
  950. /* eslint-disable no-invalid-this */
  951. // Add all faces
  952. wrapper.onAdd = function () {
  953. var parent = wrapper.parentGroup,
  954. className = wrapper.attr('class');
  955. wrapper.top.add(wrapper);
  956. // These faces are added outside the wrapper group because the z index
  957. // relates to neighbour elements as well
  958. ['out', 'inn', 'side1', 'side2'].forEach(function (face) {
  959. wrapper[face]
  960. .attr({
  961. 'class': className + ' highcharts-3d-side'
  962. })
  963. .add(parent);
  964. });
  965. };
  966. // Cascade to faces
  967. ['addClass', 'removeClass'].forEach(function (fn) {
  968. wrapper[fn] = function () {
  969. var args = arguments;
  970. ['top', 'out', 'inn', 'side1', 'side2'].forEach(function (face) {
  971. wrapper[face][fn].apply(wrapper[face], args);
  972. });
  973. };
  974. });
  975. /**
  976. * Compute the transformed paths and set them to the composite shapes
  977. * @private
  978. */
  979. wrapper.setPaths = function (attribs) {
  980. var paths = wrapper.renderer.arc3dPath(attribs),
  981. zIndex = paths.zTop * 100;
  982. wrapper.attribs = attribs;
  983. wrapper.top.attr({ d: paths.top, zIndex: paths.zTop });
  984. wrapper.inn.attr({ d: paths.inn, zIndex: paths.zInn });
  985. wrapper.out.attr({ d: paths.out, zIndex: paths.zOut });
  986. wrapper.side1.attr({ d: paths.side1, zIndex: paths.zSide1 });
  987. wrapper.side2.attr({ d: paths.side2, zIndex: paths.zSide2 });
  988. // show all children
  989. wrapper.zIndex = zIndex;
  990. wrapper.attr({ zIndex: zIndex });
  991. // Set the radial gradient center the first time
  992. if (attribs.center) {
  993. wrapper.top.setRadialReference(attribs.center);
  994. delete attribs.center;
  995. }
  996. };
  997. wrapper.setPaths(attribs);
  998. /**
  999. * Apply the fill to the top and a darker shade to the sides
  1000. * @private
  1001. */
  1002. wrapper.fillSetter = function (value) {
  1003. var darker = color(value).brighten(-0.1).get();
  1004. this.fill = value;
  1005. this.side1.attr({ fill: darker });
  1006. this.side2.attr({ fill: darker });
  1007. this.inn.attr({ fill: darker });
  1008. this.out.attr({ fill: darker });
  1009. this.top.attr({ fill: value });
  1010. return this;
  1011. };
  1012. // Apply the same value to all. These properties cascade down to the
  1013. // children when set to the composite arc3d.
  1014. ['opacity', 'translateX', 'translateY', 'visibility'].forEach(function (setter) {
  1015. wrapper[setter + 'Setter'] = function (value, key) {
  1016. wrapper[key] = value;
  1017. ['out', 'inn', 'side1', 'side2', 'top'].forEach(function (el) {
  1018. wrapper[el].attr(key, value);
  1019. });
  1020. };
  1021. });
  1022. // Override attr to remove shape attributes and use those to set child paths
  1023. wrapper.attr = function (params) {
  1024. var ca,
  1025. paramArr;
  1026. if (typeof params === 'object') {
  1027. paramArr = suckOutCustom(params);
  1028. if (paramArr) {
  1029. ca = paramArr[0];
  1030. arguments[0] = paramArr[1];
  1031. extend(wrapper.attribs, ca);
  1032. wrapper.setPaths(wrapper.attribs);
  1033. }
  1034. }
  1035. return SVGElement.prototype.attr.apply(wrapper, arguments);
  1036. };
  1037. // Override the animate function by sucking out custom parameters related to
  1038. // the shapes directly, and update the shapes from the animation step.
  1039. wrapper.animate = function (params, animation, complete) {
  1040. var paramArr,
  1041. from = this.attribs,
  1042. to,
  1043. anim,
  1044. randomProp = 'data-' + Math.random().toString(26).substring(2, 9);
  1045. // Attribute-line properties connected to 3D. These shouldn't have been
  1046. // in the attribs collection in the first place.
  1047. delete params.center;
  1048. delete params.z;
  1049. delete params.alpha;
  1050. delete params.beta;
  1051. anim = animObject(pick(animation, this.renderer.globalAnimation));
  1052. if (anim.duration) {
  1053. paramArr = suckOutCustom(params);
  1054. // Params need to have a property in order for the step to run
  1055. // (#5765, #7097, #7437)
  1056. wrapper[randomProp] = 0;
  1057. params[randomProp] = 1;
  1058. wrapper[randomProp + 'Setter'] = H.noop;
  1059. if (paramArr) {
  1060. to = paramArr[0]; // custom attr
  1061. anim.step = function (a, fx) {
  1062. /**
  1063. * @private
  1064. */
  1065. function interpolate(key) {
  1066. return from[key] + (pick(to[key], from[key]) -
  1067. from[key]) * fx.pos;
  1068. }
  1069. if (fx.prop === randomProp) {
  1070. fx.elem.setPaths(merge(from, {
  1071. x: interpolate('x'),
  1072. y: interpolate('y'),
  1073. r: interpolate('r'),
  1074. innerR: interpolate('innerR'),
  1075. start: interpolate('start'),
  1076. end: interpolate('end'),
  1077. depth: interpolate('depth')
  1078. }));
  1079. }
  1080. };
  1081. }
  1082. animation = anim; // Only when duration (#5572)
  1083. }
  1084. return SVGElement.prototype.animate.call(this, params, animation, complete);
  1085. };
  1086. // destroy all children
  1087. wrapper.destroy = function () {
  1088. this.top.destroy();
  1089. this.out.destroy();
  1090. this.inn.destroy();
  1091. this.side1.destroy();
  1092. this.side2.destroy();
  1093. return SVGElement.prototype.destroy.call(this);
  1094. };
  1095. // hide all children
  1096. wrapper.hide = function () {
  1097. this.top.hide();
  1098. this.out.hide();
  1099. this.inn.hide();
  1100. this.side1.hide();
  1101. this.side2.hide();
  1102. };
  1103. wrapper.show = function (inherit) {
  1104. this.top.show(inherit);
  1105. this.out.show(inherit);
  1106. this.inn.show(inherit);
  1107. this.side1.show(inherit);
  1108. this.side2.show(inherit);
  1109. };
  1110. /* eslint-enable no-invalid-this */
  1111. return wrapper;
  1112. };
  1113. // Generate the paths required to draw a 3D arc
  1114. SVGRenderer.prototype.arc3dPath = function (shapeArgs) {
  1115. var cx = shapeArgs.x || 0, // x coordinate of the center
  1116. cy = shapeArgs.y || 0, // y coordinate of the center
  1117. start = shapeArgs.start || 0, // start angle
  1118. end = (shapeArgs.end || 0) - 0.00001, // end angle
  1119. r = shapeArgs.r || 0, // radius
  1120. ir = shapeArgs.innerR || 0, // inner radius
  1121. d = shapeArgs.depth || 0, // depth
  1122. alpha = shapeArgs.alpha || 0, // alpha rotation of the chart
  1123. beta = shapeArgs.beta || 0; // beta rotation of the chart
  1124. // Derived Variables
  1125. var cs = Math.cos(start), // cosinus of the start angle
  1126. ss = Math.sin(start), // sinus of the start angle
  1127. ce = Math.cos(end), // cosinus of the end angle
  1128. se = Math.sin(end), // sinus of the end angle
  1129. rx = r * Math.cos(beta), // x-radius
  1130. ry = r * Math.cos(alpha), // y-radius
  1131. irx = ir * Math.cos(beta), // x-radius (inner)
  1132. iry = ir * Math.cos(alpha), // y-radius (inner)
  1133. dx = d * Math.sin(beta), // distance between top and bottom in x
  1134. dy = d * Math.sin(alpha); // distance between top and bottom in y
  1135. // TOP
  1136. var top = [
  1137. ['M',
  1138. cx + (rx * cs),
  1139. cy + (ry * ss)]
  1140. ];
  1141. top = top.concat(curveTo(cx, cy, rx, ry, start, end, 0, 0));
  1142. top.push([
  1143. 'L', cx + (irx * ce), cy + (iry * se)
  1144. ]);
  1145. top = top.concat(curveTo(cx, cy, irx, iry, end, start, 0, 0));
  1146. top.push(['Z']);
  1147. // OUTSIDE
  1148. var b = (beta > 0 ? Math.PI / 2 : 0),
  1149. a = (alpha > 0 ? 0 : Math.PI / 2);
  1150. var start2 = start > -b ? start : (end > -b ? -b : start),
  1151. end2 = end < PI - a ? end : (start < PI - a ? PI - a : end),
  1152. midEnd = 2 * PI - a;
  1153. // When slice goes over bottom middle, need to add both, left and right
  1154. // outer side. Additionally, when we cross right hand edge, create sharp
  1155. // edge. Outer shape/wall:
  1156. //
  1157. // -------
  1158. // / ^ \
  1159. // 4) / / \ \ 1)
  1160. // / / \ \
  1161. // / / \ \
  1162. // (c)=> ==== ==== <=(d)
  1163. // \ \ / /
  1164. // \ \<=(a)/ /
  1165. // \ \ / / <=(b)
  1166. // 3) \ v / 2)
  1167. // -------
  1168. //
  1169. // (a) - inner side
  1170. // (b) - outer side
  1171. // (c) - left edge (sharp)
  1172. // (d) - right edge (sharp)
  1173. // 1..n - rendering order for startAngle = 0, when set to e.g 90, order
  1174. // changes clockwise (1->2, 2->3, n->1) and counterclockwise for negative
  1175. // startAngle
  1176. var out = [
  1177. ['M',
  1178. cx + (rx * cos(start2)),
  1179. cy + (ry * sin(start2))]
  1180. ];
  1181. out = out.concat(curveTo(cx, cy, rx, ry, start2, end2, 0, 0));
  1182. // When shape is wide, it can cross both, (c) and (d) edges, when using
  1183. // startAngle
  1184. if (end > midEnd && start < midEnd) {
  1185. // Go to outer side
  1186. out.push([
  1187. 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
  1188. ]);
  1189. // Curve to the right edge of the slice (d)
  1190. out = out.concat(curveTo(cx, cy, rx, ry, end2, midEnd, dx, dy));
  1191. // Go to the inner side
  1192. out.push([
  1193. 'L', cx + (rx * cos(midEnd)), cy + (ry * sin(midEnd))
  1194. ]);
  1195. // Curve to the true end of the slice
  1196. out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end, 0, 0));
  1197. // Go to the outer side
  1198. out.push([
  1199. 'L', cx + (rx * cos(end)) + dx, cy + (ry * sin(end)) + dy
  1200. ]);
  1201. // Go back to middle (d)
  1202. out = out.concat(curveTo(cx, cy, rx, ry, end, midEnd, dx, dy));
  1203. out.push([
  1204. 'L', cx + (rx * cos(midEnd)), cy + (ry * sin(midEnd))
  1205. ]);
  1206. // Go back to the left edge
  1207. out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end2, 0, 0));
  1208. // But shape can cross also only (c) edge:
  1209. }
  1210. else if (end > PI - a && start < PI - a) {
  1211. // Go to outer side
  1212. out.push([
  1213. 'L',
  1214. cx + (rx * Math.cos(end2)) + dx,
  1215. cy + (ry * Math.sin(end2)) + dy
  1216. ]);
  1217. // Curve to the true end of the slice
  1218. out = out.concat(curveTo(cx, cy, rx, ry, end2, end, dx, dy));
  1219. // Go to the inner side
  1220. out.push([
  1221. 'L', cx + (rx * Math.cos(end)), cy + (ry * Math.sin(end))
  1222. ]);
  1223. // Go back to the artifical end2
  1224. out = out.concat(curveTo(cx, cy, rx, ry, end, end2, 0, 0));
  1225. }
  1226. out.push([
  1227. 'L', cx + (rx * Math.cos(end2)) + dx, cy + (ry * Math.sin(end2)) + dy
  1228. ]);
  1229. out = out.concat(curveTo(cx, cy, rx, ry, end2, start2, dx, dy));
  1230. out.push(['Z']);
  1231. // INSIDE
  1232. var inn = [
  1233. ['M',
  1234. cx + (irx * cs),
  1235. cy + (iry * ss)]
  1236. ];
  1237. inn = inn.concat(curveTo(cx, cy, irx, iry, start, end, 0, 0));
  1238. inn.push([
  1239. 'L', cx + (irx * Math.cos(end)) + dx, cy + (iry * Math.sin(end)) + dy
  1240. ]);
  1241. inn = inn.concat(curveTo(cx, cy, irx, iry, end, start, dx, dy));
  1242. inn.push(['Z']);
  1243. // SIDES
  1244. var side1 = [
  1245. ['M',
  1246. cx + (rx * cs),
  1247. cy + (ry * ss)],
  1248. ['L',
  1249. cx + (rx * cs) + dx,
  1250. cy + (ry * ss) + dy],
  1251. ['L',
  1252. cx + (irx * cs) + dx,
  1253. cy + (iry * ss) + dy],
  1254. ['L',
  1255. cx + (irx * cs),
  1256. cy + (iry * ss)],
  1257. ['Z']
  1258. ];
  1259. var side2 = [
  1260. ['M',
  1261. cx + (rx * ce),
  1262. cy + (ry * se)],
  1263. ['L',
  1264. cx + (rx * ce) + dx,
  1265. cy + (ry * se) + dy],
  1266. ['L',
  1267. cx + (irx * ce) + dx,
  1268. cy + (iry * se) + dy],
  1269. ['L',
  1270. cx + (irx * ce),
  1271. cy + (iry * se)],
  1272. ['Z']
  1273. ];
  1274. // correction for changed position of vanishing point caused by alpha and
  1275. // beta rotations
  1276. var angleCorr = Math.atan2(dy, -dx),
  1277. angleEnd = Math.abs(end + angleCorr),
  1278. angleStart = Math.abs(start + angleCorr),
  1279. angleMid = Math.abs((start + end) / 2 + angleCorr);
  1280. /**
  1281. * set to 0-PI range
  1282. * @private
  1283. */
  1284. function toZeroPIRange(angle) {
  1285. angle = angle % (2 * Math.PI);
  1286. if (angle > Math.PI) {
  1287. angle = 2 * Math.PI - angle;
  1288. }
  1289. return angle;
  1290. }
  1291. angleEnd = toZeroPIRange(angleEnd);
  1292. angleStart = toZeroPIRange(angleStart);
  1293. angleMid = toZeroPIRange(angleMid);
  1294. // *1e5 is to compensate pInt in zIndexSetter
  1295. var incPrecision = 1e5,
  1296. a1 = angleMid * incPrecision,
  1297. a2 = angleStart * incPrecision,
  1298. a3 = angleEnd * incPrecision;
  1299. return {
  1300. top: top,
  1301. // max angle is PI, so this is always higher
  1302. zTop: Math.PI * incPrecision + 1,
  1303. out: out,
  1304. zOut: Math.max(a1, a2, a3),
  1305. inn: inn,
  1306. zInn: Math.max(a1, a2, a3),
  1307. side1: side1,
  1308. zSide1: a3 * 0.99,
  1309. side2: side2,
  1310. zSide2: a2 * 0.99
  1311. };
  1312. };
  1313. /* *
  1314. *
  1315. * Default Export
  1316. *
  1317. * */
  1318. return SVGRenderer;
  1319. });
  1320. _registerModule(_modules, 'Extensions/Oldie/VMLAxis3D.js', [_modules['Core/Utilities.js']], function (U) {
  1321. /* *
  1322. *
  1323. * (c) 2010-2021 Torstein Honsi
  1324. *
  1325. * Extension to the VML Renderer
  1326. *
  1327. * License: www.highcharts.com/license
  1328. *
  1329. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1330. *
  1331. * */
  1332. var addEvent = U.addEvent;
  1333. /* eslint-disable valid-jsdoc */
  1334. var VMLAxis3DAdditions = /** @class */ (function () {
  1335. /* *
  1336. *
  1337. * Constructors
  1338. *
  1339. * */
  1340. function VMLAxis3DAdditions(axis) {
  1341. this.axis = axis;
  1342. }
  1343. return VMLAxis3DAdditions;
  1344. }());
  1345. var VMLAxis3D = /** @class */ (function () {
  1346. function VMLAxis3D() {
  1347. }
  1348. /* *
  1349. *
  1350. * Static Properties
  1351. *
  1352. * */
  1353. VMLAxis3D.compose = function (AxisClass) {
  1354. AxisClass.keepProps.push('vml');
  1355. addEvent(AxisClass, 'init', VMLAxis3D.onInit);
  1356. addEvent(AxisClass, 'render', VMLAxis3D.onRender);
  1357. };
  1358. /**
  1359. * @private
  1360. */
  1361. VMLAxis3D.onInit = function () {
  1362. var axis = this;
  1363. if (!axis.vml) {
  1364. axis.vml = new VMLAxis3DAdditions(axis);
  1365. }
  1366. };
  1367. /**
  1368. * @private
  1369. */
  1370. VMLAxis3D.onRender = function () {
  1371. var axis = this;
  1372. var vml = axis.vml;
  1373. // VML doesn't support a negative z-index
  1374. if (vml.sideFrame) {
  1375. vml.sideFrame.css({ zIndex: 0 });
  1376. vml.sideFrame.front.attr({
  1377. fill: vml.sideFrame.color
  1378. });
  1379. }
  1380. if (vml.bottomFrame) {
  1381. vml.bottomFrame.css({ zIndex: 1 });
  1382. vml.bottomFrame.front.attr({
  1383. fill: vml.bottomFrame.color
  1384. });
  1385. }
  1386. if (vml.backFrame) {
  1387. vml.backFrame.css({ zIndex: 0 });
  1388. vml.backFrame.front.attr({
  1389. fill: vml.backFrame.color
  1390. });
  1391. }
  1392. };
  1393. return VMLAxis3D;
  1394. }());
  1395. return VMLAxis3D;
  1396. });
  1397. _registerModule(_modules, 'Extensions/Oldie/VMLRenderer3D.js', [_modules['Core/Axis/Axis.js'], _modules['Core/Options.js'], _modules['Extensions/Oldie/VMLAxis3D.js']], function (Axis, O, VMLAxis3D) {
  1398. /* *
  1399. *
  1400. * (c) 2010-2021 Torstein Honsi
  1401. *
  1402. * Extension to the VML Renderer
  1403. *
  1404. * License: www.highcharts.com/license
  1405. *
  1406. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1407. *
  1408. * */
  1409. var setOptions = O.setOptions;
  1410. var VMLRenderer3D = /** @class */ (function () {
  1411. function VMLRenderer3D() {
  1412. }
  1413. /* *
  1414. *
  1415. * Static Properties
  1416. *
  1417. * */
  1418. VMLRenderer3D.compose = function (vmlClass, svgClass) {
  1419. var svgProto = svgClass.prototype;
  1420. var vmlProto = vmlClass.prototype;
  1421. setOptions({ animate: false });
  1422. vmlProto.face3d = svgProto.face3d;
  1423. vmlProto.polyhedron = svgProto.polyhedron;
  1424. vmlProto.elements3d = svgProto.elements3d;
  1425. vmlProto.element3d = svgProto.element3d;
  1426. vmlProto.cuboid = svgProto.cuboid;
  1427. vmlProto.cuboidPath = svgProto.cuboidPath;
  1428. vmlProto.toLinePath = svgProto.toLinePath;
  1429. vmlProto.toLineSegments = svgProto.toLineSegments;
  1430. vmlProto.arc3d = function (shapeArgs) {
  1431. var result = svgProto.arc3d.call(this,
  1432. shapeArgs);
  1433. result.css({ zIndex: result.zIndex });
  1434. return result;
  1435. };
  1436. vmlProto.arc3dPath = svgProto.arc3dPath;
  1437. VMLAxis3D.compose(Axis);
  1438. };
  1439. return VMLRenderer3D;
  1440. }());
  1441. return VMLRenderer3D;
  1442. });
  1443. _registerModule(_modules, 'Extensions/Oldie/Oldie.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Options.js'], _modules['Core/Color/Palette.js'], _modules['Core/Pointer.js'], _modules['Core/Renderer/SVG/SVGElement.js'], _modules['Core/Renderer/SVG/SVGRenderer3D.js'], _modules['Core/Utilities.js'], _modules['Extensions/Oldie/VMLRenderer3D.js']], function (Chart, Color, H, O, palette, Pointer, SVGElement, SVGRenderer, U, VMLRenderer3D) {
  1444. /* *
  1445. *
  1446. * (c) 2010-2021 Torstein Honsi
  1447. *
  1448. * License: www.highcharts.com/license
  1449. *
  1450. * Support for old IE browsers (6, 7 and 8) in Highcharts v6+.
  1451. *
  1452. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1453. *
  1454. * */
  1455. var color = Color.parse;
  1456. var deg2rad = H.deg2rad,
  1457. doc = H.doc,
  1458. noop = H.noop,
  1459. svg = H.svg,
  1460. win = H.win;
  1461. var getOptions = O.getOptions;
  1462. var addEvent = U.addEvent,
  1463. createElement = U.createElement,
  1464. css = U.css,
  1465. defined = U.defined,
  1466. discardElement = U.discardElement,
  1467. erase = U.erase,
  1468. extend = U.extend,
  1469. extendClass = U.extendClass,
  1470. isArray = U.isArray,
  1471. isNumber = U.isNumber,
  1472. isObject = U.isObject,
  1473. pick = U.pick,
  1474. pInt = U.pInt,
  1475. uniqueKey = U.uniqueKey;
  1476. var VMLRenderer,
  1477. VMLElement;
  1478. /**
  1479. * Path to the pattern image required by VML browsers in order to
  1480. * draw radial gradients.
  1481. *
  1482. * @type {string}
  1483. * @default http://code.highcharts.com/{version}/gfx/vml-radial-gradient.png
  1484. * @since 2.3.0
  1485. * @requires modules/oldie
  1486. * @apioption global.VMLRadialGradientURL
  1487. */
  1488. getOptions().global.VMLRadialGradientURL =
  1489. 'http://code.highcharts.com/9.1.0/gfx/vml-radial-gradient.png';
  1490. // Utilites
  1491. if (doc && !doc.defaultView) {
  1492. H.getStyle = U.getStyle = function getStyle(el, prop) {
  1493. var val,
  1494. alias = {
  1495. width: 'clientWidth',
  1496. height: 'clientHeight'
  1497. }[prop];
  1498. if (el.style[prop]) {
  1499. return pInt(el.style[prop]);
  1500. }
  1501. if (prop === 'opacity') {
  1502. prop = 'filter';
  1503. }
  1504. // Getting the rendered width and height
  1505. if (alias) {
  1506. el.style.zoom = 1;
  1507. return Math.max(el[alias] - 2 * getStyle(el, 'padding'), 0);
  1508. }
  1509. val = el.currentStyle[prop.replace(/\-(\w)/g, function (a, b) {
  1510. return b.toUpperCase();
  1511. })];
  1512. if (prop === 'filter') {
  1513. val = val.replace(/alpha\(opacity=([0-9]+)\)/, function (a, b) {
  1514. return (b / 100);
  1515. });
  1516. }
  1517. return val === '' ? 1 : pInt(val);
  1518. };
  1519. }
  1520. /* eslint-disable no-invalid-this, valid-jsdoc */
  1521. if (!svg) {
  1522. // Prevent wrapping from creating false offsetWidths in export in legacy IE.
  1523. // This applies only to charts for export, where IE runs the SVGRenderer
  1524. // instead of the VMLRenderer
  1525. // (#1079, #1063)
  1526. addEvent(SVGElement, 'afterInit', function () {
  1527. if (this.element.nodeName === 'text') {
  1528. this.css({
  1529. position: 'absolute'
  1530. });
  1531. }
  1532. });
  1533. /**
  1534. * Old IE override for pointer normalize, adds chartX and chartY to event
  1535. * arguments.
  1536. *
  1537. * @ignore
  1538. * @function Highcharts.Pointer#normalize
  1539. * @param {global.PointerEvent} e
  1540. * @param {boolean} [chartPosition=false]
  1541. * @return {Highcharts.PointerEventObject}
  1542. */
  1543. Pointer.prototype.normalize = function (e, chartPosition) {
  1544. e = e || win.event;
  1545. if (!e.target) {
  1546. e.target = e.srcElement;
  1547. }
  1548. // Get mouse position
  1549. if (!chartPosition) {
  1550. this.chartPosition = chartPosition = this.getChartPosition();
  1551. }
  1552. return extend(e, {
  1553. // #2005, #2129: the second case is for IE10 quirks mode within
  1554. // framesets
  1555. chartX: Math.round(Math.max(e.x, e.clientX - chartPosition.left)),
  1556. chartY: Math.round(e.y)
  1557. });
  1558. };
  1559. /**
  1560. * Further sanitize the mock-SVG that is generated when exporting charts in
  1561. * oldIE.
  1562. *
  1563. * @private
  1564. * @function Highcharts.Chart#ieSanitizeSVG
  1565. */
  1566. Chart.prototype.ieSanitizeSVG = function (svg) {
  1567. svg = svg
  1568. .replace(/<IMG /g, '<image ')
  1569. .replace(/<(\/?)TITLE>/g, '<$1title>')
  1570. .replace(/height=([^" ]+)/g, 'height="$1"')
  1571. .replace(/width=([^" ]+)/g, 'width="$1"')
  1572. .replace(/hc-svg-href="([^"]+)">/g, 'xlink:href="$1"/>')
  1573. .replace(/ id=([^" >]+)/g, ' id="$1"') // #4003
  1574. .replace(/class=([^" >]+)/g, 'class="$1"')
  1575. .replace(/ transform /g, ' ')
  1576. .replace(/:(path|rect)/g, '$1')
  1577. .replace(/style="([^"]+)"/g, function (s) {
  1578. return s.toLowerCase();
  1579. });
  1580. return svg;
  1581. };
  1582. /**
  1583. * VML namespaces can't be added until after complete. Listening
  1584. * for Perini's doScroll hack is not enough.
  1585. *
  1586. * @private
  1587. * @function Highcharts.Chart#isReadyToRender
  1588. */
  1589. Chart.prototype.isReadyToRender = function () {
  1590. var chart = this;
  1591. // Note: win == win.top is required
  1592. if (!svg &&
  1593. (win == win.top && // eslint-disable-line eqeqeq
  1594. doc.readyState !== 'complete')) {
  1595. doc.attachEvent('onreadystatechange', function () {
  1596. doc.detachEvent('onreadystatechange', chart.firstRender);
  1597. if (doc.readyState === 'complete') {
  1598. chart.firstRender();
  1599. }
  1600. });
  1601. return false;
  1602. }
  1603. return true;
  1604. };
  1605. // IE compatibility hack for generating SVG content that it doesn't really
  1606. // understand. Used by the exporting module.
  1607. if (!doc.createElementNS) {
  1608. doc.createElementNS = function (ns, tagName) {
  1609. return doc.createElement(tagName);
  1610. };
  1611. }
  1612. /**
  1613. * Old IE polyfill for addEventListener, called from inside the addEvent
  1614. * function.
  1615. *
  1616. * @private
  1617. * @function Highcharts.addEventListenerPolyfill<T>
  1618. * @param {string} type
  1619. * @param {Highcharts.EventCallbackFunction<T>} fn
  1620. * @return {void}
  1621. */
  1622. H.addEventListenerPolyfill = function (type, fn) {
  1623. var el = this;
  1624. /**
  1625. * @private
  1626. */
  1627. function wrappedFn(e) {
  1628. e.target = e.srcElement || win; // #2820
  1629. fn.call(el, e);
  1630. }
  1631. if (el.attachEvent) {
  1632. if (!el.hcEventsIE) {
  1633. el.hcEventsIE = {};
  1634. }
  1635. // unique function string (#6746)
  1636. if (!fn.hcKey) {
  1637. fn.hcKey = uniqueKey();
  1638. }
  1639. // Link wrapped fn with original fn, so we can get this in
  1640. // removeEvent
  1641. el.hcEventsIE[fn.hcKey] = wrappedFn;
  1642. el.attachEvent('on' + type, wrappedFn);
  1643. }
  1644. };
  1645. /**
  1646. * @private
  1647. * @function Highcharts.removeEventListenerPolyfill<T>
  1648. * @param {string} type
  1649. * @param {Highcharts.EventCallbackFunction<T>} fn
  1650. * @return {void}
  1651. */
  1652. H.removeEventListenerPolyfill = function (type, fn) {
  1653. if (this.detachEvent) {
  1654. fn = this.hcEventsIE[fn.hcKey];
  1655. this.detachEvent('on' + type, fn);
  1656. }
  1657. };
  1658. /**
  1659. * The VML element wrapper.
  1660. *
  1661. * @private
  1662. * @class
  1663. * @name Highcharts.VMLElement
  1664. *
  1665. * @augments Highcharts.SVGElement
  1666. */
  1667. VMLElement = {
  1668. docMode8: doc && doc.documentMode === 8,
  1669. /**
  1670. * Initialize a new VML element wrapper. It builds the markup as a
  1671. * string to minimize DOM traffic.
  1672. *
  1673. * @function Highcharts.VMLElement#init
  1674. * @param {Highcharts.VMLRenderer} renderer
  1675. * @param {string} nodeName
  1676. */
  1677. init: function (renderer, nodeName) {
  1678. var wrapper = this, markup = ['<', nodeName, ' filled="f" stroked="f"'], style = ['position: ', 'absolute', ';'], isDiv = nodeName === 'div';
  1679. // divs and shapes need size
  1680. if (nodeName === 'shape' || isDiv) {
  1681. style.push('left:0;top:0;width:1px;height:1px;');
  1682. }
  1683. style.push('visibility: ', isDiv ? 'hidden' : 'visible');
  1684. markup.push(' style="', style.join(''), '"/>');
  1685. // create element with default attributes and style
  1686. if (nodeName) {
  1687. markup = isDiv || nodeName === 'span' || nodeName === 'img' ?
  1688. markup.join('') :
  1689. renderer.prepVML(markup);
  1690. wrapper.element = createElement(markup);
  1691. }
  1692. wrapper.renderer = renderer;
  1693. },
  1694. /**
  1695. * Add the node to the given parent
  1696. *
  1697. * @function Highcharts.VMLElement
  1698. * @param {Highcharts.VMLElement} parent
  1699. * @return {Highcharts.VMLElement}
  1700. */
  1701. add: function (parent) {
  1702. var wrapper = this,
  1703. renderer = wrapper.renderer,
  1704. element = wrapper.element,
  1705. box = renderer.box,
  1706. inverted = parent && parent.inverted,
  1707. // get the parent node
  1708. parentNode = parent ?
  1709. parent.element || parent :
  1710. box;
  1711. if (parent) {
  1712. this.parentGroup = parent;
  1713. }
  1714. // if the parent group is inverted, apply inversion on all children
  1715. if (inverted) { // only on groups
  1716. renderer.invertChild(element, parentNode);
  1717. }
  1718. // append it
  1719. parentNode.appendChild(element);
  1720. // align text after adding to be able to read offset
  1721. wrapper.added = true;
  1722. if (wrapper.alignOnAdd && !wrapper.deferUpdateTransform) {
  1723. wrapper.updateTransform();
  1724. }
  1725. // fire an event for internal hooks
  1726. if (wrapper.onAdd) {
  1727. wrapper.onAdd();
  1728. }
  1729. // IE8 Standards can't set the class name before the element is
  1730. // appended
  1731. if (this.className) {
  1732. this.attr('class', this.className);
  1733. }
  1734. return wrapper;
  1735. },
  1736. /**
  1737. * VML always uses htmlUpdateTransform
  1738. *
  1739. * @function Highcharts.VMLElement#updateTransform
  1740. */
  1741. updateTransform: SVGElement.prototype.htmlUpdateTransform,
  1742. /**
  1743. * Set the rotation of a span with oldIE's filter
  1744. *
  1745. * @function Highcharts.VMLElement#setSpanRotation
  1746. * @return {void}
  1747. */
  1748. setSpanRotation: function () {
  1749. // Adjust for alignment and rotation. Rotation of useHTML content is
  1750. // not yet implemented but it can probably be implemented for
  1751. // Firefox 3.5+ on user request. FF3.5+ has support for CSS3
  1752. // transform. The getBBox method also needs to be updated to
  1753. // compensate for the rotation, like it currently does for SVG.
  1754. // Test case: https://jsfiddle.net/highcharts/Ybt44/
  1755. var rotation = this.rotation,
  1756. costheta = Math.cos(rotation * deg2rad),
  1757. sintheta = Math.sin(rotation * deg2rad);
  1758. css(this.element, {
  1759. filter: rotation ? [
  1760. 'progid:DXImageTransform.Microsoft.Matrix(M11=', costheta,
  1761. ', M12=', -sintheta, ', M21=', sintheta, ', M22=', costheta,
  1762. ', sizingMethod=\'auto expand\')'
  1763. ].join('') : 'none'
  1764. });
  1765. },
  1766. /**
  1767. * Get the positioning correction for the span after rotating.
  1768. *
  1769. * @function Highcharts.VMLElement#getSpanCorrection
  1770. */
  1771. getSpanCorrection: function (width, baseline, alignCorrection, rotation, align) {
  1772. var costheta = rotation ? Math.cos(rotation * deg2rad) : 1,
  1773. sintheta = rotation ? Math.sin(rotation * deg2rad) : 0,
  1774. height = pick(this.elemHeight,
  1775. this.element.offsetHeight),
  1776. quad,
  1777. nonLeft = align && align !== 'left';
  1778. // correct x and y
  1779. this.xCorr = (costheta < 0 && -width);
  1780. this.yCorr = (sintheta < 0 && -height);
  1781. // correct for baseline and corners spilling out after rotation
  1782. quad = costheta * sintheta < 0;
  1783. this.xCorr += (sintheta *
  1784. baseline *
  1785. (quad ? 1 - alignCorrection : alignCorrection));
  1786. this.yCorr -= (costheta *
  1787. baseline *
  1788. (rotation ? (quad ? alignCorrection : 1 - alignCorrection) : 1));
  1789. // correct for the length/height of the text
  1790. if (nonLeft) {
  1791. this.xCorr -=
  1792. width * alignCorrection * (costheta < 0 ? -1 : 1);
  1793. if (rotation) {
  1794. this.yCorr -= (height *
  1795. alignCorrection *
  1796. (sintheta < 0 ? -1 : 1));
  1797. }
  1798. css(this.element, {
  1799. textAlign: align
  1800. });
  1801. }
  1802. },
  1803. /**
  1804. * Converts a subset of an SVG path definition to its VML counterpart.
  1805. * Takes an array as the parameter and returns a string.
  1806. *
  1807. * @function Highcharts.VMLElement#pathToVML
  1808. */
  1809. pathToVML: function (value) {
  1810. // convert paths
  1811. var i = value.length,
  1812. path = [];
  1813. while (i--) {
  1814. // Multiply by 10 to allow subpixel precision.
  1815. // Substracting half a pixel seems to make the coordinates
  1816. // align with SVG, but this hasn't been tested thoroughly
  1817. if (isNumber(value[i])) {
  1818. path[i] = Math.round(value[i] * 10) - 5;
  1819. }
  1820. else if (value[i] === 'Z') { // close the path
  1821. path[i] = 'x';
  1822. }
  1823. else {
  1824. path[i] = value[i];
  1825. // When the start X and end X coordinates of an arc are too
  1826. // close, they are rounded to the same value above. In this
  1827. // case, substract or add 1 from the end X and Y positions.
  1828. // #186, #760, #1371, #1410.
  1829. if (value.isArc &&
  1830. (value[i] === 'wa' || value[i] === 'at')) {
  1831. // Start and end X
  1832. if (path[i + 5] === path[i + 7]) {
  1833. path[i + 7] +=
  1834. value[i + 7] > value[i + 5] ? 1 : -1;
  1835. }
  1836. // Start and end Y
  1837. if (path[i + 6] === path[i + 8]) {
  1838. path[i + 8] +=
  1839. value[i + 8] > value[i + 6] ? 1 : -1;
  1840. }
  1841. }
  1842. }
  1843. }
  1844. return path.join(' ') || 'x';
  1845. },
  1846. /**
  1847. * Set the element's clipping to a predefined rectangle
  1848. *
  1849. * @function Highcharts.VMLElement#clip
  1850. * @param {Highcharts.VMLClipRectObject} clipRect
  1851. * @return {Highcharts.VMLElement}
  1852. */
  1853. clip: function (clipRect) {
  1854. var wrapper = this,
  1855. clipMembers,
  1856. cssRet;
  1857. if (clipRect) {
  1858. clipMembers = clipRect.members;
  1859. // Ensure unique list of elements (#1258)
  1860. erase(clipMembers, wrapper);
  1861. clipMembers.push(wrapper);
  1862. wrapper.destroyClip = function () {
  1863. erase(clipMembers, wrapper);
  1864. };
  1865. cssRet = clipRect.getCSS(wrapper);
  1866. }
  1867. else {
  1868. if (wrapper.destroyClip) {
  1869. wrapper.destroyClip();
  1870. }
  1871. cssRet = {
  1872. clip: wrapper.docMode8 ? 'inherit' : 'rect(auto)'
  1873. }; // #1214
  1874. }
  1875. return wrapper.css(cssRet);
  1876. },
  1877. /**
  1878. * Set styles for the element
  1879. *
  1880. * @function Highcharts.VMLElement#css
  1881. * @param {Highcharts.CSSObject} styles
  1882. * @return {Highcharts.VMLElement}
  1883. */
  1884. css: SVGElement.prototype.htmlCss,
  1885. /**
  1886. * Removes a child either by removeChild or move to garbageBin.
  1887. * Issue 490; in VML removeChild results in Orphaned nodes according to
  1888. * sIEve, discardElement does not.
  1889. *
  1890. * @function Highcharts.VMLElement#safeRemoveChild
  1891. * @param {Highcharts.HTMLDOMElement} element
  1892. * @return {void}
  1893. */
  1894. safeRemoveChild: function (element) {
  1895. // discardElement will detach the node from its parent before
  1896. // attaching it to the garbage bin. Therefore it is important that
  1897. // the node is attached and have parent.
  1898. if (element.parentNode) {
  1899. discardElement(element);
  1900. }
  1901. },
  1902. /**
  1903. * Extend element.destroy by removing it from the clip members array
  1904. *
  1905. * @function Highcharts.VMLElement#destroy
  1906. */
  1907. destroy: function () {
  1908. if (this.destroyClip) {
  1909. this.destroyClip();
  1910. }
  1911. return SVGElement.prototype.destroy.apply(this);
  1912. },
  1913. /**
  1914. * Add an event listener. VML override for normalizing event parameters.
  1915. *
  1916. * @function Highcharts.VMLElement#on
  1917. * @param {string} eventType
  1918. * @param {Function} handler
  1919. * @return {Highcharts.VMLElement}
  1920. */
  1921. on: function (eventType, handler) {
  1922. // simplest possible event model for internal use
  1923. this.element['on' + eventType] = function () {
  1924. var e = win.event;
  1925. e.target = e.srcElement;
  1926. handler(e);
  1927. };
  1928. return this;
  1929. },
  1930. /**
  1931. * In stacked columns, cut off the shadows so that they don't overlap
  1932. *
  1933. * @function Highcharts.VMLElement#cutOffPath
  1934. * @param {string} path
  1935. * @param {number} length
  1936. * @return {string}
  1937. */
  1938. cutOffPath: function (path, length) {
  1939. var len;
  1940. // The extra comma tricks the trailing comma remover in
  1941. // "gulp scripts" task
  1942. path = path.split(/[ ,]/);
  1943. len = path.length;
  1944. if (len === 9 || len === 11) {
  1945. path[len - 4] = path[len - 2] =
  1946. pInt(path[len - 2]) - 10 * length;
  1947. }
  1948. return path.join(' ');
  1949. },
  1950. /**
  1951. * Apply a drop shadow by copying elements and giving them different
  1952. * strokes.
  1953. *
  1954. * @function Highcharts.VMLElement#shadow
  1955. * @param {Highcharts.ShadowOptionsObject} shadowOptions
  1956. * @param {Highcharts.VMLElement} group
  1957. * @param {boolean} cutOff
  1958. * @return {Highcharts.VMLElement}
  1959. */
  1960. shadow: function (shadowOptions, group, cutOff) {
  1961. var shadows = [],
  1962. i,
  1963. element = this.element,
  1964. renderer = this.renderer,
  1965. shadow,
  1966. elemStyle = element.style,
  1967. markup,
  1968. path = element.path,
  1969. strokeWidth,
  1970. modifiedPath,
  1971. shadowWidth,
  1972. shadowElementOpacity;
  1973. // some times empty paths are not strings
  1974. if (path && typeof path.value !== 'string') {
  1975. path = 'x';
  1976. }
  1977. modifiedPath = path;
  1978. if (shadowOptions) {
  1979. shadowWidth = pick(shadowOptions.width, 3);
  1980. shadowElementOpacity =
  1981. (shadowOptions.opacity || 0.15) / shadowWidth;
  1982. for (i = 1; i <= 3; i++) {
  1983. strokeWidth = (shadowWidth * 2) + 1 - (2 * i);
  1984. // Cut off shadows for stacked column items
  1985. if (cutOff) {
  1986. modifiedPath = this.cutOffPath(path.value, strokeWidth + 0.5);
  1987. }
  1988. markup = [
  1989. '<shape isShadow="true" strokeweight="', strokeWidth,
  1990. '" filled="false" path="', modifiedPath,
  1991. '" coordsize="10 10" style="', element.style.cssText,
  1992. '" />'
  1993. ];
  1994. shadow = createElement(renderer.prepVML(markup), null, {
  1995. left: (pInt(elemStyle.left) +
  1996. pick(shadowOptions.offsetX, 1)) + 'px',
  1997. top: (pInt(elemStyle.top) +
  1998. pick(shadowOptions.offsetY, 1)) + 'px'
  1999. });
  2000. if (cutOff) {
  2001. shadow.cutOff = strokeWidth + 1;
  2002. }
  2003. // apply the opacity
  2004. markup = [
  2005. '<stroke color="',
  2006. shadowOptions.color || palette.neutralColor100,
  2007. '" opacity="', shadowElementOpacity * i, '"/>'
  2008. ];
  2009. createElement(renderer.prepVML(markup), null, null, shadow);
  2010. // insert it
  2011. if (group) {
  2012. group.element.appendChild(shadow);
  2013. }
  2014. else {
  2015. element.parentNode
  2016. .insertBefore(shadow, element);
  2017. }
  2018. // record it
  2019. shadows.push(shadow);
  2020. }
  2021. this.shadows = shadows;
  2022. }
  2023. return this;
  2024. },
  2025. updateShadows: noop,
  2026. setAttr: function (key, value) {
  2027. if (this.docMode8) { // IE8 setAttribute bug
  2028. this.element[key] = value;
  2029. }
  2030. else {
  2031. this.element.setAttribute(key, value);
  2032. }
  2033. },
  2034. getAttr: function (key) {
  2035. if (this.docMode8) { // IE8 setAttribute bug
  2036. return this.element[key];
  2037. }
  2038. return this.element.getAttribute(key);
  2039. },
  2040. classSetter: function (value) {
  2041. // IE8 Standards mode has problems retrieving the className unless
  2042. // set like this. IE8 Standards can't set the class name before the
  2043. // element is appended.
  2044. (this.added ? this.element : this).className = value;
  2045. },
  2046. dashstyleSetter: function (value, key, element) {
  2047. var strokeElem = element.getElementsByTagName('stroke')[0] ||
  2048. createElement(this.renderer.prepVML(['<stroke/>']),
  2049. null,
  2050. null,
  2051. element);
  2052. strokeElem[key] = value || 'solid';
  2053. // Because changing stroke-width will change the dash length and
  2054. // cause an epileptic effect
  2055. this[key] = value;
  2056. },
  2057. dSetter: function (value, key, element) {
  2058. var i,
  2059. shadows = this.shadows;
  2060. value = value || [];
  2061. // Used in getter for animation
  2062. this.d = value.join && value.join(' ');
  2063. element.path = value = this.pathToVML(value);
  2064. // update shadows
  2065. if (shadows) {
  2066. i = shadows.length;
  2067. while (i--) {
  2068. shadows[i].path = shadows[i].cutOff ?
  2069. this.cutOffPath(value, shadows[i].cutOff) :
  2070. value;
  2071. }
  2072. }
  2073. this.setAttr(key, value);
  2074. },
  2075. fillSetter: function (value, key, element) {
  2076. var nodeName = element.nodeName;
  2077. if (nodeName === 'SPAN') { // text color
  2078. element.style.color = value;
  2079. }
  2080. else if (nodeName !== 'IMG') { // #1336
  2081. element.filled = value !== 'none';
  2082. this.setAttr('fillcolor', this.renderer.color(value, element, key, this));
  2083. }
  2084. },
  2085. 'fill-opacitySetter': function (value, key, element) {
  2086. createElement(this.renderer.prepVML(['<', key.split('-')[0], ' opacity="', value, '"/>']), null, null, element);
  2087. },
  2088. // Don't bother - animation is too slow and filters introduce artifacts
  2089. opacitySetter: noop,
  2090. rotationSetter: function (value, key, element) {
  2091. var style = element.style;
  2092. // style is for #1873:
  2093. this[key] = style[key] = value;
  2094. // Correction for the 1x1 size of the shape container. Used in gauge
  2095. // needles.
  2096. style.left =
  2097. -Math.round(Math.sin(value * deg2rad) + 1) + 'px';
  2098. style.top =
  2099. Math.round(Math.cos(value * deg2rad)) + 'px';
  2100. },
  2101. strokeSetter: function (value, key, element) {
  2102. this.setAttr('strokecolor', this.renderer.color(value, element, key, this));
  2103. },
  2104. 'stroke-widthSetter': function (value, key, element) {
  2105. element.stroked = !!value; // VML "stroked" attribute
  2106. this[key] = value; // used in getter, issue #113
  2107. if (isNumber(value)) {
  2108. value += 'px';
  2109. }
  2110. this.setAttr('strokeweight', value);
  2111. },
  2112. titleSetter: function (value, key) {
  2113. this.setAttr(key, value);
  2114. },
  2115. visibilitySetter: function (value, key, element) {
  2116. // Handle inherited visibility
  2117. if (value === 'inherit') {
  2118. value = 'visible';
  2119. }
  2120. // Let the shadow follow the main element
  2121. if (this.shadows) {
  2122. this.shadows.forEach(function (shadow) {
  2123. shadow.style[key] = value;
  2124. });
  2125. }
  2126. // Instead of toggling the visibility CSS property, move the div out
  2127. // of the viewport. This works around #61 and #586
  2128. if (element.nodeName === 'DIV') {
  2129. value = value === 'hidden' ? '-999em' : 0;
  2130. // In order to redraw, IE7 needs the div to be visible when
  2131. // tucked away outside the viewport. So the visibility is
  2132. // actually opposite of the expected value. This applies to the
  2133. // tooltip only.
  2134. if (!this.docMode8) {
  2135. element.style[key] = value ? 'visible' : 'hidden';
  2136. }
  2137. key = 'top';
  2138. }
  2139. element.style[key] = value;
  2140. },
  2141. xSetter: function (value, key, element) {
  2142. this[key] = value; // used in getter
  2143. if (key === 'x') {
  2144. key = 'left';
  2145. }
  2146. else if (key === 'y') {
  2147. key = 'top';
  2148. }
  2149. // clipping rectangle special
  2150. if (this.updateClipping) {
  2151. // the key is now 'left' or 'top' for 'x' and 'y'
  2152. this[key] = value;
  2153. this.updateClipping();
  2154. }
  2155. else {
  2156. // normal
  2157. element.style[key] = value;
  2158. }
  2159. },
  2160. zIndexSetter: function (value, key, element) {
  2161. element.style[key] = value;
  2162. },
  2163. fillGetter: function () {
  2164. return this.getAttr('fillcolor') || '';
  2165. },
  2166. strokeGetter: function () {
  2167. return this.getAttr('strokecolor') || '';
  2168. },
  2169. // #7850
  2170. classGetter: function () {
  2171. return this.getAttr('className') || '';
  2172. }
  2173. };
  2174. VMLElement['stroke-opacitySetter'] =
  2175. VMLElement['fill-opacitySetter'];
  2176. H.VMLElement = VMLElement = extendClass(SVGElement, VMLElement);
  2177. // Some shared setters
  2178. VMLElement.prototype.ySetter =
  2179. VMLElement.prototype.widthSetter =
  2180. VMLElement.prototype.heightSetter =
  2181. VMLElement.prototype.xSetter;
  2182. /**
  2183. * The VML renderer
  2184. *
  2185. * @private
  2186. * @class
  2187. * @name Highcharts.VMLRenderer
  2188. *
  2189. * @augments Highcharts.SVGRenderer
  2190. */
  2191. var VMLRendererExtension = {
  2192. Element: VMLElement,
  2193. isIE8: win.navigator.userAgent.indexOf('MSIE 8.0') > -1,
  2194. /**
  2195. * Initialize the VMLRenderer.
  2196. *
  2197. * @function Highcharts.VMLRenderer#init
  2198. * @param {Highcharts.HTMLDOMElement} container
  2199. * @param {number} width
  2200. * @param {number} height
  2201. * @return {void}
  2202. */
  2203. init: function (container,
  2204. width,
  2205. height) {
  2206. var renderer = this,
  2207. boxWrapper,
  2208. box,
  2209. css;
  2210. // Extended SVGRenderer member
  2211. this.crispPolyLine = SVGRenderer.prototype.crispPolyLine;
  2212. renderer.alignedObjects = [];
  2213. boxWrapper = renderer.createElement('div')
  2214. .css({ position: 'relative' });
  2215. box = boxWrapper.element;
  2216. container.appendChild(boxWrapper.element);
  2217. // generate the containing box
  2218. renderer.isVML = true;
  2219. renderer.box = box;
  2220. renderer.boxWrapper = boxWrapper;
  2221. renderer.gradients = {};
  2222. renderer.cache = {}; // Cache for numerical bounding boxes
  2223. renderer.cacheKeys = [];
  2224. renderer.imgCount = 0;
  2225. renderer.setSize(width, height, false);
  2226. // The only way to make IE6 and IE7 print is to use a global
  2227. // namespace. However, with IE8 the only way to make the dynamic
  2228. // shapes visible in screen and print mode seems to be to add the
  2229. // xmlns attribute and the behaviour style inline.
  2230. if (!doc.namespaces.hcv) {
  2231. doc.namespaces.add('hcv', 'urn:schemas-microsoft-com:vml');
  2232. // Setup default CSS (#2153, #2368, #2384)
  2233. css = 'hcv\\:fill, hcv\\:path, hcv\\:shape, hcv\\:stroke' +
  2234. '{ behavior:url(#default#VML); display: inline-block; } ';
  2235. try {
  2236. doc.createStyleSheet().cssText = css;
  2237. }
  2238. catch (e) {
  2239. doc.styleSheets[0].cssText += css;
  2240. }
  2241. }
  2242. },
  2243. /**
  2244. * Detect whether the renderer is hidden. This happens when one of the
  2245. * parent elements has display: none
  2246. *
  2247. * @function Highcharts.VMLRenderer#isHidden
  2248. */
  2249. isHidden: function () {
  2250. return !this.box.offsetWidth;
  2251. },
  2252. /**
  2253. * Define a clipping rectangle. In VML it is accomplished by storing the
  2254. * values for setting the CSS style to all associated members.
  2255. *
  2256. * @function Highcharts.VMLRenderer#clipRect
  2257. * @param {number|Highcharts.SizeObject} x
  2258. * @param {number} y
  2259. * @param {number} width
  2260. * @param {number} height
  2261. * @return {Highcharts.VMLElement}
  2262. */
  2263. clipRect: function (x, y, width, height) {
  2264. // create a dummy element
  2265. var clipRect = this.createElement(),
  2266. isObj = isObject(x);
  2267. // mimic a rectangle with its style object for automatic updating in
  2268. // attr
  2269. return extend(clipRect, {
  2270. members: [],
  2271. count: 0,
  2272. left: (isObj ? x.x : x) + 1,
  2273. top: (isObj ? x.y : y) + 1,
  2274. width: (isObj ? x.width : width) - 1,
  2275. height: (isObj ? x.height : height) - 1,
  2276. getCSS: function (wrapper) {
  2277. 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 = {
  2278. clip: 'rect(' +
  2279. Math.round(inverted ? left : top) + 'px,' +
  2280. Math.round(inverted ? bottom : right) + 'px,' +
  2281. Math.round(inverted ? right : bottom) + 'px,' +
  2282. Math.round(inverted ? top : left) + 'px)'
  2283. };
  2284. // issue 74 workaround
  2285. if (!inverted && wrapper.docMode8 && nodeName === 'DIV') {
  2286. extend(ret, {
  2287. width: right + 'px',
  2288. height: bottom + 'px'
  2289. });
  2290. }
  2291. return ret;
  2292. },
  2293. // used in attr and animation to update the clipping of all
  2294. // members
  2295. updateClipping: function () {
  2296. clipRect.members.forEach(function (member) {
  2297. // Member.element is falsy on deleted series, like in
  2298. // stock/members/series-remove demo. Should be removed
  2299. // from members, but this will do.
  2300. if (member.element) {
  2301. member.css(clipRect.getCSS(member));
  2302. }
  2303. });
  2304. }
  2305. });
  2306. },
  2307. /**
  2308. * Take a color and return it if it's a string, make it a gradient if
  2309. * it's a gradient configuration object, and apply opacity.
  2310. *
  2311. * @function Highcharts.VMLRenderer#color<T>
  2312. *
  2313. * @param {T} color
  2314. * The color or config object
  2315. *
  2316. * @return {T}
  2317. */
  2318. color: function (colorOption, elem, prop, wrapper) {
  2319. var renderer = this,
  2320. colorObject,
  2321. regexRgba = /^rgba/,
  2322. markup,
  2323. fillType,
  2324. ret = 'none';
  2325. // Check for linear or radial gradient
  2326. if (colorOption &&
  2327. colorOption.linearGradient) {
  2328. fillType = 'gradient';
  2329. }
  2330. else if (colorOption &&
  2331. colorOption.radialGradient) {
  2332. fillType = 'pattern';
  2333. }
  2334. if (fillType) {
  2335. var stopColor_1, stopOpacity_1, gradient = (colorOption.linearGradient ||
  2336. colorOption.radialGradient), x1 = void 0, y1 = void 0, x2 = void 0, y2 = void 0, opacity1_1, opacity2_1, color1_1, color2_1, fillAttr_1 = '', stops = colorOption.stops, firstStop = void 0, lastStop = void 0, colors_1 = [], addFillNode_1 = function () {
  2337. // Add the fill subnode. When colors attribute is used,
  2338. // the meanings of opacity and o:opacity2 are reversed.
  2339. markup = ['<fill colors="' + colors_1.join(',') +
  2340. '" opacity="', opacity2_1, '" o:opacity2="',
  2341. opacity1_1, '" type="', fillType, '" ', fillAttr_1,
  2342. 'focus="100%" method="any" />'];
  2343. createElement(renderer.prepVML(markup), null, null, elem);
  2344. };
  2345. // Extend from 0 to 1
  2346. firstStop = stops[0];
  2347. lastStop = stops[stops.length - 1];
  2348. if (firstStop[0] > 0) {
  2349. stops.unshift([
  2350. 0,
  2351. firstStop[1]
  2352. ]);
  2353. }
  2354. if (lastStop[0] < 1) {
  2355. stops.push([
  2356. 1,
  2357. lastStop[1]
  2358. ]);
  2359. }
  2360. // Compute the stops
  2361. stops.forEach(function (stop, i) {
  2362. if (regexRgba.test(stop[1])) {
  2363. colorObject = color(stop[1]);
  2364. stopColor_1 = colorObject.get('rgb');
  2365. stopOpacity_1 = colorObject.get('a');
  2366. }
  2367. else {
  2368. stopColor_1 = stop[1];
  2369. stopOpacity_1 = 1;
  2370. }
  2371. // Build the color attribute
  2372. colors_1.push((stop[0] * 100) + '% ' + stopColor_1);
  2373. // Only start and end opacities are allowed, so we use the
  2374. // first and the last
  2375. if (!i) {
  2376. opacity1_1 = stopOpacity_1;
  2377. color2_1 = stopColor_1;
  2378. }
  2379. else {
  2380. opacity2_1 = stopOpacity_1;
  2381. color1_1 = stopColor_1;
  2382. }
  2383. });
  2384. // Apply the gradient to fills only.
  2385. if (prop === 'fill') {
  2386. // Handle linear gradient angle
  2387. if (fillType === 'gradient') {
  2388. x1 = gradient.x1 || gradient[0] || 0;
  2389. y1 = gradient.y1 || gradient[1] || 0;
  2390. x2 = gradient.x2 || gradient[2] || 0;
  2391. y2 = gradient.y2 || gradient[3] || 0;
  2392. fillAttr_1 = 'angle="' + (90 - Math.atan((y2 - y1) / // y vector
  2393. (x2 - x1) // x vector
  2394. ) * 180 / Math.PI) + '"';
  2395. addFillNode_1();
  2396. // Radial (circular) gradient
  2397. }
  2398. else {
  2399. var r = gradient.r,
  2400. sizex_1 = r * 2,
  2401. sizey_1 = r * 2,
  2402. cx_1 = gradient.cx,
  2403. cy_1 = gradient.cy,
  2404. radialReference_1 = elem.radialReference,
  2405. bBox_1,
  2406. applyRadialGradient = function () {
  2407. if (radialReference_1) {
  2408. bBox_1 = wrapper.getBBox();
  2409. cx_1 += (radialReference_1[0] - bBox_1.x) /
  2410. bBox_1.width - 0.5;
  2411. cy_1 += (radialReference_1[1] - bBox_1.y) /
  2412. bBox_1.height - 0.5;
  2413. sizex_1 *= radialReference_1[2] / bBox_1.width;
  2414. sizey_1 *= radialReference_1[2] / bBox_1.height;
  2415. }
  2416. fillAttr_1 =
  2417. 'src="' + getOptions().global.VMLRadialGradientURL +
  2418. '" ' +
  2419. 'size="' + sizex_1 + ',' + sizey_1 + '" ' +
  2420. 'origin="0.5,0.5" ' +
  2421. 'position="' + cx_1 + ',' + cy_1 + '" ' +
  2422. 'color2="' + color2_1 + '" ';
  2423. addFillNode_1();
  2424. };
  2425. // Apply radial gradient
  2426. if (wrapper.added) {
  2427. applyRadialGradient();
  2428. }
  2429. else {
  2430. // We need to know the bounding box to get the size
  2431. // and position right
  2432. wrapper.onAdd = applyRadialGradient;
  2433. }
  2434. // The fill element's color attribute is broken in IE8
  2435. // standards mode, so we need to set the parent shape's
  2436. // fillcolor attribute instead.
  2437. ret = color1_1;
  2438. }
  2439. // Gradients are not supported for VML stroke, return the first
  2440. // color. #722.
  2441. }
  2442. else {
  2443. ret = stopColor_1;
  2444. }
  2445. // If the color is an rgba color, split it and add a fill node
  2446. // to hold the opacity component
  2447. }
  2448. else if (regexRgba.test(colorOption) && elem.tagName !== 'IMG') {
  2449. colorObject = color(colorOption);
  2450. wrapper[prop + '-opacitySetter'](colorObject.get('a'), prop, elem);
  2451. ret = colorObject.get('rgb');
  2452. }
  2453. else {
  2454. // 'stroke' or 'fill' node
  2455. var propNodes = elem.getElementsByTagName(prop);
  2456. if (propNodes.length) {
  2457. propNodes[0].opacity = 1;
  2458. propNodes[0].type = 'solid';
  2459. }
  2460. ret = colorOption;
  2461. }
  2462. return ret;
  2463. },
  2464. /**
  2465. * Take a VML string and prepare it for either IE8 or IE6/IE7.
  2466. *
  2467. * @function Highcharts.VMLRenderer#prepVML
  2468. *
  2469. * @param {Array<(number|string)>} markup
  2470. * A string array of the VML markup to prepare
  2471. *
  2472. * @return {string}
  2473. */
  2474. prepVML: function (markup) {
  2475. var vmlStyle = 'display:inline-block;behavior:url(#default#VML);',
  2476. isIE8 = this.isIE8;
  2477. markup = markup.join('');
  2478. if (isIE8) { // add xmlns and style inline
  2479. markup = markup.replace('/>', ' xmlns="urn:schemas-microsoft-com:vml" />');
  2480. if (markup.indexOf('style="') === -1) {
  2481. markup = markup.replace('/>', ' style="' + vmlStyle + '" />');
  2482. }
  2483. else {
  2484. markup = markup.replace('style="', 'style="' + vmlStyle);
  2485. }
  2486. }
  2487. else { // add namespace
  2488. markup = markup.replace('<', '<hcv:');
  2489. }
  2490. return markup;
  2491. },
  2492. /**
  2493. * Create rotated and aligned text
  2494. *
  2495. * @function Highcharts.VMLRenderer#text
  2496. *
  2497. * @param {string} str
  2498. *
  2499. * @param {number} x
  2500. *
  2501. * @param {number} y
  2502. */
  2503. text: SVGRenderer.prototype.html,
  2504. /**
  2505. * Create and return a path element
  2506. *
  2507. * @function Highcharts.VMLRenderer#path
  2508. *
  2509. * @param {Highcharts.VMLAttributes|Highcharts.VMLPathArray} [path]
  2510. */
  2511. path: function (path) {
  2512. var attr = {
  2513. // subpixel precision down to 0.1 (width and height = 1px)
  2514. coordsize: '10 10'
  2515. };
  2516. if (isArray(path)) {
  2517. attr.d = path;
  2518. }
  2519. else if (isObject(path)) { // attributes
  2520. extend(attr, path);
  2521. }
  2522. // create the shape
  2523. return this.createElement('shape').attr(attr);
  2524. },
  2525. /**
  2526. * Create and return a circle element. In VML circles are implemented as
  2527. * shapes, which is faster than v:oval
  2528. *
  2529. * @function Highcharts.VMLRenderer#circle
  2530. * @param {number|Highcharts.Dictionary<number>} x
  2531. * @param {number} [y]
  2532. * @param {number} [r]
  2533. * @return {Highcharts.VMLElement}
  2534. */
  2535. circle: function (x, y, r) {
  2536. var circle = this.symbol('circle');
  2537. if (isObject(x)) {
  2538. r = x.r;
  2539. y = x.y;
  2540. x = x.x;
  2541. }
  2542. circle.isCircle = true; // Causes x and y to mean center (#1682)
  2543. circle.r = r;
  2544. return circle.attr({ x: x, y: y });
  2545. },
  2546. /**
  2547. * Create a group using an outer div and an inner v:group to allow
  2548. * rotating and flipping. A simple v:group would have problems with
  2549. * positioning child HTML elements and CSS clip.
  2550. *
  2551. * @function Highcharts.VMLRenderer#g
  2552. *
  2553. * @param {string} name
  2554. * The name of the group
  2555. *
  2556. * @return {Highcharts.VMLElement}
  2557. */
  2558. g: function (name) {
  2559. var wrapper,
  2560. attribs;
  2561. // set the class name
  2562. if (name) {
  2563. attribs = {
  2564. 'className': 'highcharts-' + name,
  2565. 'class': 'highcharts-' + name
  2566. };
  2567. }
  2568. // the div to hold HTML and clipping
  2569. wrapper = this.createElement('div').attr(attribs);
  2570. return wrapper;
  2571. },
  2572. /**
  2573. * VML override to create a regular HTML image.
  2574. *
  2575. * @function Highcharts.VMLRenderer#image
  2576. *
  2577. * @param {string} src
  2578. *
  2579. * @param {number} x
  2580. *
  2581. * @param {number} y
  2582. *
  2583. * @param {number} width
  2584. *
  2585. * @param {number} height
  2586. * @return {Highcharts.VMLElement}
  2587. */
  2588. image: function (src, x, y, width, height) {
  2589. var obj = this.createElement('img').attr({ src: src });
  2590. if (arguments.length > 1) {
  2591. obj.attr({
  2592. x: x,
  2593. y: y,
  2594. width: width,
  2595. height: height
  2596. });
  2597. }
  2598. return obj;
  2599. },
  2600. /**
  2601. * For rectangles, VML uses a shape for rect to overcome bugs and
  2602. * rotation problems
  2603. *
  2604. * @function Highcharts.VMLRenderer#createElement
  2605. * @param {string} nodeName
  2606. * @return {Highcharts.VMLElement}
  2607. */
  2608. createElement: function (nodeName) {
  2609. return nodeName === 'rect' ?
  2610. this.symbol(nodeName) :
  2611. SVGRenderer.prototype.createElement.call(this, nodeName);
  2612. },
  2613. /**
  2614. * In the VML renderer, each child of an inverted div (group) is
  2615. * inverted
  2616. *
  2617. * @function Highcharts.VMLRenderer#invertChild
  2618. *
  2619. * @param {Highcharts.HTMLDOMElement} element
  2620. *
  2621. * @param {Highcharts.HTMLDOMElement} parentNode
  2622. */
  2623. invertChild: function (element, parentNode) {
  2624. var ren = this,
  2625. parentStyle = parentNode.style,
  2626. imgStyle = element.tagName === 'IMG' && element.style; // #1111
  2627. css(element, {
  2628. flip: 'x',
  2629. left: (pInt(parentStyle.width) -
  2630. (imgStyle ? pInt(imgStyle.top) : 1)) + 'px',
  2631. top: (pInt(parentStyle.height) -
  2632. (imgStyle ? pInt(imgStyle.left) : 1)) + 'px',
  2633. rotation: -90
  2634. });
  2635. // Recursively invert child elements, needed for nested composite
  2636. // shapes like box plots and error bars. #1680, #1806.
  2637. [].forEach.call(element.childNodes, function (child) {
  2638. ren.invertChild(child, element);
  2639. });
  2640. },
  2641. /**
  2642. * Symbol definitions that override the parent SVG renderer's symbols
  2643. *
  2644. * @name Highcharts.VMLRenderer#symbols
  2645. * @type {Highcharts.Dictionary<Function>}
  2646. */
  2647. symbols: {
  2648. // VML specific arc function
  2649. arc: function (x, y, w, h, options) {
  2650. var start = options.start,
  2651. end = options.end,
  2652. radius = options.r || w || h,
  2653. innerRadius = options.innerR,
  2654. cosStart = Math.cos(start),
  2655. sinStart = Math.sin(start),
  2656. cosEnd = Math.cos(end),
  2657. sinEnd = Math.sin(end),
  2658. ret;
  2659. if (end - start === 0) { // no angle, don't show it.
  2660. return ['x'];
  2661. }
  2662. ret = [
  2663. 'wa',
  2664. x - radius,
  2665. y - radius,
  2666. x + radius,
  2667. y + radius,
  2668. x + radius * cosStart,
  2669. y + radius * sinStart,
  2670. x + radius * cosEnd,
  2671. y + radius * sinEnd // end y
  2672. ];
  2673. if (options.open && !innerRadius) {
  2674. ret.push('e', 'M', x, // - innerRadius,
  2675. y // - innerRadius
  2676. );
  2677. }
  2678. ret.push('at', // anti clockwise arc to
  2679. x - innerRadius, // left
  2680. y - innerRadius, // top
  2681. x + innerRadius, // right
  2682. y + innerRadius, // bottom
  2683. x + innerRadius * cosEnd, // start x
  2684. y + innerRadius * sinEnd, // start y
  2685. x + innerRadius * cosStart, // end x
  2686. y + innerRadius * sinStart, // end y
  2687. 'x', // finish path
  2688. 'e' // close
  2689. );
  2690. ret.isArc = true;
  2691. return ret;
  2692. },
  2693. // Add circle symbol path. This performs significantly faster than
  2694. // v:oval.
  2695. circle: function (x, y, w, h, wrapper) {
  2696. if (wrapper && defined(wrapper.r)) {
  2697. w = h = 2 * wrapper.r;
  2698. }
  2699. // Center correction, #1682
  2700. if (wrapper && wrapper.isCircle) {
  2701. x -= w / 2;
  2702. y -= h / 2;
  2703. }
  2704. // Return the path
  2705. return [
  2706. 'wa',
  2707. x,
  2708. y,
  2709. x + w,
  2710. y + h,
  2711. x + w,
  2712. y + h / 2,
  2713. x + w,
  2714. y + h / 2,
  2715. 'e' // close
  2716. ];
  2717. },
  2718. /**
  2719. * Add rectangle symbol path which eases rotation and omits arcsize
  2720. * problems compared to the built-in VML roundrect shape. When
  2721. * borders are not rounded, use the simpler square path, else use
  2722. * the callout path without the arrow.
  2723. */
  2724. rect: function (x, y, w, h, options) {
  2725. return SVGRenderer.prototype.symbols[!defined(options) || !options.r ? 'square' : 'callout'].call(0, x, y, w, h, options);
  2726. }
  2727. }
  2728. };
  2729. H.VMLRenderer = VMLRenderer = function () {
  2730. this.init.apply(this, arguments);
  2731. };
  2732. extend(VMLRenderer.prototype, SVGRenderer.prototype);
  2733. extend(VMLRenderer.prototype, VMLRendererExtension);
  2734. // general renderer
  2735. H.Renderer = VMLRenderer;
  2736. // 3D additions
  2737. VMLRenderer3D.compose(VMLRenderer, SVGRenderer);
  2738. }
  2739. SVGRenderer.prototype.getSpanWidth = function (wrapper, tspan) {
  2740. var renderer = this,
  2741. bBox = wrapper.getBBox(true),
  2742. actualWidth = bBox.width;
  2743. // Old IE cannot measure the actualWidth for SVG elements (#2314)
  2744. if (!svg && renderer.forExport) {
  2745. actualWidth = renderer.measureSpanWidth(tspan.firstChild.data, wrapper.styles);
  2746. }
  2747. return actualWidth;
  2748. };
  2749. // This method is used with exporting in old IE, when emulating SVG (see #2314)
  2750. SVGRenderer.prototype.measureSpanWidth = function (text, styles) {
  2751. var measuringSpan = doc.createElement('span'),
  2752. offsetWidth,
  2753. textNode = doc.createTextNode(text);
  2754. measuringSpan.appendChild(textNode);
  2755. css(measuringSpan, styles);
  2756. this.box.appendChild(measuringSpan);
  2757. offsetWidth = measuringSpan.offsetWidth;
  2758. discardElement(measuringSpan); // #2463
  2759. return offsetWidth;
  2760. };
  2761. });
  2762. _registerModule(_modules, 'masters/modules/oldie.src.js', [], function () {
  2763. });
  2764. }));