oldie.src.js 119 KB

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