highcharts-3d.src.js 200 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528
  1. /**
  2. * @license Highcharts JS v8.1.2 (2020-06-16)
  3. *
  4. * 3D features for Highcharts JS
  5. *
  6. * License: www.highcharts.com/license
  7. */
  8. 'use strict';
  9. (function (factory) {
  10. if (typeof module === 'object' && module.exports) {
  11. factory['default'] = factory;
  12. module.exports = factory;
  13. } else if (typeof define === 'function' && define.amd) {
  14. define('highcharts/highcharts-3d', ['highcharts'], function (Highcharts) {
  15. factory(Highcharts);
  16. factory.Highcharts = Highcharts;
  17. return factory;
  18. });
  19. } else {
  20. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  21. }
  22. }(function (Highcharts) {
  23. var _modules = Highcharts ? Highcharts._modules : {};
  24. function _registerModule(obj, path, args, fn) {
  25. if (!obj.hasOwnProperty(path)) {
  26. obj[path] = fn.apply(null, args);
  27. }
  28. }
  29. _registerModule(_modules, 'parts-3d/Math.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  30. /* *
  31. *
  32. * (c) 2010-2020 Torstein Honsi
  33. *
  34. * License: www.highcharts.com/license
  35. *
  36. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  37. *
  38. * */
  39. var pick = U.pick;
  40. // Mathematical Functionility
  41. var deg2rad = H.deg2rad;
  42. /* eslint-disable max-len */
  43. /**
  44. * Apply 3-D rotation
  45. * Euler Angles (XYZ):
  46. * cosA = cos(Alfa|Roll)
  47. * cosB = cos(Beta|Pitch)
  48. * cosG = cos(Gamma|Yaw)
  49. *
  50. * Composite rotation:
  51. * | cosB * cosG | cosB * sinG | -sinB |
  52. * | sinA * sinB * cosG - cosA * sinG | sinA * sinB * sinG + cosA * cosG | sinA * cosB |
  53. * | cosA * sinB * cosG + sinA * sinG | cosA * sinB * sinG - sinA * cosG | cosA * cosB |
  54. *
  55. * Now, Gamma/Yaw is not used (angle=0), so we assume cosG = 1 and sinG = 0, so
  56. * we get:
  57. * | cosB | 0 | - sinB |
  58. * | sinA * sinB | cosA | sinA * cosB |
  59. * | cosA * sinB | - sinA | cosA * cosB |
  60. *
  61. * But in browsers, y is reversed, so we get sinA => -sinA. The general result
  62. * is:
  63. * | cosB | 0 | - sinB | | x | | px |
  64. * | - sinA * sinB | cosA | - sinA * cosB | x | y | = | py |
  65. * | cosA * sinB | sinA | cosA * cosB | | z | | pz |
  66. *
  67. * @private
  68. * @function rotate3D
  69. */
  70. /* eslint-enable max-len */
  71. /**
  72. * @private
  73. * @param {number} x
  74. * X coordinate
  75. * @param {number} y
  76. * Y coordinate
  77. * @param {number} z
  78. * Z coordinate
  79. * @param {Highcharts.Rotation3dObject} angles
  80. * Rotation angles
  81. * @return {Highcharts.Rotation3dObject}
  82. * Rotated position
  83. */
  84. function rotate3D(x, y, z, angles) {
  85. return {
  86. x: angles.cosB * x - angles.sinB * z,
  87. y: -angles.sinA * angles.sinB * x + angles.cosA * y -
  88. angles.cosB * angles.sinA * z,
  89. z: angles.cosA * angles.sinB * x + angles.sinA * y +
  90. angles.cosA * angles.cosB * z
  91. };
  92. }
  93. /**
  94. * Perspective3D function is available in global Highcharts scope because is
  95. * needed also outside of perspective() function (#8042).
  96. * @private
  97. * @function Highcharts.perspective3D
  98. *
  99. * @param {Highcharts.Position3dObject} coordinate
  100. * 3D position
  101. *
  102. * @param {Highcharts.Position3dObject} origin
  103. * 3D root position
  104. *
  105. * @param {number} distance
  106. * Perspective distance
  107. *
  108. * @return {Highcharts.PositionObject}
  109. * Perspective 3D Position
  110. *
  111. * @requires highcharts-3d
  112. */
  113. H.perspective3D = function (coordinate, origin, distance) {
  114. var projection = ((distance > 0) && (distance < Number.POSITIVE_INFINITY)) ?
  115. distance / (coordinate.z + origin.z + distance) :
  116. 1;
  117. return {
  118. x: coordinate.x * projection,
  119. y: coordinate.y * projection
  120. };
  121. };
  122. /**
  123. * Transforms a given array of points according to the angles in chart.options.
  124. *
  125. * @private
  126. * @function Highcharts.perspective
  127. *
  128. * @param {Array<Highcharts.Position3dObject>} points
  129. * The array of points
  130. *
  131. * @param {Highcharts.Chart} chart
  132. * The chart
  133. *
  134. * @param {boolean} [insidePlotArea]
  135. * Whether to verifiy that the points are inside the plotArea
  136. *
  137. * @param {boolean} [useInvertedPersp]
  138. * Whether to use inverted perspective in calculations
  139. *
  140. * @return {Array<Highcharts.Position3dObject>}
  141. * An array of transformed points
  142. *
  143. * @requires highcharts-3d
  144. */
  145. H.perspective = function (points, chart, insidePlotArea, useInvertedPersp) {
  146. var options3d = chart.options.chart.options3d,
  147. /* The useInvertedPersp argument is used for
  148. * inverted charts with already inverted elements,
  149. * such as dataLabels or tooltip positions.
  150. */
  151. inverted = pick(useInvertedPersp, insidePlotArea ? chart.inverted : false), origin = {
  152. x: chart.plotWidth / 2,
  153. y: chart.plotHeight / 2,
  154. z: options3d.depth / 2,
  155. vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
  156. }, scale = chart.scale3d || 1, beta = deg2rad * options3d.beta * (inverted ? -1 : 1), alpha = deg2rad * options3d.alpha * (inverted ? -1 : 1), angles = {
  157. cosA: Math.cos(alpha),
  158. cosB: Math.cos(-beta),
  159. sinA: Math.sin(alpha),
  160. sinB: Math.sin(-beta)
  161. };
  162. if (!insidePlotArea) {
  163. origin.x += chart.plotLeft;
  164. origin.y += chart.plotTop;
  165. }
  166. // Transform each point
  167. return points.map(function (point) {
  168. var rotated = rotate3D((inverted ? point.y : point.x) - origin.x, (inverted ? point.x : point.y) - origin.y, (point.z || 0) - origin.z, angles),
  169. // Apply perspective
  170. coordinate = H.perspective3D(rotated, origin, origin.vd);
  171. // Apply translation
  172. coordinate.x = coordinate.x * scale + origin.x;
  173. coordinate.y = coordinate.y * scale + origin.y;
  174. coordinate.z = rotated.z * scale + origin.z;
  175. return {
  176. x: (inverted ? coordinate.y : coordinate.x),
  177. y: (inverted ? coordinate.x : coordinate.y),
  178. z: coordinate.z
  179. };
  180. });
  181. };
  182. /**
  183. * Calculate a distance from camera to points - made for calculating zIndex of
  184. * scatter points.
  185. *
  186. * @private
  187. * @function Highcharts.pointCameraDistance
  188. *
  189. * @param {Highcharts.Dictionary<number>} coordinates
  190. * Coordinates of the specific point
  191. *
  192. * @param {Highcharts.Chart} chart
  193. * Related chart
  194. *
  195. * @return {number}
  196. * Distance from camera to point
  197. *
  198. * @requires highcharts-3d
  199. */
  200. H.pointCameraDistance = function (coordinates, chart) {
  201. var options3d = chart.options.chart.options3d, cameraPosition = {
  202. x: chart.plotWidth / 2,
  203. y: chart.plotHeight / 2,
  204. z: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0) +
  205. options3d.depth
  206. },
  207. // Added support for objects with plotX or x coordinates.
  208. distance = Math.sqrt(Math.pow(cameraPosition.x - pick(coordinates.plotX, coordinates.x), 2) +
  209. Math.pow(cameraPosition.y - pick(coordinates.plotY, coordinates.y), 2) +
  210. Math.pow(cameraPosition.z - pick(coordinates.plotZ, coordinates.z), 2));
  211. return distance;
  212. };
  213. /**
  214. * Calculate area of a 2D polygon using Shoelace algorithm
  215. * https://en.wikipedia.org/wiki/Shoelace_formula
  216. *
  217. * @private
  218. * @function Highcharts.shapeArea
  219. *
  220. * @param {Array<Highcharts.PositionObject>} vertexes
  221. * 2D Polygon
  222. *
  223. * @return {number}
  224. * Calculated area
  225. *
  226. * @requires highcharts-3d
  227. */
  228. H.shapeArea = function (vertexes) {
  229. var area = 0, i, j;
  230. for (i = 0; i < vertexes.length; i++) {
  231. j = (i + 1) % vertexes.length;
  232. area += vertexes[i].x * vertexes[j].y - vertexes[j].x * vertexes[i].y;
  233. }
  234. return area / 2;
  235. };
  236. /**
  237. * Calculate area of a 3D polygon after perspective projection
  238. *
  239. * @private
  240. * @function Highcharts.shapeArea3d
  241. *
  242. * @param {Array<Highcharts.Position3dObject>} vertexes
  243. * 3D Polygon
  244. *
  245. * @param {Highcharts.Chart} chart
  246. * Related chart
  247. *
  248. * @param {boolean} [insidePlotArea]
  249. * Whether to verifiy that the points are inside the plotArea
  250. *
  251. * @return {number}
  252. * Calculated area
  253. *
  254. * @requires highcharts-3d
  255. */
  256. H.shapeArea3d = function (vertexes, chart, insidePlotArea) {
  257. return H.shapeArea(H.perspective(vertexes, chart, insidePlotArea));
  258. };
  259. });
  260. _registerModule(_modules, 'parts-3d/SVGRenderer.js', [_modules['parts/Color.js'], _modules['parts/Globals.js'], _modules['parts/SVGElement.js'], _modules['parts/SVGRenderer.js'], _modules['parts/Utilities.js']], function (Color, H, SVGElement, SVGRenderer, U) {
  261. /* *
  262. *
  263. * (c) 2010-2020 Torstein Honsi
  264. *
  265. * Extensions to the SVGRenderer class to enable 3D shapes
  266. *
  267. * License: www.highcharts.com/license
  268. *
  269. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  270. *
  271. * */
  272. var color = Color.parse;
  273. var animObject = U.animObject, defined = U.defined, extend = U.extend, merge = U.merge, objectEach = U.objectEach, pick = U.pick;
  274. var cos = Math.cos, PI = Math.PI, sin = Math.sin;
  275. var charts = H.charts, deg2rad = H.deg2rad, perspective = H.perspective,
  276. // internal:
  277. dFactor, element3dMethods, cuboidMethods;
  278. /*
  279. EXTENSION TO THE SVG-RENDERER TO ENABLE 3D SHAPES
  280. */
  281. // HELPER METHODS
  282. dFactor = (4 * (Math.sqrt(2) - 1) / 3) / (PI / 2);
  283. /* eslint-disable no-invalid-this, valid-jsdoc */
  284. /**
  285. * Method to construct a curved path. Can 'wrap' around more then 180 degrees.
  286. * @private
  287. */
  288. function curveTo(cx, cy, rx, ry, start, end, dx, dy) {
  289. var result = [], arcAngle = end - start;
  290. if ((end > start) && (end - start > Math.PI / 2 + 0.0001)) {
  291. result = result.concat(curveTo(cx, cy, rx, ry, start, start + (Math.PI / 2), dx, dy));
  292. result = result.concat(curveTo(cx, cy, rx, ry, start + (Math.PI / 2), end, dx, dy));
  293. return result;
  294. }
  295. if ((end < start) && (start - end > Math.PI / 2 + 0.0001)) {
  296. result = result.concat(curveTo(cx, cy, rx, ry, start, start - (Math.PI / 2), dx, dy));
  297. result = result.concat(curveTo(cx, cy, rx, ry, start - (Math.PI / 2), end, dx, dy));
  298. return result;
  299. }
  300. return [[
  301. 'C',
  302. cx + (rx * Math.cos(start)) -
  303. ((rx * dFactor * arcAngle) * Math.sin(start)) + dx,
  304. cy + (ry * Math.sin(start)) +
  305. ((ry * dFactor * arcAngle) * Math.cos(start)) + dy,
  306. cx + (rx * Math.cos(end)) +
  307. ((rx * dFactor * arcAngle) * Math.sin(end)) + dx,
  308. cy + (ry * Math.sin(end)) -
  309. ((ry * dFactor * arcAngle) * Math.cos(end)) + dy,
  310. cx + (rx * Math.cos(end)) + dx,
  311. cy + (ry * Math.sin(end)) + dy
  312. ]];
  313. }
  314. SVGRenderer.prototype.toLinePath = function (points, closed) {
  315. var result = [];
  316. // Put "L x y" for each point
  317. points.forEach(function (point) {
  318. result.push(['L', point.x, point.y]);
  319. });
  320. if (points.length) {
  321. // Set the first element to M
  322. result[0][0] = 'M';
  323. // If it is a closed line, add Z
  324. if (closed) {
  325. result.push(['Z']);
  326. }
  327. }
  328. return result;
  329. };
  330. SVGRenderer.prototype.toLineSegments = function (points) {
  331. var result = [], m = true;
  332. points.forEach(function (point) {
  333. result.push(m ? ['M', point.x, point.y] : ['L', point.x, point.y]);
  334. m = !m;
  335. });
  336. return result;
  337. };
  338. // A 3-D Face is defined by it's 3D vertexes, and is only visible if it's
  339. // vertexes are counter-clockwise (Back-face culling). It is used as a
  340. // polyhedron Element
  341. SVGRenderer.prototype.face3d = function (args) {
  342. var renderer = this, ret = this.createElement('path');
  343. ret.vertexes = [];
  344. ret.insidePlotArea = false;
  345. ret.enabled = true;
  346. ret.attr = function (hash) {
  347. if (typeof hash === 'object' &&
  348. (defined(hash.enabled) ||
  349. defined(hash.vertexes) ||
  350. defined(hash.insidePlotArea))) {
  351. this.enabled = pick(hash.enabled, this.enabled);
  352. this.vertexes = pick(hash.vertexes, this.vertexes);
  353. this.insidePlotArea = pick(hash.insidePlotArea, this.insidePlotArea);
  354. delete hash.enabled;
  355. delete hash.vertexes;
  356. delete hash.insidePlotArea;
  357. var chart = charts[renderer.chartIndex], vertexes2d = perspective(this.vertexes, chart, this.insidePlotArea), path = renderer.toLinePath(vertexes2d, true), area = H.shapeArea(vertexes2d), visibility = (this.enabled && area > 0) ? 'visible' : 'hidden';
  358. hash.d = path;
  359. hash.visibility = visibility;
  360. }
  361. return SVGElement.prototype.attr.apply(this, arguments);
  362. };
  363. ret.animate = function (params) {
  364. if (typeof params === 'object' &&
  365. (defined(params.enabled) ||
  366. defined(params.vertexes) ||
  367. defined(params.insidePlotArea))) {
  368. this.enabled = pick(params.enabled, this.enabled);
  369. this.vertexes = pick(params.vertexes, this.vertexes);
  370. this.insidePlotArea = pick(params.insidePlotArea, this.insidePlotArea);
  371. delete params.enabled;
  372. delete params.vertexes;
  373. delete params.insidePlotArea;
  374. var chart = charts[renderer.chartIndex], vertexes2d = perspective(this.vertexes, chart, this.insidePlotArea), path = renderer.toLinePath(vertexes2d, true), area = H.shapeArea(vertexes2d), visibility = (this.enabled && area > 0) ? 'visible' : 'hidden';
  375. params.d = path;
  376. this.attr('visibility', visibility);
  377. }
  378. return SVGElement.prototype.animate.apply(this, arguments);
  379. };
  380. return ret.attr(args);
  381. };
  382. // A Polyhedron is a handy way of defining a group of 3-D faces. It's only
  383. // attribute is `faces`, an array of attributes of each one of it's Face3D
  384. // instances.
  385. SVGRenderer.prototype.polyhedron = function (args) {
  386. var renderer = this, result = this.g(), destroy = result.destroy;
  387. if (!this.styledMode) {
  388. result.attr({
  389. 'stroke-linejoin': 'round'
  390. });
  391. }
  392. result.faces = [];
  393. // destroy all children
  394. result.destroy = function () {
  395. for (var i = 0; i < result.faces.length; i++) {
  396. result.faces[i].destroy();
  397. }
  398. return destroy.call(this);
  399. };
  400. result.attr = function (hash, val, complete, continueAnimation) {
  401. if (typeof hash === 'object' && defined(hash.faces)) {
  402. while (result.faces.length > hash.faces.length) {
  403. result.faces.pop().destroy();
  404. }
  405. while (result.faces.length < hash.faces.length) {
  406. result.faces.push(renderer.face3d().add(result));
  407. }
  408. for (var i = 0; i < hash.faces.length; i++) {
  409. if (renderer.styledMode) {
  410. delete hash.faces[i].fill;
  411. }
  412. result.faces[i].attr(hash.faces[i], null, complete, continueAnimation);
  413. }
  414. delete hash.faces;
  415. }
  416. return SVGElement.prototype.attr.apply(this, arguments);
  417. };
  418. result.animate = function (params, duration, complete) {
  419. if (params && params.faces) {
  420. while (result.faces.length > params.faces.length) {
  421. result.faces.pop().destroy();
  422. }
  423. while (result.faces.length < params.faces.length) {
  424. result.faces.push(renderer.face3d().add(result));
  425. }
  426. for (var i = 0; i < params.faces.length; i++) {
  427. result.faces[i].animate(params.faces[i], duration, complete);
  428. }
  429. delete params.faces;
  430. }
  431. return SVGElement.prototype.animate.apply(this, arguments);
  432. };
  433. return result.attr(args);
  434. };
  435. // Base, abstract prototype member for 3D elements
  436. element3dMethods = {
  437. /**
  438. * The init is used by base - renderer.Element
  439. * @private
  440. */
  441. initArgs: function (args) {
  442. var elem3d = this, renderer = elem3d.renderer, paths = renderer[elem3d.pathType + 'Path'](args), zIndexes = paths.zIndexes;
  443. // build parts
  444. elem3d.parts.forEach(function (part) {
  445. elem3d[part] = renderer.path(paths[part]).attr({
  446. 'class': 'highcharts-3d-' + part,
  447. zIndex: zIndexes[part] || 0
  448. }).add(elem3d);
  449. });
  450. elem3d.attr({
  451. 'stroke-linejoin': 'round',
  452. zIndex: zIndexes.group
  453. });
  454. // store original destroy
  455. elem3d.originalDestroy = elem3d.destroy;
  456. elem3d.destroy = elem3d.destroyParts;
  457. // Store information if any side of element was rendered by force.
  458. elem3d.forcedSides = paths.forcedSides;
  459. },
  460. /**
  461. * Single property setter that applies options to each part
  462. * @private
  463. */
  464. singleSetterForParts: function (prop, val, values, verb, duration, complete) {
  465. var elem3d = this, newAttr = {}, optionsToApply = [null, null, (verb || 'attr'), duration, complete], hasZIndexes = values && values.zIndexes;
  466. if (!values) {
  467. newAttr[prop] = val;
  468. optionsToApply[0] = newAttr;
  469. }
  470. else {
  471. // It is needed to deal with the whole group zIndexing
  472. // in case of graph rotation
  473. if (hasZIndexes && hasZIndexes.group) {
  474. this.attr({
  475. zIndex: hasZIndexes.group
  476. });
  477. }
  478. objectEach(values, function (partVal, part) {
  479. newAttr[part] = {};
  480. newAttr[part][prop] = partVal;
  481. // include zIndexes if provided
  482. if (hasZIndexes) {
  483. newAttr[part].zIndex = values.zIndexes[part] || 0;
  484. }
  485. });
  486. optionsToApply[1] = newAttr;
  487. }
  488. return elem3d.processParts.apply(elem3d, optionsToApply);
  489. },
  490. /**
  491. * Calls function for each part. Used for attr, animate and destroy.
  492. * @private
  493. */
  494. processParts: function (props, partsProps, verb, duration, complete) {
  495. var elem3d = this;
  496. elem3d.parts.forEach(function (part) {
  497. // if different props for different parts
  498. if (partsProps) {
  499. props = pick(partsProps[part], false);
  500. }
  501. // only if something to set, but allow undefined
  502. if (props !== false) {
  503. elem3d[part][verb](props, duration, complete);
  504. }
  505. });
  506. return elem3d;
  507. },
  508. /**
  509. * Destroy all parts
  510. * @private
  511. */
  512. destroyParts: function () {
  513. this.processParts(null, null, 'destroy');
  514. return this.originalDestroy();
  515. }
  516. };
  517. // CUBOID
  518. cuboidMethods = merge(element3dMethods, {
  519. parts: ['front', 'top', 'side'],
  520. pathType: 'cuboid',
  521. attr: function (args, val, complete, continueAnimation) {
  522. // Resolve setting attributes by string name
  523. if (typeof args === 'string' && typeof val !== 'undefined') {
  524. var key = args;
  525. args = {};
  526. args[key] = val;
  527. }
  528. if (args.shapeArgs || defined(args.x)) {
  529. return this.singleSetterForParts('d', null, this.renderer[this.pathType + 'Path'](args.shapeArgs || args));
  530. }
  531. return SVGElement.prototype.attr.call(this, args, void 0, complete, continueAnimation);
  532. },
  533. animate: function (args, duration, complete) {
  534. if (defined(args.x) && defined(args.y)) {
  535. var paths = this.renderer[this.pathType + 'Path'](args), forcedSides = paths.forcedSides;
  536. this.singleSetterForParts('d', null, paths, 'animate', duration, complete);
  537. this.attr({
  538. zIndex: paths.zIndexes.group
  539. });
  540. // If sides that are forced to render changed, recalculate colors.
  541. if (forcedSides !== this.forcedSides) {
  542. this.forcedSides = forcedSides;
  543. cuboidMethods.fillSetter.call(this, this.fill);
  544. }
  545. }
  546. else {
  547. SVGElement.prototype.animate.call(this, args, duration, complete);
  548. }
  549. return this;
  550. },
  551. fillSetter: function (fill) {
  552. var elem3d = this;
  553. elem3d.forcedSides = elem3d.forcedSides || [];
  554. elem3d.singleSetterForParts('fill', null, {
  555. front: fill,
  556. // Do not change color if side was forced to render.
  557. top: color(fill).brighten(elem3d.forcedSides.indexOf('top') >= 0 ? 0 : 0.1).get(),
  558. side: color(fill).brighten(elem3d.forcedSides.indexOf('side') >= 0 ? 0 : -0.1).get()
  559. });
  560. // fill for animation getter (#6776)
  561. elem3d.color = elem3d.fill = fill;
  562. return elem3d;
  563. }
  564. });
  565. // set them up
  566. SVGRenderer.prototype.elements3d = {
  567. base: element3dMethods,
  568. cuboid: cuboidMethods
  569. };
  570. /**
  571. * return result, generalization
  572. * @private
  573. * @requires highcharts-3d
  574. */
  575. SVGRenderer.prototype.element3d = function (type, shapeArgs) {
  576. // base
  577. var ret = this.g();
  578. // extend
  579. extend(ret, this.elements3d[type]);
  580. // init
  581. ret.initArgs(shapeArgs);
  582. // return
  583. return ret;
  584. };
  585. // generelized, so now use simply
  586. SVGRenderer.prototype.cuboid = function (shapeArgs) {
  587. return this.element3d('cuboid', shapeArgs);
  588. };
  589. // Generates a cuboid path and zIndexes
  590. SVGRenderer.prototype.cuboidPath = function (shapeArgs) {
  591. var x = shapeArgs.x, y = shapeArgs.y, z = shapeArgs.z || 0,
  592. // For side calculation (right/left)
  593. // there is a need for height (and other shapeArgs arguments)
  594. // to be at least 1px
  595. h = shapeArgs.height, w = shapeArgs.width, d = shapeArgs.depth, chart = charts[this.chartIndex], front, back, top, bottom, left, right, shape, path1, path2, path3, isFront, isTop, isRight, options3d = chart.options.chart.options3d, alpha = options3d.alpha,
  596. // Priority for x axis is the biggest,
  597. // because of x direction has biggest influence on zIndex
  598. incrementX = 1000000,
  599. // y axis has the smallest priority in case of our charts
  600. // (needs to be set because of stacking)
  601. incrementY = 10, incrementZ = 100, zIndex = 0,
  602. // The 8 corners of the cube
  603. pArr = [{
  604. x: x,
  605. y: y,
  606. z: z
  607. }, {
  608. x: x + w,
  609. y: y,
  610. z: z
  611. }, {
  612. x: x + w,
  613. y: y + h,
  614. z: z
  615. }, {
  616. x: x,
  617. y: y + h,
  618. z: z
  619. }, {
  620. x: x,
  621. y: y + h,
  622. z: z + d
  623. }, {
  624. x: x + w,
  625. y: y + h,
  626. z: z + d
  627. }, {
  628. x: x + w,
  629. y: y,
  630. z: z + d
  631. }, {
  632. x: x,
  633. y: y,
  634. z: z + d
  635. }], forcedSides = [], pickShape;
  636. // apply perspective
  637. pArr = perspective(pArr, chart, shapeArgs.insidePlotArea);
  638. /**
  639. * helper method to decide which side is visible
  640. * @private
  641. */
  642. function mapSidePath(i) {
  643. // Added support for 0 value in columns, where height is 0
  644. // but the shape is rendered.
  645. // Height is used from 1st to 6th element of pArr
  646. if (h === 0 && i > 1 && i < 6) { // [2, 3, 4, 5]
  647. return {
  648. x: pArr[i].x,
  649. // when height is 0 instead of cuboid we render plane
  650. // so it is needed to add fake 10 height to imitate cuboid
  651. // for side calculation
  652. y: pArr[i].y + 10,
  653. z: pArr[i].z
  654. };
  655. }
  656. // It is needed to calculate dummy sides (front/back) for breaking
  657. // points in case of x and depth values. If column has side,
  658. // it means that x values of front and back side are different.
  659. if (pArr[0].x === pArr[7].x && i >= 4) { // [4, 5, 6, 7]
  660. return {
  661. x: pArr[i].x + 10,
  662. // when height is 0 instead of cuboid we render plane
  663. // so it is needed to add fake 10 height to imitate cuboid
  664. // for side calculation
  665. y: pArr[i].y,
  666. z: pArr[i].z
  667. };
  668. }
  669. // Added dummy depth
  670. if (d === 0 && i < 2 || i > 5) { // [0, 1, 6, 7]
  671. return {
  672. x: pArr[i].x,
  673. // when height is 0 instead of cuboid we render plane
  674. // so it is needed to add fake 10 height to imitate cuboid
  675. // for side calculation
  676. y: pArr[i].y,
  677. z: pArr[i].z + 10
  678. };
  679. }
  680. return pArr[i];
  681. }
  682. /**
  683. * method creating the final side
  684. * @private
  685. */
  686. function mapPath(i) {
  687. return pArr[i];
  688. }
  689. /**
  690. * First value - path with specific face
  691. * Second value - added information about side for later calculations.
  692. * Possible second values are 0 for path1, 1 for path2 and -1 for no path
  693. * chosen.
  694. * Third value - string containing information about current side
  695. * of cuboid for forcing side rendering.
  696. * @private
  697. */
  698. pickShape = function (verticesIndex1, verticesIndex2, side) {
  699. var ret = [[], -1],
  700. // An array of vertices for cuboid face
  701. face1 = verticesIndex1.map(mapPath), face2 = verticesIndex2.map(mapPath),
  702. // dummy face is calculated the same way as standard face,
  703. // but if cuboid height is 0 additional height is added so it is
  704. // possible to use this vertices array for visible face calculation
  705. dummyFace1 = verticesIndex1.map(mapSidePath), dummyFace2 = verticesIndex2.map(mapSidePath);
  706. if (H.shapeArea(face1) < 0) {
  707. ret = [face1, 0];
  708. }
  709. else if (H.shapeArea(face2) < 0) {
  710. ret = [face2, 1];
  711. }
  712. else if (side) {
  713. forcedSides.push(side);
  714. if (H.shapeArea(dummyFace1) < 0) {
  715. ret = [face1, 0];
  716. }
  717. else if (H.shapeArea(dummyFace2) < 0) {
  718. ret = [face2, 1];
  719. }
  720. else {
  721. ret = [face1, 0]; // force side calculation.
  722. }
  723. }
  724. return ret;
  725. };
  726. // front or back
  727. front = [3, 2, 1, 0];
  728. back = [7, 6, 5, 4];
  729. shape = pickShape(front, back, 'front');
  730. path1 = shape[0];
  731. isFront = shape[1];
  732. // top or bottom
  733. top = [1, 6, 7, 0];
  734. bottom = [4, 5, 2, 3];
  735. shape = pickShape(top, bottom, 'top');
  736. path2 = shape[0];
  737. isTop = shape[1];
  738. // side
  739. right = [1, 2, 5, 6];
  740. left = [0, 7, 4, 3];
  741. shape = pickShape(right, left, 'side');
  742. path3 = shape[0];
  743. isRight = shape[1];
  744. /* New block used for calculating zIndex. It is basing on X, Y and Z
  745. position of specific columns. All zIndexes (for X, Y and Z values) are
  746. added to the final zIndex, where every value has different priority. The
  747. biggest priority is in X and Z directions, the lowest index is for
  748. stacked columns (Y direction and the same X and Z positions). Big
  749. differences between priorities is made because we need to ensure that
  750. even for big changes in Y and Z parameters all columns will be drawn
  751. correctly. */
  752. if (isRight === 1) {
  753. // It is needed to connect value with current chart width
  754. // for big chart size.
  755. zIndex += incrementX * (chart.plotWidth - x);
  756. }
  757. else if (!isRight) {
  758. zIndex += incrementX * x;
  759. }
  760. zIndex += incrementY * (!isTop ||
  761. // Numbers checked empirically
  762. (alpha >= 0 && alpha <= 180 || alpha < 360 && alpha > 357.5) ?
  763. chart.plotHeight - y : 10 + y);
  764. if (isFront === 1) {
  765. zIndex += incrementZ * (z);
  766. }
  767. else if (!isFront) {
  768. zIndex += incrementZ * (1000 - z);
  769. }
  770. return {
  771. front: this.toLinePath(path1, true),
  772. top: this.toLinePath(path2, true),
  773. side: this.toLinePath(path3, true),
  774. zIndexes: {
  775. group: Math.round(zIndex)
  776. },
  777. forcedSides: forcedSides,
  778. // additional info about zIndexes
  779. isFront: isFront,
  780. isTop: isTop
  781. }; // #4774
  782. };
  783. // SECTORS //
  784. SVGRenderer.prototype.arc3d = function (attribs) {
  785. var wrapper = this.g(), renderer = wrapper.renderer, customAttribs = ['x', 'y', 'r', 'innerR', 'start', 'end', 'depth'];
  786. /**
  787. * Get custom attributes. Don't mutate the original object and return an
  788. * object with only custom attr.
  789. * @private
  790. */
  791. function suckOutCustom(params) {
  792. var hasCA = false, ca = {}, key;
  793. params = merge(params); // Don't mutate the original object
  794. for (key in params) {
  795. if (customAttribs.indexOf(key) !== -1) {
  796. ca[key] = params[key];
  797. delete params[key];
  798. hasCA = true;
  799. }
  800. }
  801. return hasCA ? [ca, params] : false;
  802. }
  803. attribs = merge(attribs);
  804. attribs.alpha = (attribs.alpha || 0) * deg2rad;
  805. attribs.beta = (attribs.beta || 0) * deg2rad;
  806. // Create the different sub sections of the shape
  807. wrapper.top = renderer.path();
  808. wrapper.side1 = renderer.path();
  809. wrapper.side2 = renderer.path();
  810. wrapper.inn = renderer.path();
  811. wrapper.out = renderer.path();
  812. // Add all faces
  813. wrapper.onAdd = function () {
  814. var parent = wrapper.parentGroup, className = wrapper.attr('class');
  815. wrapper.top.add(wrapper);
  816. // These faces are added outside the wrapper group because the z index
  817. // relates to neighbour elements as well
  818. ['out', 'inn', 'side1', 'side2'].forEach(function (face) {
  819. wrapper[face]
  820. .attr({
  821. 'class': className + ' highcharts-3d-side'
  822. })
  823. .add(parent);
  824. });
  825. };
  826. // Cascade to faces
  827. ['addClass', 'removeClass'].forEach(function (fn) {
  828. wrapper[fn] = function () {
  829. var args = arguments;
  830. ['top', 'out', 'inn', 'side1', 'side2'].forEach(function (face) {
  831. wrapper[face][fn].apply(wrapper[face], args);
  832. });
  833. };
  834. });
  835. /**
  836. * Compute the transformed paths and set them to the composite shapes
  837. * @private
  838. */
  839. wrapper.setPaths = function (attribs) {
  840. var paths = wrapper.renderer.arc3dPath(attribs), zIndex = paths.zTop * 100;
  841. wrapper.attribs = attribs;
  842. wrapper.top.attr({ d: paths.top, zIndex: paths.zTop });
  843. wrapper.inn.attr({ d: paths.inn, zIndex: paths.zInn });
  844. wrapper.out.attr({ d: paths.out, zIndex: paths.zOut });
  845. wrapper.side1.attr({ d: paths.side1, zIndex: paths.zSide1 });
  846. wrapper.side2.attr({ d: paths.side2, zIndex: paths.zSide2 });
  847. // show all children
  848. wrapper.zIndex = zIndex;
  849. wrapper.attr({ zIndex: zIndex });
  850. // Set the radial gradient center the first time
  851. if (attribs.center) {
  852. wrapper.top.setRadialReference(attribs.center);
  853. delete attribs.center;
  854. }
  855. };
  856. wrapper.setPaths(attribs);
  857. /**
  858. * Apply the fill to the top and a darker shade to the sides
  859. * @private
  860. */
  861. wrapper.fillSetter = function (value) {
  862. var darker = color(value).brighten(-0.1).get();
  863. this.fill = value;
  864. this.side1.attr({ fill: darker });
  865. this.side2.attr({ fill: darker });
  866. this.inn.attr({ fill: darker });
  867. this.out.attr({ fill: darker });
  868. this.top.attr({ fill: value });
  869. return this;
  870. };
  871. // Apply the same value to all. These properties cascade down to the
  872. // children when set to the composite arc3d.
  873. ['opacity', 'translateX', 'translateY', 'visibility'].forEach(function (setter) {
  874. wrapper[setter + 'Setter'] = function (value, key) {
  875. wrapper[key] = value;
  876. ['out', 'inn', 'side1', 'side2', 'top'].forEach(function (el) {
  877. wrapper[el].attr(key, value);
  878. });
  879. };
  880. });
  881. // Override attr to remove shape attributes and use those to set child paths
  882. wrapper.attr = function (params) {
  883. var ca, paramArr;
  884. if (typeof params === 'object') {
  885. paramArr = suckOutCustom(params);
  886. if (paramArr) {
  887. ca = paramArr[0];
  888. arguments[0] = paramArr[1];
  889. extend(wrapper.attribs, ca);
  890. wrapper.setPaths(wrapper.attribs);
  891. }
  892. }
  893. return SVGElement.prototype.attr.apply(wrapper, arguments);
  894. };
  895. // Override the animate function by sucking out custom parameters related to
  896. // the shapes directly, and update the shapes from the animation step.
  897. wrapper.animate = function (params, animation, complete) {
  898. var paramArr, from = this.attribs, to, anim, randomProp = 'data-' + Math.random().toString(26).substring(2, 9);
  899. // Attribute-line properties connected to 3D. These shouldn't have been
  900. // in the attribs collection in the first place.
  901. delete params.center;
  902. delete params.z;
  903. delete params.alpha;
  904. delete params.beta;
  905. anim = animObject(pick(animation, this.renderer.globalAnimation));
  906. if (anim.duration) {
  907. paramArr = suckOutCustom(params);
  908. // Params need to have a property in order for the step to run
  909. // (#5765, #7097, #7437)
  910. wrapper[randomProp] = 0;
  911. params[randomProp] = 1;
  912. wrapper[randomProp + 'Setter'] = H.noop;
  913. if (paramArr) {
  914. to = paramArr[0]; // custom attr
  915. anim.step = function (a, fx) {
  916. /**
  917. * @private
  918. */
  919. function interpolate(key) {
  920. return from[key] + (pick(to[key], from[key]) -
  921. from[key]) * fx.pos;
  922. }
  923. if (fx.prop === randomProp) {
  924. fx.elem.setPaths(merge(from, {
  925. x: interpolate('x'),
  926. y: interpolate('y'),
  927. r: interpolate('r'),
  928. innerR: interpolate('innerR'),
  929. start: interpolate('start'),
  930. end: interpolate('end'),
  931. depth: interpolate('depth')
  932. }));
  933. }
  934. };
  935. }
  936. animation = anim; // Only when duration (#5572)
  937. }
  938. return SVGElement.prototype.animate.call(this, params, animation, complete);
  939. };
  940. // destroy all children
  941. wrapper.destroy = function () {
  942. this.top.destroy();
  943. this.out.destroy();
  944. this.inn.destroy();
  945. this.side1.destroy();
  946. this.side2.destroy();
  947. return SVGElement.prototype.destroy.call(this);
  948. };
  949. // hide all children
  950. wrapper.hide = function () {
  951. this.top.hide();
  952. this.out.hide();
  953. this.inn.hide();
  954. this.side1.hide();
  955. this.side2.hide();
  956. };
  957. wrapper.show = function (inherit) {
  958. this.top.show(inherit);
  959. this.out.show(inherit);
  960. this.inn.show(inherit);
  961. this.side1.show(inherit);
  962. this.side2.show(inherit);
  963. };
  964. return wrapper;
  965. };
  966. // Generate the paths required to draw a 3D arc
  967. SVGRenderer.prototype.arc3dPath = function (shapeArgs) {
  968. var cx = shapeArgs.x, // x coordinate of the center
  969. cy = shapeArgs.y, // y coordinate of the center
  970. start = shapeArgs.start, // start angle
  971. end = shapeArgs.end - 0.00001, // end angle
  972. r = shapeArgs.r, // radius
  973. ir = shapeArgs.innerR || 0, // inner radius
  974. d = shapeArgs.depth || 0, // depth
  975. alpha = shapeArgs.alpha, // alpha rotation of the chart
  976. beta = shapeArgs.beta; // beta rotation of the chart
  977. // Derived Variables
  978. var cs = Math.cos(start), // cosinus of the start angle
  979. ss = Math.sin(start), // sinus of the start angle
  980. ce = Math.cos(end), // cosinus of the end angle
  981. se = Math.sin(end), // sinus of the end angle
  982. rx = r * Math.cos(beta), // x-radius
  983. ry = r * Math.cos(alpha), // y-radius
  984. irx = ir * Math.cos(beta), // x-radius (inner)
  985. iry = ir * Math.cos(alpha), // y-radius (inner)
  986. dx = d * Math.sin(beta), // distance between top and bottom in x
  987. dy = d * Math.sin(alpha); // distance between top and bottom in y
  988. // TOP
  989. var top = [
  990. ['M', cx + (rx * cs), cy + (ry * ss)]
  991. ];
  992. top = top.concat(curveTo(cx, cy, rx, ry, start, end, 0, 0));
  993. top.push([
  994. 'L', cx + (irx * ce), cy + (iry * se)
  995. ]);
  996. top = top.concat(curveTo(cx, cy, irx, iry, end, start, 0, 0));
  997. top.push(['Z']);
  998. // OUTSIDE
  999. var b = (beta > 0 ? Math.PI / 2 : 0), a = (alpha > 0 ? 0 : Math.PI / 2);
  1000. var start2 = start > -b ? start : (end > -b ? -b : start), end2 = end < PI - a ? end : (start < PI - a ? PI - a : end), midEnd = 2 * PI - a;
  1001. // When slice goes over bottom middle, need to add both, left and right
  1002. // outer side. Additionally, when we cross right hand edge, create sharp
  1003. // edge. Outer shape/wall:
  1004. //
  1005. // -------
  1006. // / ^ \
  1007. // 4) / / \ \ 1)
  1008. // / / \ \
  1009. // / / \ \
  1010. // (c)=> ==== ==== <=(d)
  1011. // \ \ / /
  1012. // \ \<=(a)/ /
  1013. // \ \ / / <=(b)
  1014. // 3) \ v / 2)
  1015. // -------
  1016. //
  1017. // (a) - inner side
  1018. // (b) - outer side
  1019. // (c) - left edge (sharp)
  1020. // (d) - right edge (sharp)
  1021. // 1..n - rendering order for startAngle = 0, when set to e.g 90, order
  1022. // changes clockwise (1->2, 2->3, n->1) and counterclockwise for negative
  1023. // startAngle
  1024. var out = [
  1025. ['M', cx + (rx * cos(start2)), cy + (ry * sin(start2))]
  1026. ];
  1027. out = out.concat(curveTo(cx, cy, rx, ry, start2, end2, 0, 0));
  1028. // When shape is wide, it can cross both, (c) and (d) edges, when using
  1029. // startAngle
  1030. if (end > midEnd && start < midEnd) {
  1031. // Go to outer side
  1032. out.push([
  1033. 'L', cx + (rx * cos(end2)) + dx, cy + (ry * sin(end2)) + dy
  1034. ]);
  1035. // Curve to the right edge of the slice (d)
  1036. out = out.concat(curveTo(cx, cy, rx, ry, end2, midEnd, dx, dy));
  1037. // Go to the inner side
  1038. out.push([
  1039. 'L', cx + (rx * cos(midEnd)), cy + (ry * sin(midEnd))
  1040. ]);
  1041. // Curve to the true end of the slice
  1042. out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end, 0, 0));
  1043. // Go to the outer side
  1044. out.push([
  1045. 'L', cx + (rx * cos(end)) + dx, cy + (ry * sin(end)) + dy
  1046. ]);
  1047. // Go back to middle (d)
  1048. out = out.concat(curveTo(cx, cy, rx, ry, end, midEnd, dx, dy));
  1049. out.push([
  1050. 'L', cx + (rx * cos(midEnd)), cy + (ry * sin(midEnd))
  1051. ]);
  1052. // Go back to the left edge
  1053. out = out.concat(curveTo(cx, cy, rx, ry, midEnd, end2, 0, 0));
  1054. // But shape can cross also only (c) edge:
  1055. }
  1056. else if (end > PI - a && start < PI - a) {
  1057. // Go to outer side
  1058. out.push([
  1059. 'L',
  1060. cx + (rx * Math.cos(end2)) + dx,
  1061. cy + (ry * Math.sin(end2)) + dy
  1062. ]);
  1063. // Curve to the true end of the slice
  1064. out = out.concat(curveTo(cx, cy, rx, ry, end2, end, dx, dy));
  1065. // Go to the inner side
  1066. out.push([
  1067. 'L', cx + (rx * Math.cos(end)), cy + (ry * Math.sin(end))
  1068. ]);
  1069. // Go back to the artifical end2
  1070. out = out.concat(curveTo(cx, cy, rx, ry, end, end2, 0, 0));
  1071. }
  1072. out.push([
  1073. 'L', cx + (rx * Math.cos(end2)) + dx, cy + (ry * Math.sin(end2)) + dy
  1074. ]);
  1075. out = out.concat(curveTo(cx, cy, rx, ry, end2, start2, dx, dy));
  1076. out.push(['Z']);
  1077. // INSIDE
  1078. var inn = [
  1079. ['M', cx + (irx * cs), cy + (iry * ss)]
  1080. ];
  1081. inn = inn.concat(curveTo(cx, cy, irx, iry, start, end, 0, 0));
  1082. inn.push([
  1083. 'L', cx + (irx * Math.cos(end)) + dx, cy + (iry * Math.sin(end)) + dy
  1084. ]);
  1085. inn = inn.concat(curveTo(cx, cy, irx, iry, end, start, dx, dy));
  1086. inn.push(['Z']);
  1087. // SIDES
  1088. var side1 = [
  1089. ['M', cx + (rx * cs), cy + (ry * ss)],
  1090. ['L', cx + (rx * cs) + dx, cy + (ry * ss) + dy],
  1091. ['L', cx + (irx * cs) + dx, cy + (iry * ss) + dy],
  1092. ['L', cx + (irx * cs), cy + (iry * ss)],
  1093. ['Z']
  1094. ];
  1095. var side2 = [
  1096. ['M', cx + (rx * ce), cy + (ry * se)],
  1097. ['L', cx + (rx * ce) + dx, cy + (ry * se) + dy],
  1098. ['L', cx + (irx * ce) + dx, cy + (iry * se) + dy],
  1099. ['L', cx + (irx * ce), cy + (iry * se)],
  1100. ['Z']
  1101. ];
  1102. // correction for changed position of vanishing point caused by alpha and
  1103. // beta rotations
  1104. var angleCorr = Math.atan2(dy, -dx), angleEnd = Math.abs(end + angleCorr), angleStart = Math.abs(start + angleCorr), angleMid = Math.abs((start + end) / 2 + angleCorr);
  1105. /**
  1106. * set to 0-PI range
  1107. * @private
  1108. */
  1109. function toZeroPIRange(angle) {
  1110. angle = angle % (2 * Math.PI);
  1111. if (angle > Math.PI) {
  1112. angle = 2 * Math.PI - angle;
  1113. }
  1114. return angle;
  1115. }
  1116. angleEnd = toZeroPIRange(angleEnd);
  1117. angleStart = toZeroPIRange(angleStart);
  1118. angleMid = toZeroPIRange(angleMid);
  1119. // *1e5 is to compensate pInt in zIndexSetter
  1120. var incPrecision = 1e5, a1 = angleMid * incPrecision, a2 = angleStart * incPrecision, a3 = angleEnd * incPrecision;
  1121. return {
  1122. top: top,
  1123. // max angle is PI, so this is always higher
  1124. zTop: Math.PI * incPrecision + 1,
  1125. out: out,
  1126. zOut: Math.max(a1, a2, a3),
  1127. inn: inn,
  1128. zInn: Math.max(a1, a2, a3),
  1129. side1: side1,
  1130. zSide1: a3 * 0.99,
  1131. side2: side2,
  1132. zSide2: a2 * 0.99
  1133. };
  1134. };
  1135. });
  1136. _registerModule(_modules, 'parts-3d/Tick3D.js', [_modules['parts/Utilities.js']], function (U) {
  1137. /* *
  1138. *
  1139. * (c) 2010-2020 Torstein Honsi
  1140. *
  1141. * Extenstion for 3d axes
  1142. *
  1143. * License: www.highcharts.com/license
  1144. *
  1145. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1146. *
  1147. * */
  1148. var addEvent = U.addEvent, extend = U.extend, wrap = U.wrap;
  1149. /* eslint-disable valid-jsdoc */
  1150. /**
  1151. * Tick with 3D support
  1152. * @private
  1153. * @class
  1154. */
  1155. var Tick3D = /** @class */ (function () {
  1156. function Tick3D() {
  1157. }
  1158. /* *
  1159. *
  1160. * Static Functions
  1161. *
  1162. * */
  1163. /**
  1164. * @private
  1165. */
  1166. Tick3D.compose = function (TickClass) {
  1167. addEvent(TickClass, 'afterGetLabelPosition', Tick3D.onAfterGetLabelPosition);
  1168. var tickProto = TickClass.prototype;
  1169. wrap(tickProto, 'getMarkPath', Tick3D.wrapGetMarkPath);
  1170. };
  1171. /**
  1172. * @private
  1173. */
  1174. Tick3D.onAfterGetLabelPosition = function (e) {
  1175. var axis3D = this.axis.axis3D;
  1176. if (axis3D) {
  1177. extend(e.pos, axis3D.fix3dPosition(e.pos));
  1178. }
  1179. };
  1180. /**
  1181. * @private
  1182. */
  1183. Tick3D.wrapGetMarkPath = function (proceed) {
  1184. var chart = this.axis.chart;
  1185. var axis3D = this.axis.axis3D;
  1186. var path = proceed.apply(this, [].slice.call(arguments, 1));
  1187. if (axis3D) {
  1188. var start = path[0];
  1189. var end = path[1];
  1190. if (start[0] === 'M' && end[0] === 'L') {
  1191. var pArr = [
  1192. axis3D.fix3dPosition({ x: start[1], y: start[2], z: 0 }),
  1193. axis3D.fix3dPosition({ x: end[1], y: end[2], z: 0 })
  1194. ];
  1195. return this.axis.chart.renderer.toLineSegments(pArr);
  1196. }
  1197. }
  1198. return path;
  1199. };
  1200. return Tick3D;
  1201. }());
  1202. return Tick3D;
  1203. });
  1204. _registerModule(_modules, 'parts-3d/Axis3D.js', [_modules['parts/Globals.js'], _modules['parts/Tick.js'], _modules['parts-3d/Tick3D.js'], _modules['parts/Utilities.js']], function (H, Tick, Tick3D, U) {
  1205. /* *
  1206. *
  1207. * (c) 2010-2020 Torstein Honsi
  1208. *
  1209. * Extenstion for 3d axes
  1210. *
  1211. * License: www.highcharts.com/license
  1212. *
  1213. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1214. *
  1215. * */
  1216. var addEvent = U.addEvent, merge = U.merge, pick = U.pick, wrap = U.wrap;
  1217. var deg2rad = H.deg2rad, perspective = H.perspective, perspective3D = H.perspective3D, shapeArea = H.shapeArea;
  1218. /* eslint-disable valid-jsdoc */
  1219. /**
  1220. * Adds 3D support to axes.
  1221. * @private
  1222. * @class
  1223. */
  1224. var Axis3DAdditions = /** @class */ (function () {
  1225. /* *
  1226. *
  1227. * Constructors
  1228. *
  1229. * */
  1230. /**
  1231. * @private
  1232. */
  1233. function Axis3DAdditions(axis) {
  1234. this.axis = axis;
  1235. }
  1236. /* *
  1237. *
  1238. * Functions
  1239. *
  1240. * */
  1241. /**
  1242. * @private
  1243. * @param {Highcharts.Axis} axis
  1244. * Related axis.
  1245. * @param {Highcharts.Position3dObject} pos
  1246. * Position to fix.
  1247. * @param {boolean} [isTitle]
  1248. * Whether this is a title position.
  1249. * @return {Highcharts.Position3dObject}
  1250. * Fixed position.
  1251. */
  1252. Axis3DAdditions.prototype.fix3dPosition = function (pos, isTitle) {
  1253. var axis3D = this;
  1254. var axis = axis3D.axis;
  1255. var chart = axis.chart;
  1256. // Do not do this if the chart is not 3D
  1257. if (axis.coll === 'colorAxis' ||
  1258. !chart.chart3d ||
  1259. !chart.is3d()) {
  1260. return pos;
  1261. }
  1262. var alpha = deg2rad * chart.options.chart.options3d.alpha, beta = deg2rad * chart.options.chart.options3d.beta, positionMode = pick(isTitle && axis.options.title.position3d, axis.options.labels.position3d), skew = pick(isTitle && axis.options.title.skew3d, axis.options.labels.skew3d), frame = chart.chart3d.frame3d, plotLeft = chart.plotLeft, plotRight = chart.plotWidth + plotLeft, plotTop = chart.plotTop, plotBottom = chart.plotHeight + plotTop,
  1263. // Indicates that we are labelling an X or Z axis on the "back" of
  1264. // the chart
  1265. reverseFlap = false, offsetX = 0, offsetY = 0, vecX, vecY = { x: 0, y: 1, z: 0 };
  1266. pos = axis.axis3D.swapZ({ x: pos.x, y: pos.y, z: 0 });
  1267. if (axis.isZAxis) { // Z Axis
  1268. if (axis.opposite) {
  1269. if (frame.axes.z.top === null) {
  1270. return {};
  1271. }
  1272. offsetY = pos.y - plotTop;
  1273. pos.x = frame.axes.z.top.x;
  1274. pos.y = frame.axes.z.top.y;
  1275. vecX = frame.axes.z.top.xDir;
  1276. reverseFlap = !frame.top.frontFacing;
  1277. }
  1278. else {
  1279. if (frame.axes.z.bottom === null) {
  1280. return {};
  1281. }
  1282. offsetY = pos.y - plotBottom;
  1283. pos.x = frame.axes.z.bottom.x;
  1284. pos.y = frame.axes.z.bottom.y;
  1285. vecX = frame.axes.z.bottom.xDir;
  1286. reverseFlap = !frame.bottom.frontFacing;
  1287. }
  1288. }
  1289. else if (axis.horiz) { // X Axis
  1290. if (axis.opposite) {
  1291. if (frame.axes.x.top === null) {
  1292. return {};
  1293. }
  1294. offsetY = pos.y - plotTop;
  1295. pos.y = frame.axes.x.top.y;
  1296. pos.z = frame.axes.x.top.z;
  1297. vecX = frame.axes.x.top.xDir;
  1298. reverseFlap = !frame.top.frontFacing;
  1299. }
  1300. else {
  1301. if (frame.axes.x.bottom === null) {
  1302. return {};
  1303. }
  1304. offsetY = pos.y - plotBottom;
  1305. pos.y = frame.axes.x.bottom.y;
  1306. pos.z = frame.axes.x.bottom.z;
  1307. vecX = frame.axes.x.bottom.xDir;
  1308. reverseFlap = !frame.bottom.frontFacing;
  1309. }
  1310. }
  1311. else { // Y Axis
  1312. if (axis.opposite) {
  1313. if (frame.axes.y.right === null) {
  1314. return {};
  1315. }
  1316. offsetX = pos.x - plotRight;
  1317. pos.x = frame.axes.y.right.x;
  1318. pos.z = frame.axes.y.right.z;
  1319. vecX = frame.axes.y.right.xDir;
  1320. // Rotate 90º on opposite edge
  1321. vecX = { x: vecX.z, y: vecX.y, z: -vecX.x };
  1322. }
  1323. else {
  1324. if (frame.axes.y.left === null) {
  1325. return {};
  1326. }
  1327. offsetX = pos.x - plotLeft;
  1328. pos.x = frame.axes.y.left.x;
  1329. pos.z = frame.axes.y.left.z;
  1330. vecX = frame.axes.y.left.xDir;
  1331. }
  1332. }
  1333. if (positionMode === 'chart') {
  1334. // Labels preserve their direction relative to the chart
  1335. // nothing to do
  1336. }
  1337. else if (positionMode === 'flap') {
  1338. // Labels are rotated around the axis direction to face the screen
  1339. if (!axis.horiz) { // Y Axis
  1340. vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
  1341. }
  1342. else { // X and Z Axis
  1343. var sin = Math.sin(alpha);
  1344. var cos = Math.cos(alpha);
  1345. if (axis.opposite) {
  1346. sin = -sin;
  1347. }
  1348. if (reverseFlap) {
  1349. sin = -sin;
  1350. }
  1351. vecY = { x: vecX.z * sin, y: cos, z: -vecX.x * sin };
  1352. }
  1353. }
  1354. else if (positionMode === 'ortho') {
  1355. // Labels will be rotated to be ortogonal to the axis
  1356. if (!axis.horiz) { // Y Axis
  1357. vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
  1358. }
  1359. else { // X and Z Axis
  1360. var sina = Math.sin(alpha);
  1361. var cosa = Math.cos(alpha);
  1362. var sinb = Math.sin(beta);
  1363. var cosb = Math.cos(beta);
  1364. var vecZ = { x: sinb * cosa, y: -sina, z: -cosa * cosb };
  1365. vecY = {
  1366. x: vecX.y * vecZ.z - vecX.z * vecZ.y,
  1367. y: vecX.z * vecZ.x - vecX.x * vecZ.z,
  1368. z: vecX.x * vecZ.y - vecX.y * vecZ.x
  1369. };
  1370. var scale = 1 / Math.sqrt(vecY.x * vecY.x + vecY.y * vecY.y + vecY.z * vecY.z);
  1371. if (reverseFlap) {
  1372. scale = -scale;
  1373. }
  1374. vecY = { x: scale * vecY.x, y: scale * vecY.y, z: scale * vecY.z };
  1375. }
  1376. }
  1377. else { // positionMode == 'offset'
  1378. // Labels will be skewd to maintain vertical / horizontal offsets
  1379. // from axis
  1380. if (!axis.horiz) { // Y Axis
  1381. vecX = { x: Math.cos(beta), y: 0, z: Math.sin(beta) };
  1382. }
  1383. else { // X and Z Axis
  1384. vecY = {
  1385. x: Math.sin(beta) * Math.sin(alpha),
  1386. y: Math.cos(alpha),
  1387. z: -Math.cos(beta) * Math.sin(alpha)
  1388. };
  1389. }
  1390. }
  1391. pos.x += offsetX * vecX.x + offsetY * vecY.x;
  1392. pos.y += offsetX * vecX.y + offsetY * vecY.y;
  1393. pos.z += offsetX * vecX.z + offsetY * vecY.z;
  1394. var projected = perspective([pos], axis.chart)[0];
  1395. if (skew) {
  1396. // Check if the label text would be mirrored
  1397. var isMirrored = shapeArea(perspective([
  1398. pos,
  1399. { x: pos.x + vecX.x, y: pos.y + vecX.y, z: pos.z + vecX.z },
  1400. { x: pos.x + vecY.x, y: pos.y + vecY.y, z: pos.z + vecY.z }
  1401. ], axis.chart)) < 0;
  1402. if (isMirrored) {
  1403. vecX = { x: -vecX.x, y: -vecX.y, z: -vecX.z };
  1404. }
  1405. var pointsProjected = perspective([
  1406. { x: pos.x, y: pos.y, z: pos.z },
  1407. { x: pos.x + vecX.x, y: pos.y + vecX.y, z: pos.z + vecX.z },
  1408. { x: pos.x + vecY.x, y: pos.y + vecY.y, z: pos.z + vecY.z }
  1409. ], axis.chart);
  1410. projected.matrix = [
  1411. pointsProjected[1].x - pointsProjected[0].x,
  1412. pointsProjected[1].y - pointsProjected[0].y,
  1413. pointsProjected[2].x - pointsProjected[0].x,
  1414. pointsProjected[2].y - pointsProjected[0].y,
  1415. projected.x,
  1416. projected.y
  1417. ];
  1418. projected.matrix[4] -= projected.x * projected.matrix[0] +
  1419. projected.y * projected.matrix[2];
  1420. projected.matrix[5] -= projected.x * projected.matrix[1] +
  1421. projected.y * projected.matrix[3];
  1422. }
  1423. return projected;
  1424. };
  1425. /**
  1426. * @private
  1427. */
  1428. Axis3DAdditions.prototype.swapZ = function (p, insidePlotArea) {
  1429. var axis = this.axis;
  1430. if (axis.isZAxis) {
  1431. var plotLeft = insidePlotArea ? 0 : axis.chart.plotLeft;
  1432. return {
  1433. x: plotLeft + p.z,
  1434. y: p.y,
  1435. z: p.x - plotLeft
  1436. };
  1437. }
  1438. return p;
  1439. };
  1440. return Axis3DAdditions;
  1441. }());
  1442. /**
  1443. * Axis with 3D support.
  1444. * @private
  1445. * @class
  1446. */
  1447. var Axis3D = /** @class */ (function () {
  1448. function Axis3D() {
  1449. }
  1450. /* *
  1451. *
  1452. * Static Functions
  1453. *
  1454. * */
  1455. /**
  1456. * Extends axis class with 3D support.
  1457. * @private
  1458. */
  1459. Axis3D.compose = function (AxisClass) {
  1460. merge(true, AxisClass.defaultOptions, Axis3D.defaultOptions);
  1461. AxisClass.keepProps.push('axis3D');
  1462. addEvent(AxisClass, 'init', Axis3D.onInit);
  1463. addEvent(AxisClass, 'afterSetOptions', Axis3D.onAfterSetOptions);
  1464. addEvent(AxisClass, 'drawCrosshair', Axis3D.onDrawCrosshair);
  1465. addEvent(AxisClass, 'destroy', Axis3D.onDestroy);
  1466. var axisProto = AxisClass.prototype;
  1467. wrap(axisProto, 'getLinePath', Axis3D.wrapGetLinePath);
  1468. wrap(axisProto, 'getPlotBandPath', Axis3D.wrapGetPlotBandPath);
  1469. wrap(axisProto, 'getPlotLinePath', Axis3D.wrapGetPlotLinePath);
  1470. wrap(axisProto, 'getSlotWidth', Axis3D.wrapGetSlotWidth);
  1471. wrap(axisProto, 'getTitlePosition', Axis3D.wrapGetTitlePosition);
  1472. Tick3D.compose(Tick);
  1473. };
  1474. /**
  1475. * @private
  1476. */
  1477. Axis3D.onAfterSetOptions = function () {
  1478. var axis = this;
  1479. var chart = axis.chart;
  1480. var options = axis.options;
  1481. if (chart.is3d && chart.is3d() && axis.coll !== 'colorAxis') {
  1482. options.tickWidth = pick(options.tickWidth, 0);
  1483. options.gridLineWidth = pick(options.gridLineWidth, 1);
  1484. }
  1485. };
  1486. /**
  1487. * @private
  1488. */
  1489. Axis3D.onDestroy = function () {
  1490. ['backFrame', 'bottomFrame', 'sideFrame'].forEach(function (prop) {
  1491. if (this[prop]) {
  1492. this[prop] = this[prop].destroy();
  1493. }
  1494. }, this);
  1495. };
  1496. /**
  1497. * @private
  1498. */
  1499. Axis3D.onDrawCrosshair = function (e) {
  1500. var axis = this;
  1501. if (axis.chart.is3d() &&
  1502. axis.coll !== 'colorAxis') {
  1503. if (e.point) {
  1504. e.point.crosshairPos = axis.isXAxis ?
  1505. e.point.axisXpos :
  1506. axis.len - e.point.axisYpos;
  1507. }
  1508. }
  1509. };
  1510. /**
  1511. * @private
  1512. */
  1513. Axis3D.onInit = function () {
  1514. var axis = this;
  1515. if (!axis.axis3D) {
  1516. axis.axis3D = new Axis3DAdditions(axis);
  1517. }
  1518. };
  1519. /**
  1520. * Do not draw axislines in 3D.
  1521. * @private
  1522. */
  1523. Axis3D.wrapGetLinePath = function (proceed) {
  1524. var axis = this;
  1525. // Do not do this if the chart is not 3D
  1526. if (!axis.chart.is3d() || axis.coll === 'colorAxis') {
  1527. return proceed.apply(axis, [].slice.call(arguments, 1));
  1528. }
  1529. return [];
  1530. };
  1531. /**
  1532. * @private
  1533. */
  1534. Axis3D.wrapGetPlotBandPath = function (proceed) {
  1535. // Do not do this if the chart is not 3D
  1536. if (!this.chart.is3d() || this.coll === 'colorAxis') {
  1537. return proceed.apply(this, [].slice.call(arguments, 1));
  1538. }
  1539. var args = arguments, from = args[1], to = args[2], path = [], fromPath = this.getPlotLinePath({ value: from }), toPath = this.getPlotLinePath({ value: to });
  1540. if (fromPath && toPath) {
  1541. for (var i = 0; i < fromPath.length; i += 2) {
  1542. var fromStartSeg = fromPath[i], fromEndSeg = fromPath[i + 1], toStartSeg = toPath[i], toEndSeg = toPath[i + 1];
  1543. if (fromStartSeg[0] === 'M' &&
  1544. fromEndSeg[0] === 'L' &&
  1545. toStartSeg[0] === 'M' &&
  1546. toEndSeg[0] === 'L') {
  1547. path.push(fromStartSeg, fromEndSeg, toEndSeg,
  1548. // lineTo instead of moveTo
  1549. ['L', toStartSeg[1], toStartSeg[2]], ['Z']);
  1550. }
  1551. }
  1552. }
  1553. return path;
  1554. };
  1555. /**
  1556. * @private
  1557. */
  1558. Axis3D.wrapGetPlotLinePath = function (proceed) {
  1559. var axis = this;
  1560. var axis3D = axis.axis3D;
  1561. var chart = axis.chart;
  1562. var path = proceed.apply(axis, [].slice.call(arguments, 1));
  1563. // Do not do this if the chart is not 3D
  1564. if (axis.coll === 'colorAxis' ||
  1565. !chart.chart3d ||
  1566. !chart.is3d()) {
  1567. return path;
  1568. }
  1569. if (path === null) {
  1570. return path;
  1571. }
  1572. var options3d = chart.options.chart.options3d, d = axis.isZAxis ? chart.plotWidth : options3d.depth, frame = chart.chart3d.frame3d, startSegment = path[0], endSegment = path[1], pArr, pathSegments = [];
  1573. if (startSegment[0] === 'M' && endSegment[0] === 'L') {
  1574. pArr = [
  1575. axis3D.swapZ({ x: startSegment[1], y: startSegment[2], z: 0 }),
  1576. axis3D.swapZ({ x: startSegment[1], y: startSegment[2], z: d }),
  1577. axis3D.swapZ({ x: endSegment[1], y: endSegment[2], z: 0 }),
  1578. axis3D.swapZ({ x: endSegment[1], y: endSegment[2], z: d })
  1579. ];
  1580. if (!this.horiz) { // Y-Axis
  1581. if (frame.front.visible) {
  1582. pathSegments.push(pArr[0], pArr[2]);
  1583. }
  1584. if (frame.back.visible) {
  1585. pathSegments.push(pArr[1], pArr[3]);
  1586. }
  1587. if (frame.left.visible) {
  1588. pathSegments.push(pArr[0], pArr[1]);
  1589. }
  1590. if (frame.right.visible) {
  1591. pathSegments.push(pArr[2], pArr[3]);
  1592. }
  1593. }
  1594. else if (this.isZAxis) { // Z-Axis
  1595. if (frame.left.visible) {
  1596. pathSegments.push(pArr[0], pArr[2]);
  1597. }
  1598. if (frame.right.visible) {
  1599. pathSegments.push(pArr[1], pArr[3]);
  1600. }
  1601. if (frame.top.visible) {
  1602. pathSegments.push(pArr[0], pArr[1]);
  1603. }
  1604. if (frame.bottom.visible) {
  1605. pathSegments.push(pArr[2], pArr[3]);
  1606. }
  1607. }
  1608. else { // X-Axis
  1609. if (frame.front.visible) {
  1610. pathSegments.push(pArr[0], pArr[2]);
  1611. }
  1612. if (frame.back.visible) {
  1613. pathSegments.push(pArr[1], pArr[3]);
  1614. }
  1615. if (frame.top.visible) {
  1616. pathSegments.push(pArr[0], pArr[1]);
  1617. }
  1618. if (frame.bottom.visible) {
  1619. pathSegments.push(pArr[2], pArr[3]);
  1620. }
  1621. }
  1622. pathSegments = perspective(pathSegments, this.chart, false);
  1623. }
  1624. return chart.renderer.toLineSegments(pathSegments);
  1625. };
  1626. /**
  1627. * Wrap getSlotWidth function to calculate individual width value for each
  1628. * slot (#8042).
  1629. * @private
  1630. */
  1631. Axis3D.wrapGetSlotWidth = function (proceed, tick) {
  1632. var axis = this;
  1633. var chart = axis.chart;
  1634. var ticks = axis.ticks;
  1635. var gridGroup = axis.gridGroup;
  1636. if (axis.categories &&
  1637. chart.frameShapes &&
  1638. chart.is3d() &&
  1639. gridGroup &&
  1640. tick &&
  1641. tick.label) {
  1642. var firstGridLine = gridGroup.element.childNodes[0].getBBox(), frame3DLeft = chart.frameShapes.left.getBBox(), options3d = chart.options.chart.options3d, origin = {
  1643. x: chart.plotWidth / 2,
  1644. y: chart.plotHeight / 2,
  1645. z: options3d.depth / 2,
  1646. vd: pick(options3d.depth, 1) * pick(options3d.viewDistance, 0)
  1647. }, labelPos, prevLabelPos, nextLabelPos, slotWidth, tickId = tick.pos, prevTick = ticks[tickId - 1], nextTick = ticks[tickId + 1];
  1648. // Check whether the tick is not the first one and previous tick
  1649. // exists, then calculate position of previous label.
  1650. if (tickId !== 0 && prevTick && prevTick.label.xy) {
  1651. prevLabelPos = perspective3D({
  1652. x: prevTick.label.xy.x,
  1653. y: prevTick.label.xy.y,
  1654. z: null
  1655. }, origin, origin.vd);
  1656. }
  1657. // If next label position is defined, then recalculate its position
  1658. // basing on the perspective.
  1659. if (nextTick && nextTick.label.xy) {
  1660. nextLabelPos = perspective3D({
  1661. x: nextTick.label.xy.x,
  1662. y: nextTick.label.xy.y,
  1663. z: null
  1664. }, origin, origin.vd);
  1665. }
  1666. labelPos = {
  1667. x: tick.label.xy.x,
  1668. y: tick.label.xy.y,
  1669. z: null
  1670. };
  1671. labelPos = perspective3D(labelPos, origin, origin.vd);
  1672. // If tick is first one, check whether next label position is
  1673. // already calculated, then return difference between the first and
  1674. // the second label. If there is no next label position calculated,
  1675. // return the difference between the first grid line and left 3d
  1676. // frame.
  1677. slotWidth = Math.abs(prevLabelPos ?
  1678. labelPos.x - prevLabelPos.x : nextLabelPos ?
  1679. nextLabelPos.x - labelPos.x :
  1680. firstGridLine.x - frame3DLeft.x);
  1681. return slotWidth;
  1682. }
  1683. return proceed.apply(axis, [].slice.call(arguments, 1));
  1684. };
  1685. /**
  1686. * @private
  1687. */
  1688. Axis3D.wrapGetTitlePosition = function (proceed) {
  1689. var pos = proceed.apply(this, [].slice.call(arguments, 1));
  1690. return this.axis3D ?
  1691. this.axis3D.fix3dPosition(pos, true) :
  1692. pos;
  1693. };
  1694. /* *
  1695. *
  1696. * Static Properties
  1697. *
  1698. * */
  1699. /**
  1700. * @optionparent xAxis
  1701. */
  1702. Axis3D.defaultOptions = {
  1703. labels: {
  1704. /**
  1705. * Defines how the labels are be repositioned according to the 3D
  1706. * chart orientation.
  1707. *
  1708. * - `'offset'`: Maintain a fixed horizontal/vertical distance from
  1709. * the tick marks, despite the chart orientation. This is the
  1710. * backwards compatible behavior, and causes skewing of X and Z
  1711. * axes.
  1712. *
  1713. * - `'chart'`: Preserve 3D position relative to the chart. This
  1714. * looks nice, but hard to read if the text isn't forward-facing.
  1715. *
  1716. * - `'flap'`: Rotated text along the axis to compensate for the
  1717. * chart orientation. This tries to maintain text as legible as
  1718. * possible on all orientations.
  1719. *
  1720. * - `'ortho'`: Rotated text along the axis direction so that the
  1721. * labels are orthogonal to the axis. This is very similar to
  1722. * `'flap'`, but prevents skewing the labels (X and Y scaling are
  1723. * still present).
  1724. *
  1725. * @sample highcharts/3d/skewed-labels/
  1726. * Skewed labels
  1727. *
  1728. * @since 5.0.15
  1729. * @validvalue ['offset', 'chart', 'flap', 'ortho']
  1730. * @product highcharts
  1731. * @requires highcharts-3d
  1732. */
  1733. position3d: 'offset',
  1734. /**
  1735. * If enabled, the axis labels will skewed to follow the
  1736. * perspective.
  1737. *
  1738. * This will fix overlapping labels and titles, but texts become
  1739. * less legible due to the distortion.
  1740. *
  1741. * The final appearance depends heavily on `labels.position3d`.
  1742. *
  1743. * @sample highcharts/3d/skewed-labels/
  1744. * Skewed labels
  1745. *
  1746. * @since 5.0.15
  1747. * @product highcharts
  1748. * @requires highcharts-3d
  1749. */
  1750. skew3d: false
  1751. },
  1752. title: {
  1753. /**
  1754. * Defines how the title is repositioned according to the 3D chart
  1755. * orientation.
  1756. *
  1757. * - `'offset'`: Maintain a fixed horizontal/vertical distance from
  1758. * the tick marks, despite the chart orientation. This is the
  1759. * backwards compatible behavior, and causes skewing of X and Z
  1760. * axes.
  1761. *
  1762. * - `'chart'`: Preserve 3D position relative to the chart. This
  1763. * looks nice, but hard to read if the text isn't forward-facing.
  1764. *
  1765. * - `'flap'`: Rotated text along the axis to compensate for the
  1766. * chart orientation. This tries to maintain text as legible as
  1767. * possible on all orientations.
  1768. *
  1769. * - `'ortho'`: Rotated text along the axis direction so that the
  1770. * labels are orthogonal to the axis. This is very similar to
  1771. * `'flap'`, but prevents skewing the labels (X and Y scaling are
  1772. * still present).
  1773. *
  1774. * - `undefined`: Will use the config from `labels.position3d`
  1775. *
  1776. * @sample highcharts/3d/skewed-labels/
  1777. * Skewed labels
  1778. *
  1779. * @type {"offset"|"chart"|"flap"|"ortho"|null}
  1780. * @since 5.0.15
  1781. * @product highcharts
  1782. * @requires highcharts-3d
  1783. */
  1784. position3d: null,
  1785. /**
  1786. * If enabled, the axis title will skewed to follow the perspective.
  1787. *
  1788. * This will fix overlapping labels and titles, but texts become
  1789. * less legible due to the distortion.
  1790. *
  1791. * The final appearance depends heavily on `title.position3d`.
  1792. *
  1793. * A `null` value will use the config from `labels.skew3d`.
  1794. *
  1795. * @sample highcharts/3d/skewed-labels/
  1796. * Skewed labels
  1797. *
  1798. * @type {boolean|null}
  1799. * @since 5.0.15
  1800. * @product highcharts
  1801. * @requires highcharts-3d
  1802. */
  1803. skew3d: null
  1804. }
  1805. };
  1806. return Axis3D;
  1807. }());
  1808. return Axis3D;
  1809. });
  1810. _registerModule(_modules, 'parts-3d/ZAxis.js', [_modules['parts/Axis.js'], _modules['parts/Utilities.js']], function (Axis, U) {
  1811. /* *
  1812. *
  1813. * (c) 2010-2020 Torstein Honsi
  1814. *
  1815. * License: www.highcharts.com/license
  1816. *
  1817. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1818. *
  1819. * */
  1820. var __extends = (this && this.__extends) || (function () {
  1821. var extendStatics = function (d, b) {
  1822. extendStatics = Object.setPrototypeOf ||
  1823. ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
  1824. function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
  1825. return extendStatics(d, b);
  1826. };
  1827. return function (d, b) {
  1828. extendStatics(d, b);
  1829. function __() { this.constructor = d; }
  1830. d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
  1831. };
  1832. })();
  1833. var addEvent = U.addEvent, merge = U.merge, pick = U.pick, splat = U.splat;
  1834. /* eslint-disable valid-jsdoc */
  1835. /**
  1836. * 3D chart with support of z coordinates.
  1837. * @private
  1838. * @class
  1839. */
  1840. var ZChart = /** @class */ (function () {
  1841. function ZChart() {
  1842. }
  1843. /* *
  1844. *
  1845. * Static Functions
  1846. *
  1847. * */
  1848. ZChart.compose = function (ChartClass) {
  1849. addEvent(ChartClass, 'afterGetAxes', ZChart.onAfterGetAxes);
  1850. var chartProto = ChartClass.prototype;
  1851. chartProto.addZAxis = ZChart.wrapAddZAxis;
  1852. chartProto.collectionsWithInit.zAxis = [chartProto.addZAxis];
  1853. chartProto.collectionsWithUpdate.push('zAxis');
  1854. };
  1855. /**
  1856. * Get the Z axis in addition to the default X and Y.
  1857. * @private
  1858. */
  1859. ZChart.onAfterGetAxes = function () {
  1860. var chart = this;
  1861. var options = this.options;
  1862. var zAxisOptions = options.zAxis = splat(options.zAxis || {});
  1863. if (!chart.is3d()) {
  1864. return;
  1865. }
  1866. chart.zAxis = [];
  1867. zAxisOptions.forEach(function (axisOptions, i) {
  1868. axisOptions.index = i;
  1869. // Z-Axis is shown horizontally, so it's kind of a X-Axis
  1870. axisOptions.isX = true;
  1871. chart
  1872. .addZAxis(axisOptions)
  1873. .setScale();
  1874. });
  1875. };
  1876. /**
  1877. * @private
  1878. */
  1879. ZChart.wrapAddZAxis = function (options) {
  1880. return new ZAxis(this, options);
  1881. };
  1882. return ZChart;
  1883. }());
  1884. /**
  1885. * 3D axis for z coordinates.
  1886. */
  1887. var ZAxis = /** @class */ (function (_super) {
  1888. __extends(ZAxis, _super);
  1889. /* *
  1890. *
  1891. * Constructors
  1892. *
  1893. * */
  1894. function ZAxis(chart, userOptions) {
  1895. var _this = _super.call(this, chart, userOptions) || this;
  1896. _this.isZAxis = true;
  1897. return _this;
  1898. }
  1899. /* *
  1900. *
  1901. * Functions
  1902. *
  1903. * */
  1904. ZAxis.prototype.getSeriesExtremes = function () {
  1905. var axis = this;
  1906. var chart = axis.chart;
  1907. axis.hasVisibleSeries = false;
  1908. // Reset properties in case we're redrawing (#3353)
  1909. axis.dataMin = axis.dataMax = axis.ignoreMinPadding = axis.ignoreMaxPadding = void 0;
  1910. if (axis.stacking) {
  1911. axis.stacking.buildStacks();
  1912. }
  1913. // loop through this axis' series
  1914. axis.series.forEach(function (series) {
  1915. if (series.visible ||
  1916. !(chart.options.chart &&
  1917. chart.options.chart.ignoreHiddenSeries)) {
  1918. var seriesOptions = series.options, zData, threshold = seriesOptions.threshold;
  1919. axis.hasVisibleSeries = true;
  1920. // Validate threshold in logarithmic axes
  1921. if (axis.positiveValuesOnly && threshold <= 0) {
  1922. threshold = void 0;
  1923. }
  1924. zData = series.zData;
  1925. if (zData.length) {
  1926. axis.dataMin = Math.min(pick(axis.dataMin, zData[0]), Math.min.apply(null, zData));
  1927. axis.dataMax = Math.max(pick(axis.dataMax, zData[0]), Math.max.apply(null, zData));
  1928. }
  1929. }
  1930. });
  1931. };
  1932. /**
  1933. * @private
  1934. */
  1935. ZAxis.prototype.setAxisSize = function () {
  1936. var axis = this;
  1937. var chart = axis.chart;
  1938. _super.prototype.setAxisSize.call(this);
  1939. axis.width = axis.len = (chart.options.chart &&
  1940. chart.options.chart.options3d &&
  1941. chart.options.chart.options3d.depth) || 0;
  1942. axis.right = chart.chartWidth - axis.width - axis.left;
  1943. };
  1944. /**
  1945. * @private
  1946. */
  1947. ZAxis.prototype.setOptions = function (userOptions) {
  1948. userOptions = merge({
  1949. offset: 0,
  1950. lineWidth: 0
  1951. }, userOptions);
  1952. _super.prototype.setOptions.call(this, userOptions);
  1953. this.coll = 'zAxis';
  1954. };
  1955. /* *
  1956. *
  1957. * Static Properties
  1958. *
  1959. * */
  1960. ZAxis.ZChartComposition = ZChart;
  1961. return ZAxis;
  1962. }(Axis));
  1963. return ZAxis;
  1964. });
  1965. _registerModule(_modules, 'parts-3d/Chart3D.js', [_modules['parts/Axis.js'], _modules['parts-3d/Axis3D.js'], _modules['parts/Chart.js'], _modules['parts/Globals.js'], _modules['parts/Options.js'], _modules['parts/Utilities.js'], _modules['parts-3d/ZAxis.js']], function (Axis, Axis3D, Chart, H, O, U, ZAxis) {
  1966. /* *
  1967. *
  1968. * (c) 2010-2020 Torstein Honsi
  1969. *
  1970. * Extension for 3D charts
  1971. *
  1972. * License: www.highcharts.com/license
  1973. *
  1974. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1975. *
  1976. * */
  1977. var genericDefaultOptions = O.defaultOptions;
  1978. var addEvent = U.addEvent, Fx = U.Fx, isArray = U.isArray, merge = U.merge, pick = U.pick, wrap = U.wrap;
  1979. var perspective = H.perspective;
  1980. var Chart3D;
  1981. (function (Chart3D) {
  1982. /* *
  1983. *
  1984. * Interfaces
  1985. *
  1986. * */
  1987. /* *
  1988. *
  1989. * Classes
  1990. *
  1991. * */
  1992. var Composition = /** @class */ (function () {
  1993. /* *
  1994. *
  1995. * Constructors
  1996. *
  1997. * */
  1998. /**
  1999. * @private
  2000. */
  2001. function Composition(chart) {
  2002. this.frame3d = void 0;
  2003. this.chart = chart;
  2004. }
  2005. /* *
  2006. *
  2007. * Functions
  2008. *
  2009. * */
  2010. Composition.prototype.get3dFrame = function () {
  2011. var chart = this.chart, options3d = chart.options.chart.options3d, frameOptions = options3d.frame, xm = chart.plotLeft, xp = chart.plotLeft + chart.plotWidth, ym = chart.plotTop, yp = chart.plotTop + chart.plotHeight, zm = 0, zp = options3d.depth, faceOrientation = function (vertexes) {
  2012. var area = H.shapeArea3d(vertexes, chart);
  2013. // Give it 0.5 squared-pixel as a margin for rounding errors
  2014. if (area > 0.5) {
  2015. return 1;
  2016. }
  2017. if (area < -0.5) {
  2018. return -1;
  2019. }
  2020. return 0;
  2021. }, bottomOrientation = faceOrientation([
  2022. { x: xm, y: yp, z: zp },
  2023. { x: xp, y: yp, z: zp },
  2024. { x: xp, y: yp, z: zm },
  2025. { x: xm, y: yp, z: zm }
  2026. ]), topOrientation = faceOrientation([
  2027. { x: xm, y: ym, z: zm },
  2028. { x: xp, y: ym, z: zm },
  2029. { x: xp, y: ym, z: zp },
  2030. { x: xm, y: ym, z: zp }
  2031. ]), leftOrientation = faceOrientation([
  2032. { x: xm, y: ym, z: zm },
  2033. { x: xm, y: ym, z: zp },
  2034. { x: xm, y: yp, z: zp },
  2035. { x: xm, y: yp, z: zm }
  2036. ]), rightOrientation = faceOrientation([
  2037. { x: xp, y: ym, z: zp },
  2038. { x: xp, y: ym, z: zm },
  2039. { x: xp, y: yp, z: zm },
  2040. { x: xp, y: yp, z: zp }
  2041. ]), frontOrientation = faceOrientation([
  2042. { x: xm, y: yp, z: zm },
  2043. { x: xp, y: yp, z: zm },
  2044. { x: xp, y: ym, z: zm },
  2045. { x: xm, y: ym, z: zm }
  2046. ]), backOrientation = faceOrientation([
  2047. { x: xm, y: ym, z: zp },
  2048. { x: xp, y: ym, z: zp },
  2049. { x: xp, y: yp, z: zp },
  2050. { x: xm, y: yp, z: zp }
  2051. ]), defaultShowBottom = false, defaultShowTop = false, defaultShowLeft = false, defaultShowRight = false, defaultShowFront = false, defaultShowBack = true;
  2052. // The 'default' criteria to visible faces of the frame is looking
  2053. // up every axis to decide whenever the left/right//top/bottom sides
  2054. // of the frame will be shown
  2055. []
  2056. .concat(chart.xAxis, chart.yAxis, chart.zAxis)
  2057. .forEach(function (axis) {
  2058. if (axis) {
  2059. if (axis.horiz) {
  2060. if (axis.opposite) {
  2061. defaultShowTop = true;
  2062. }
  2063. else {
  2064. defaultShowBottom = true;
  2065. }
  2066. }
  2067. else {
  2068. if (axis.opposite) {
  2069. defaultShowRight = true;
  2070. }
  2071. else {
  2072. defaultShowLeft = true;
  2073. }
  2074. }
  2075. }
  2076. });
  2077. var getFaceOptions = function (sources, faceOrientation, defaultVisible) {
  2078. var faceAttrs = ['size', 'color', 'visible'];
  2079. var options = {};
  2080. for (var i = 0; i < faceAttrs.length; i++) {
  2081. var attr = faceAttrs[i];
  2082. for (var j = 0; j < sources.length; j++) {
  2083. if (typeof sources[j] === 'object') {
  2084. var val = sources[j][attr];
  2085. if (typeof val !== 'undefined' && val !== null) {
  2086. options[attr] = val;
  2087. break;
  2088. }
  2089. }
  2090. }
  2091. }
  2092. var isVisible = defaultVisible;
  2093. if (options.visible === true || options.visible === false) {
  2094. isVisible = options.visible;
  2095. }
  2096. else if (options.visible === 'auto') {
  2097. isVisible = faceOrientation > 0;
  2098. }
  2099. return {
  2100. size: pick(options.size, 1),
  2101. color: pick(options.color, 'none'),
  2102. frontFacing: faceOrientation > 0,
  2103. visible: isVisible
  2104. };
  2105. };
  2106. // docs @TODO: Add all frame options (left, right, top, bottom,
  2107. // front, back) to apioptions JSDoc once the new system is up.
  2108. var ret = {
  2109. axes: {},
  2110. // FIXME: Previously, left/right, top/bottom and front/back
  2111. // pairs shared size and color.
  2112. // For compatibility and consistency sake, when one face have
  2113. // size/color/visibility set, the opposite face will default to
  2114. // the same values. Also, left/right used to be called 'side',
  2115. // so that's also added as a fallback.
  2116. bottom: getFaceOptions([frameOptions.bottom, frameOptions.top, frameOptions], bottomOrientation, defaultShowBottom),
  2117. top: getFaceOptions([frameOptions.top, frameOptions.bottom, frameOptions], topOrientation, defaultShowTop),
  2118. left: getFaceOptions([
  2119. frameOptions.left,
  2120. frameOptions.right,
  2121. frameOptions.side,
  2122. frameOptions
  2123. ], leftOrientation, defaultShowLeft),
  2124. right: getFaceOptions([
  2125. frameOptions.right,
  2126. frameOptions.left,
  2127. frameOptions.side,
  2128. frameOptions
  2129. ], rightOrientation, defaultShowRight),
  2130. back: getFaceOptions([frameOptions.back, frameOptions.front, frameOptions], backOrientation, defaultShowBack),
  2131. front: getFaceOptions([frameOptions.front, frameOptions.back, frameOptions], frontOrientation, defaultShowFront)
  2132. };
  2133. // Decide the bast place to put axis title/labels based on the
  2134. // visible faces. Ideally, The labels can only be on the edge
  2135. // between a visible face and an invisble one. Also, the Y label
  2136. // should be one the left-most edge (right-most if opposite).
  2137. if (options3d.axisLabelPosition === 'auto') {
  2138. var isValidEdge = function (face1, face2) {
  2139. return ((face1.visible !== face2.visible) ||
  2140. (face1.visible &&
  2141. face2.visible &&
  2142. (face1.frontFacing !== face2.frontFacing)));
  2143. };
  2144. var yEdges = [];
  2145. if (isValidEdge(ret.left, ret.front)) {
  2146. yEdges.push({
  2147. y: (ym + yp) / 2,
  2148. x: xm,
  2149. z: zm,
  2150. xDir: { x: 1, y: 0, z: 0 }
  2151. });
  2152. }
  2153. if (isValidEdge(ret.left, ret.back)) {
  2154. yEdges.push({
  2155. y: (ym + yp) / 2,
  2156. x: xm,
  2157. z: zp,
  2158. xDir: { x: 0, y: 0, z: -1 }
  2159. });
  2160. }
  2161. if (isValidEdge(ret.right, ret.front)) {
  2162. yEdges.push({
  2163. y: (ym + yp) / 2,
  2164. x: xp,
  2165. z: zm,
  2166. xDir: { x: 0, y: 0, z: 1 }
  2167. });
  2168. }
  2169. if (isValidEdge(ret.right, ret.back)) {
  2170. yEdges.push({
  2171. y: (ym + yp) / 2,
  2172. x: xp,
  2173. z: zp,
  2174. xDir: { x: -1, y: 0, z: 0 }
  2175. });
  2176. }
  2177. var xBottomEdges = [];
  2178. if (isValidEdge(ret.bottom, ret.front)) {
  2179. xBottomEdges.push({
  2180. x: (xm + xp) / 2,
  2181. y: yp,
  2182. z: zm,
  2183. xDir: { x: 1, y: 0, z: 0 }
  2184. });
  2185. }
  2186. if (isValidEdge(ret.bottom, ret.back)) {
  2187. xBottomEdges.push({
  2188. x: (xm + xp) / 2,
  2189. y: yp,
  2190. z: zp,
  2191. xDir: { x: -1, y: 0, z: 0 }
  2192. });
  2193. }
  2194. var xTopEdges = [];
  2195. if (isValidEdge(ret.top, ret.front)) {
  2196. xTopEdges.push({
  2197. x: (xm + xp) / 2,
  2198. y: ym,
  2199. z: zm,
  2200. xDir: { x: 1, y: 0, z: 0 }
  2201. });
  2202. }
  2203. if (isValidEdge(ret.top, ret.back)) {
  2204. xTopEdges.push({
  2205. x: (xm + xp) / 2,
  2206. y: ym,
  2207. z: zp,
  2208. xDir: { x: -1, y: 0, z: 0 }
  2209. });
  2210. }
  2211. var zBottomEdges = [];
  2212. if (isValidEdge(ret.bottom, ret.left)) {
  2213. zBottomEdges.push({
  2214. z: (zm + zp) / 2,
  2215. y: yp,
  2216. x: xm,
  2217. xDir: { x: 0, y: 0, z: -1 }
  2218. });
  2219. }
  2220. if (isValidEdge(ret.bottom, ret.right)) {
  2221. zBottomEdges.push({
  2222. z: (zm + zp) / 2,
  2223. y: yp,
  2224. x: xp,
  2225. xDir: { x: 0, y: 0, z: 1 }
  2226. });
  2227. }
  2228. var zTopEdges = [];
  2229. if (isValidEdge(ret.top, ret.left)) {
  2230. zTopEdges.push({
  2231. z: (zm + zp) / 2,
  2232. y: ym,
  2233. x: xm,
  2234. xDir: { x: 0, y: 0, z: -1 }
  2235. });
  2236. }
  2237. if (isValidEdge(ret.top, ret.right)) {
  2238. zTopEdges.push({
  2239. z: (zm + zp) / 2,
  2240. y: ym,
  2241. x: xp,
  2242. xDir: { x: 0, y: 0, z: 1 }
  2243. });
  2244. }
  2245. var pickEdge = function (edges, axis, mult) {
  2246. if (edges.length === 0) {
  2247. return null;
  2248. }
  2249. if (edges.length === 1) {
  2250. return edges[0];
  2251. }
  2252. var best = 0, projections = perspective(edges, chart, false);
  2253. for (var i = 1; i < projections.length; i++) {
  2254. if (mult * projections[i][axis] >
  2255. mult * projections[best][axis]) {
  2256. best = i;
  2257. }
  2258. else if ((mult * projections[i][axis] ===
  2259. mult * projections[best][axis]) &&
  2260. (projections[i].z < projections[best].z)) {
  2261. best = i;
  2262. }
  2263. }
  2264. return edges[best];
  2265. };
  2266. ret.axes = {
  2267. y: {
  2268. 'left': pickEdge(yEdges, 'x', -1),
  2269. 'right': pickEdge(yEdges, 'x', +1)
  2270. },
  2271. x: {
  2272. 'top': pickEdge(xTopEdges, 'y', -1),
  2273. 'bottom': pickEdge(xBottomEdges, 'y', +1)
  2274. },
  2275. z: {
  2276. 'top': pickEdge(zTopEdges, 'y', -1),
  2277. 'bottom': pickEdge(zBottomEdges, 'y', +1)
  2278. }
  2279. };
  2280. }
  2281. else {
  2282. ret.axes = {
  2283. y: {
  2284. 'left': { x: xm, z: zm, xDir: { x: 1, y: 0, z: 0 } },
  2285. 'right': { x: xp, z: zm, xDir: { x: 0, y: 0, z: 1 } }
  2286. },
  2287. x: {
  2288. 'top': { y: ym, z: zm, xDir: { x: 1, y: 0, z: 0 } },
  2289. 'bottom': { y: yp, z: zm, xDir: { x: 1, y: 0, z: 0 } }
  2290. },
  2291. z: {
  2292. 'top': {
  2293. x: defaultShowLeft ? xp : xm,
  2294. y: ym,
  2295. xDir: defaultShowLeft ?
  2296. { x: 0, y: 0, z: 1 } :
  2297. { x: 0, y: 0, z: -1 }
  2298. },
  2299. 'bottom': {
  2300. x: defaultShowLeft ? xp : xm,
  2301. y: yp,
  2302. xDir: defaultShowLeft ?
  2303. { x: 0, y: 0, z: 1 } :
  2304. { x: 0, y: 0, z: -1 }
  2305. }
  2306. }
  2307. };
  2308. }
  2309. return ret;
  2310. };
  2311. /**
  2312. * Calculate scale of the 3D view. That is required to fit chart's 3D
  2313. * projection into the actual plotting area. Reported as #4933.
  2314. *
  2315. * @notice
  2316. * This function should ideally take the plot values instead of a chart
  2317. * object, but since the chart object is needed for perspective it is
  2318. * not practical. Possible to make both getScale and perspective more
  2319. * logical and also immutable.
  2320. *
  2321. * @private
  2322. * @function getScale
  2323. *
  2324. * @param {number} depth
  2325. * The depth of the chart
  2326. *
  2327. * @return {number}
  2328. * The scale to fit the 3D chart into the plotting area.
  2329. *
  2330. * @requires highcharts-3d
  2331. */
  2332. Composition.prototype.getScale = function (depth) {
  2333. var chart = this.chart, plotLeft = chart.plotLeft, plotRight = chart.plotWidth + plotLeft, plotTop = chart.plotTop, plotBottom = chart.plotHeight + plotTop, originX = plotLeft + chart.plotWidth / 2, originY = plotTop + chart.plotHeight / 2, bbox3d = {
  2334. minX: Number.MAX_VALUE,
  2335. maxX: -Number.MAX_VALUE,
  2336. minY: Number.MAX_VALUE,
  2337. maxY: -Number.MAX_VALUE
  2338. }, corners, scale = 1;
  2339. // Top left corners:
  2340. corners = [{
  2341. x: plotLeft,
  2342. y: plotTop,
  2343. z: 0
  2344. }, {
  2345. x: plotLeft,
  2346. y: plotTop,
  2347. z: depth
  2348. }];
  2349. // Top right corners:
  2350. [0, 1].forEach(function (i) {
  2351. corners.push({
  2352. x: plotRight,
  2353. y: corners[i].y,
  2354. z: corners[i].z
  2355. });
  2356. });
  2357. // All bottom corners:
  2358. [0, 1, 2, 3].forEach(function (i) {
  2359. corners.push({
  2360. x: corners[i].x,
  2361. y: plotBottom,
  2362. z: corners[i].z
  2363. });
  2364. });
  2365. // Calculate 3D corners:
  2366. corners = perspective(corners, chart, false);
  2367. // Get bounding box of 3D element:
  2368. corners.forEach(function (corner) {
  2369. bbox3d.minX = Math.min(bbox3d.minX, corner.x);
  2370. bbox3d.maxX = Math.max(bbox3d.maxX, corner.x);
  2371. bbox3d.minY = Math.min(bbox3d.minY, corner.y);
  2372. bbox3d.maxY = Math.max(bbox3d.maxY, corner.y);
  2373. });
  2374. // Left edge:
  2375. if (plotLeft > bbox3d.minX) {
  2376. scale = Math.min(scale, 1 - Math.abs((plotLeft + originX) / (bbox3d.minX + originX)) % 1);
  2377. }
  2378. // Right edge:
  2379. if (plotRight < bbox3d.maxX) {
  2380. scale = Math.min(scale, (plotRight - originX) / (bbox3d.maxX - originX));
  2381. }
  2382. // Top edge:
  2383. if (plotTop > bbox3d.minY) {
  2384. if (bbox3d.minY < 0) {
  2385. scale = Math.min(scale, (plotTop + originY) / (-bbox3d.minY + plotTop + originY));
  2386. }
  2387. else {
  2388. scale = Math.min(scale, 1 - (plotTop + originY) / (bbox3d.minY + originY) % 1);
  2389. }
  2390. }
  2391. // Bottom edge:
  2392. if (plotBottom < bbox3d.maxY) {
  2393. scale = Math.min(scale, Math.abs((plotBottom - originY) / (bbox3d.maxY - originY)));
  2394. }
  2395. return scale;
  2396. };
  2397. return Composition;
  2398. }());
  2399. Chart3D.Composition = Composition;
  2400. /* *
  2401. *
  2402. * Constants
  2403. *
  2404. * */
  2405. /**
  2406. * @optionparent
  2407. * @private
  2408. */
  2409. Chart3D.defaultOptions = {
  2410. chart: {
  2411. /**
  2412. * Options to render charts in 3 dimensions. This feature requires
  2413. * `highcharts-3d.js`, found in the download package or online at
  2414. * [code.highcharts.com/highcharts-3d.js](https://code.highcharts.com/highcharts-3d.js).
  2415. *
  2416. * @since 4.0
  2417. * @product highcharts
  2418. * @requires highcharts-3d
  2419. */
  2420. options3d: {
  2421. /**
  2422. * Wether to render the chart using the 3D functionality.
  2423. *
  2424. * @since 4.0
  2425. * @product highcharts
  2426. */
  2427. enabled: false,
  2428. /**
  2429. * One of the two rotation angles for the chart.
  2430. *
  2431. * @since 4.0
  2432. * @product highcharts
  2433. */
  2434. alpha: 0,
  2435. /**
  2436. * One of the two rotation angles for the chart.
  2437. *
  2438. * @since 4.0
  2439. * @product highcharts
  2440. */
  2441. beta: 0,
  2442. /**
  2443. * The total depth of the chart.
  2444. *
  2445. * @since 4.0
  2446. * @product highcharts
  2447. */
  2448. depth: 100,
  2449. /**
  2450. * Whether the 3d box should automatically adjust to the chart
  2451. * plot area.
  2452. *
  2453. * @since 4.2.4
  2454. * @product highcharts
  2455. */
  2456. fitToPlot: true,
  2457. /**
  2458. * Defines the distance the viewer is standing in front of the
  2459. * chart, this setting is important to calculate the perspective
  2460. * effect in column and scatter charts. It is not used for 3D
  2461. * pie charts.
  2462. *
  2463. * @since 4.0
  2464. * @product highcharts
  2465. */
  2466. viewDistance: 25,
  2467. /**
  2468. * Set it to `"auto"` to automatically move the labels to the
  2469. * best edge.
  2470. *
  2471. * @type {"auto"|null}
  2472. * @since 5.0.12
  2473. * @product highcharts
  2474. */
  2475. axisLabelPosition: null,
  2476. /**
  2477. * Provides the option to draw a frame around the charts by
  2478. * defining a bottom, front and back panel.
  2479. *
  2480. * @since 4.0
  2481. * @product highcharts
  2482. * @requires highcharts-3d
  2483. */
  2484. frame: {
  2485. /**
  2486. * Whether the frames are visible.
  2487. */
  2488. visible: 'default',
  2489. /**
  2490. * General pixel thickness for the frame faces.
  2491. */
  2492. size: 1,
  2493. /**
  2494. * The bottom of the frame around a 3D chart.
  2495. *
  2496. * @since 4.0
  2497. * @product highcharts
  2498. * @requires highcharts-3d
  2499. */
  2500. /**
  2501. * The color of the panel.
  2502. *
  2503. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  2504. * @default transparent
  2505. * @since 4.0
  2506. * @product highcharts
  2507. * @apioption chart.options3d.frame.bottom.color
  2508. */
  2509. /**
  2510. * The thickness of the panel.
  2511. *
  2512. * @type {number}
  2513. * @default 1
  2514. * @since 4.0
  2515. * @product highcharts
  2516. * @apioption chart.options3d.frame.bottom.size
  2517. */
  2518. /**
  2519. * Whether to display the frame. Possible values are `true`,
  2520. * `false`, `"auto"` to display only the frames behind the
  2521. * data, and `"default"` to display faces behind the data
  2522. * based on the axis layout, ignoring the point of view.
  2523. *
  2524. * @sample {highcharts} highcharts/3d/scatter-frame/
  2525. * Auto frames
  2526. *
  2527. * @type {boolean|"default"|"auto"}
  2528. * @default default
  2529. * @since 5.0.12
  2530. * @product highcharts
  2531. * @apioption chart.options3d.frame.bottom.visible
  2532. */
  2533. /**
  2534. * The bottom of the frame around a 3D chart.
  2535. */
  2536. bottom: {},
  2537. /**
  2538. * The top of the frame around a 3D chart.
  2539. *
  2540. * @extends chart.options3d.frame.bottom
  2541. */
  2542. top: {},
  2543. /**
  2544. * The left side of the frame around a 3D chart.
  2545. *
  2546. * @extends chart.options3d.frame.bottom
  2547. */
  2548. left: {},
  2549. /**
  2550. * The right of the frame around a 3D chart.
  2551. *
  2552. * @extends chart.options3d.frame.bottom
  2553. */
  2554. right: {},
  2555. /**
  2556. * The back side of the frame around a 3D chart.
  2557. *
  2558. * @extends chart.options3d.frame.bottom
  2559. */
  2560. back: {},
  2561. /**
  2562. * The front of the frame around a 3D chart.
  2563. *
  2564. * @extends chart.options3d.frame.bottom
  2565. */
  2566. front: {}
  2567. }
  2568. }
  2569. }
  2570. };
  2571. /* *
  2572. *
  2573. * Functions
  2574. *
  2575. * */
  2576. /**
  2577. * @private
  2578. */
  2579. function compose(ChartClass, FxClass) {
  2580. var chartProto = ChartClass.prototype;
  2581. var fxProto = FxClass.prototype;
  2582. /**
  2583. * Shorthand to check the is3d flag.
  2584. * @private
  2585. * @return {boolean}
  2586. * Whether it is a 3D chart.
  2587. */
  2588. chartProto.is3d = function () {
  2589. return (this.options.chart.options3d &&
  2590. this.options.chart.options3d.enabled); // #4280
  2591. };
  2592. chartProto.propsRequireDirtyBox.push('chart.options3d');
  2593. chartProto.propsRequireUpdateSeries.push('chart.options3d');
  2594. /**
  2595. * Animation setter for matrix property.
  2596. * @private
  2597. */
  2598. fxProto.matrixSetter = function () {
  2599. var interpolated;
  2600. if (this.pos < 1 &&
  2601. (isArray(this.start) || isArray(this.end))) {
  2602. var start = this.start || [1, 0, 0, 1, 0, 0];
  2603. var end = this.end || [1, 0, 0, 1, 0, 0];
  2604. interpolated = [];
  2605. for (var i = 0; i < 6; i++) {
  2606. interpolated.push(this.pos * end[i] + (1 - this.pos) * start[i]);
  2607. }
  2608. }
  2609. else {
  2610. interpolated = this.end;
  2611. }
  2612. this.elem.attr(this.prop, interpolated, null, true);
  2613. };
  2614. merge(true, genericDefaultOptions, Chart3D.defaultOptions);
  2615. addEvent(ChartClass, 'init', onInit);
  2616. addEvent(ChartClass, 'addSeries', onAddSeries);
  2617. addEvent(ChartClass, 'afterDrawChartBox', onAfterDrawChartBox);
  2618. addEvent(ChartClass, 'afterGetContainer', onAfterGetContainer);
  2619. addEvent(ChartClass, 'afterInit', onAfterInit);
  2620. addEvent(ChartClass, 'afterSetChartSize', onAfterSetChartSize);
  2621. addEvent(ChartClass, 'beforeRedraw', onBeforeRedraw);
  2622. addEvent(ChartClass, 'beforeRender', onBeforeRender);
  2623. wrap(H.Chart.prototype, 'isInsidePlot', wrapIsInsidePlot);
  2624. wrap(ChartClass, 'renderSeries', wrapRenderSeries);
  2625. wrap(ChartClass, 'setClassName', wrapSetClassName);
  2626. }
  2627. Chart3D.compose = compose;
  2628. /**
  2629. * Legacy support for HC < 6 to make 'scatter' series in a 3D chart route to
  2630. * the real 'scatter3d' series type. (#8407)
  2631. * @private
  2632. */
  2633. function onAddSeries(e) {
  2634. if (this.is3d()) {
  2635. if (e.options.type === 'scatter') {
  2636. e.options.type = 'scatter3d';
  2637. }
  2638. }
  2639. }
  2640. /**
  2641. * @private
  2642. */
  2643. function onAfterDrawChartBox() {
  2644. if (this.chart3d &&
  2645. this.is3d()) {
  2646. var chart = this, renderer = chart.renderer, options3d = this.options.chart.options3d, frame = this.chart3d.get3dFrame(), xm = this.plotLeft, xp = this.plotLeft + this.plotWidth, ym = this.plotTop, yp = this.plotTop + this.plotHeight, zm = 0, zp = options3d.depth, xmm = xm - (frame.left.visible ? frame.left.size : 0), xpp = xp + (frame.right.visible ? frame.right.size : 0), ymm = ym - (frame.top.visible ? frame.top.size : 0), ypp = yp + (frame.bottom.visible ? frame.bottom.size : 0), zmm = zm - (frame.front.visible ? frame.front.size : 0), zpp = zp + (frame.back.visible ? frame.back.size : 0), verb = chart.hasRendered ? 'animate' : 'attr';
  2647. this.chart3d.frame3d = frame;
  2648. if (!this.frameShapes) {
  2649. this.frameShapes = {
  2650. bottom: renderer.polyhedron().add(),
  2651. top: renderer.polyhedron().add(),
  2652. left: renderer.polyhedron().add(),
  2653. right: renderer.polyhedron().add(),
  2654. back: renderer.polyhedron().add(),
  2655. front: renderer.polyhedron().add()
  2656. };
  2657. }
  2658. this.frameShapes.bottom[verb]({
  2659. 'class': 'highcharts-3d-frame highcharts-3d-frame-bottom',
  2660. zIndex: frame.bottom.frontFacing ? -1000 : 1000,
  2661. faces: [{
  2662. fill: H.color(frame.bottom.color).brighten(0.1).get(),
  2663. vertexes: [{
  2664. x: xmm,
  2665. y: ypp,
  2666. z: zmm
  2667. }, {
  2668. x: xpp,
  2669. y: ypp,
  2670. z: zmm
  2671. }, {
  2672. x: xpp,
  2673. y: ypp,
  2674. z: zpp
  2675. }, {
  2676. x: xmm,
  2677. y: ypp,
  2678. z: zpp
  2679. }],
  2680. enabled: frame.bottom.visible
  2681. },
  2682. {
  2683. fill: H.color(frame.bottom.color).brighten(0.1).get(),
  2684. vertexes: [{
  2685. x: xm,
  2686. y: yp,
  2687. z: zp
  2688. }, {
  2689. x: xp,
  2690. y: yp,
  2691. z: zp
  2692. }, {
  2693. x: xp,
  2694. y: yp,
  2695. z: zm
  2696. }, {
  2697. x: xm,
  2698. y: yp,
  2699. z: zm
  2700. }],
  2701. enabled: frame.bottom.visible
  2702. },
  2703. {
  2704. fill: H.color(frame.bottom.color).brighten(-0.1).get(),
  2705. vertexes: [{
  2706. x: xmm,
  2707. y: ypp,
  2708. z: zmm
  2709. }, {
  2710. x: xmm,
  2711. y: ypp,
  2712. z: zpp
  2713. }, {
  2714. x: xm,
  2715. y: yp,
  2716. z: zp
  2717. }, {
  2718. x: xm,
  2719. y: yp,
  2720. z: zm
  2721. }],
  2722. enabled: frame.bottom.visible && !frame.left.visible
  2723. },
  2724. {
  2725. fill: H.color(frame.bottom.color).brighten(-0.1).get(),
  2726. vertexes: [{
  2727. x: xpp,
  2728. y: ypp,
  2729. z: zpp
  2730. }, {
  2731. x: xpp,
  2732. y: ypp,
  2733. z: zmm
  2734. }, {
  2735. x: xp,
  2736. y: yp,
  2737. z: zm
  2738. }, {
  2739. x: xp,
  2740. y: yp,
  2741. z: zp
  2742. }],
  2743. enabled: frame.bottom.visible && !frame.right.visible
  2744. },
  2745. {
  2746. fill: H.color(frame.bottom.color).get(),
  2747. vertexes: [{
  2748. x: xpp,
  2749. y: ypp,
  2750. z: zmm
  2751. }, {
  2752. x: xmm,
  2753. y: ypp,
  2754. z: zmm
  2755. }, {
  2756. x: xm,
  2757. y: yp,
  2758. z: zm
  2759. }, {
  2760. x: xp,
  2761. y: yp,
  2762. z: zm
  2763. }],
  2764. enabled: frame.bottom.visible && !frame.front.visible
  2765. },
  2766. {
  2767. fill: H.color(frame.bottom.color).get(),
  2768. vertexes: [{
  2769. x: xmm,
  2770. y: ypp,
  2771. z: zpp
  2772. }, {
  2773. x: xpp,
  2774. y: ypp,
  2775. z: zpp
  2776. }, {
  2777. x: xp,
  2778. y: yp,
  2779. z: zp
  2780. }, {
  2781. x: xm,
  2782. y: yp,
  2783. z: zp
  2784. }],
  2785. enabled: frame.bottom.visible && !frame.back.visible
  2786. }]
  2787. });
  2788. this.frameShapes.top[verb]({
  2789. 'class': 'highcharts-3d-frame highcharts-3d-frame-top',
  2790. zIndex: frame.top.frontFacing ? -1000 : 1000,
  2791. faces: [{
  2792. fill: H.color(frame.top.color).brighten(0.1).get(),
  2793. vertexes: [{
  2794. x: xmm,
  2795. y: ymm,
  2796. z: zpp
  2797. }, {
  2798. x: xpp,
  2799. y: ymm,
  2800. z: zpp
  2801. }, {
  2802. x: xpp,
  2803. y: ymm,
  2804. z: zmm
  2805. }, {
  2806. x: xmm,
  2807. y: ymm,
  2808. z: zmm
  2809. }],
  2810. enabled: frame.top.visible
  2811. },
  2812. {
  2813. fill: H.color(frame.top.color).brighten(0.1).get(),
  2814. vertexes: [{
  2815. x: xm,
  2816. y: ym,
  2817. z: zm
  2818. }, {
  2819. x: xp,
  2820. y: ym,
  2821. z: zm
  2822. }, {
  2823. x: xp,
  2824. y: ym,
  2825. z: zp
  2826. }, {
  2827. x: xm,
  2828. y: ym,
  2829. z: zp
  2830. }],
  2831. enabled: frame.top.visible
  2832. },
  2833. {
  2834. fill: H.color(frame.top.color).brighten(-0.1).get(),
  2835. vertexes: [{
  2836. x: xmm,
  2837. y: ymm,
  2838. z: zpp
  2839. }, {
  2840. x: xmm,
  2841. y: ymm,
  2842. z: zmm
  2843. }, {
  2844. x: xm,
  2845. y: ym,
  2846. z: zm
  2847. }, {
  2848. x: xm,
  2849. y: ym,
  2850. z: zp
  2851. }],
  2852. enabled: frame.top.visible && !frame.left.visible
  2853. },
  2854. {
  2855. fill: H.color(frame.top.color).brighten(-0.1).get(),
  2856. vertexes: [{
  2857. x: xpp,
  2858. y: ymm,
  2859. z: zmm
  2860. }, {
  2861. x: xpp,
  2862. y: ymm,
  2863. z: zpp
  2864. }, {
  2865. x: xp,
  2866. y: ym,
  2867. z: zp
  2868. }, {
  2869. x: xp,
  2870. y: ym,
  2871. z: zm
  2872. }],
  2873. enabled: frame.top.visible && !frame.right.visible
  2874. },
  2875. {
  2876. fill: H.color(frame.top.color).get(),
  2877. vertexes: [{
  2878. x: xmm,
  2879. y: ymm,
  2880. z: zmm
  2881. }, {
  2882. x: xpp,
  2883. y: ymm,
  2884. z: zmm
  2885. }, {
  2886. x: xp,
  2887. y: ym,
  2888. z: zm
  2889. }, {
  2890. x: xm,
  2891. y: ym,
  2892. z: zm
  2893. }],
  2894. enabled: frame.top.visible && !frame.front.visible
  2895. },
  2896. {
  2897. fill: H.color(frame.top.color).get(),
  2898. vertexes: [{
  2899. x: xpp,
  2900. y: ymm,
  2901. z: zpp
  2902. }, {
  2903. x: xmm,
  2904. y: ymm,
  2905. z: zpp
  2906. }, {
  2907. x: xm,
  2908. y: ym,
  2909. z: zp
  2910. }, {
  2911. x: xp,
  2912. y: ym,
  2913. z: zp
  2914. }],
  2915. enabled: frame.top.visible && !frame.back.visible
  2916. }]
  2917. });
  2918. this.frameShapes.left[verb]({
  2919. 'class': 'highcharts-3d-frame highcharts-3d-frame-left',
  2920. zIndex: frame.left.frontFacing ? -1000 : 1000,
  2921. faces: [{
  2922. fill: H.color(frame.left.color).brighten(0.1).get(),
  2923. vertexes: [{
  2924. x: xmm,
  2925. y: ypp,
  2926. z: zmm
  2927. }, {
  2928. x: xm,
  2929. y: yp,
  2930. z: zm
  2931. }, {
  2932. x: xm,
  2933. y: yp,
  2934. z: zp
  2935. }, {
  2936. x: xmm,
  2937. y: ypp,
  2938. z: zpp
  2939. }],
  2940. enabled: frame.left.visible && !frame.bottom.visible
  2941. },
  2942. {
  2943. fill: H.color(frame.left.color).brighten(0.1).get(),
  2944. vertexes: [{
  2945. x: xmm,
  2946. y: ymm,
  2947. z: zpp
  2948. }, {
  2949. x: xm,
  2950. y: ym,
  2951. z: zp
  2952. }, {
  2953. x: xm,
  2954. y: ym,
  2955. z: zm
  2956. }, {
  2957. x: xmm,
  2958. y: ymm,
  2959. z: zmm
  2960. }],
  2961. enabled: frame.left.visible && !frame.top.visible
  2962. },
  2963. {
  2964. fill: H.color(frame.left.color).brighten(-0.1).get(),
  2965. vertexes: [{
  2966. x: xmm,
  2967. y: ypp,
  2968. z: zpp
  2969. }, {
  2970. x: xmm,
  2971. y: ymm,
  2972. z: zpp
  2973. }, {
  2974. x: xmm,
  2975. y: ymm,
  2976. z: zmm
  2977. }, {
  2978. x: xmm,
  2979. y: ypp,
  2980. z: zmm
  2981. }],
  2982. enabled: frame.left.visible
  2983. },
  2984. {
  2985. fill: H.color(frame.left.color).brighten(-0.1).get(),
  2986. vertexes: [{
  2987. x: xm,
  2988. y: ym,
  2989. z: zp
  2990. }, {
  2991. x: xm,
  2992. y: yp,
  2993. z: zp
  2994. }, {
  2995. x: xm,
  2996. y: yp,
  2997. z: zm
  2998. }, {
  2999. x: xm,
  3000. y: ym,
  3001. z: zm
  3002. }],
  3003. enabled: frame.left.visible
  3004. },
  3005. {
  3006. fill: H.color(frame.left.color).get(),
  3007. vertexes: [{
  3008. x: xmm,
  3009. y: ypp,
  3010. z: zmm
  3011. }, {
  3012. x: xmm,
  3013. y: ymm,
  3014. z: zmm
  3015. }, {
  3016. x: xm,
  3017. y: ym,
  3018. z: zm
  3019. }, {
  3020. x: xm,
  3021. y: yp,
  3022. z: zm
  3023. }],
  3024. enabled: frame.left.visible && !frame.front.visible
  3025. },
  3026. {
  3027. fill: H.color(frame.left.color).get(),
  3028. vertexes: [{
  3029. x: xmm,
  3030. y: ymm,
  3031. z: zpp
  3032. }, {
  3033. x: xmm,
  3034. y: ypp,
  3035. z: zpp
  3036. }, {
  3037. x: xm,
  3038. y: yp,
  3039. z: zp
  3040. }, {
  3041. x: xm,
  3042. y: ym,
  3043. z: zp
  3044. }],
  3045. enabled: frame.left.visible && !frame.back.visible
  3046. }]
  3047. });
  3048. this.frameShapes.right[verb]({
  3049. 'class': 'highcharts-3d-frame highcharts-3d-frame-right',
  3050. zIndex: frame.right.frontFacing ? -1000 : 1000,
  3051. faces: [{
  3052. fill: H.color(frame.right.color).brighten(0.1).get(),
  3053. vertexes: [{
  3054. x: xpp,
  3055. y: ypp,
  3056. z: zpp
  3057. }, {
  3058. x: xp,
  3059. y: yp,
  3060. z: zp
  3061. }, {
  3062. x: xp,
  3063. y: yp,
  3064. z: zm
  3065. }, {
  3066. x: xpp,
  3067. y: ypp,
  3068. z: zmm
  3069. }],
  3070. enabled: frame.right.visible && !frame.bottom.visible
  3071. },
  3072. {
  3073. fill: H.color(frame.right.color).brighten(0.1).get(),
  3074. vertexes: [{
  3075. x: xpp,
  3076. y: ymm,
  3077. z: zmm
  3078. }, {
  3079. x: xp,
  3080. y: ym,
  3081. z: zm
  3082. }, {
  3083. x: xp,
  3084. y: ym,
  3085. z: zp
  3086. }, {
  3087. x: xpp,
  3088. y: ymm,
  3089. z: zpp
  3090. }],
  3091. enabled: frame.right.visible && !frame.top.visible
  3092. },
  3093. {
  3094. fill: H.color(frame.right.color).brighten(-0.1).get(),
  3095. vertexes: [{
  3096. x: xp,
  3097. y: ym,
  3098. z: zm
  3099. }, {
  3100. x: xp,
  3101. y: yp,
  3102. z: zm
  3103. }, {
  3104. x: xp,
  3105. y: yp,
  3106. z: zp
  3107. }, {
  3108. x: xp,
  3109. y: ym,
  3110. z: zp
  3111. }],
  3112. enabled: frame.right.visible
  3113. },
  3114. {
  3115. fill: H.color(frame.right.color).brighten(-0.1).get(),
  3116. vertexes: [{
  3117. x: xpp,
  3118. y: ypp,
  3119. z: zmm
  3120. }, {
  3121. x: xpp,
  3122. y: ymm,
  3123. z: zmm
  3124. }, {
  3125. x: xpp,
  3126. y: ymm,
  3127. z: zpp
  3128. }, {
  3129. x: xpp,
  3130. y: ypp,
  3131. z: zpp
  3132. }],
  3133. enabled: frame.right.visible
  3134. },
  3135. {
  3136. fill: H.color(frame.right.color).get(),
  3137. vertexes: [{
  3138. x: xpp,
  3139. y: ymm,
  3140. z: zmm
  3141. }, {
  3142. x: xpp,
  3143. y: ypp,
  3144. z: zmm
  3145. }, {
  3146. x: xp,
  3147. y: yp,
  3148. z: zm
  3149. }, {
  3150. x: xp,
  3151. y: ym,
  3152. z: zm
  3153. }],
  3154. enabled: frame.right.visible && !frame.front.visible
  3155. },
  3156. {
  3157. fill: H.color(frame.right.color).get(),
  3158. vertexes: [{
  3159. x: xpp,
  3160. y: ypp,
  3161. z: zpp
  3162. }, {
  3163. x: xpp,
  3164. y: ymm,
  3165. z: zpp
  3166. }, {
  3167. x: xp,
  3168. y: ym,
  3169. z: zp
  3170. }, {
  3171. x: xp,
  3172. y: yp,
  3173. z: zp
  3174. }],
  3175. enabled: frame.right.visible && !frame.back.visible
  3176. }]
  3177. });
  3178. this.frameShapes.back[verb]({
  3179. 'class': 'highcharts-3d-frame highcharts-3d-frame-back',
  3180. zIndex: frame.back.frontFacing ? -1000 : 1000,
  3181. faces: [{
  3182. fill: H.color(frame.back.color).brighten(0.1).get(),
  3183. vertexes: [{
  3184. x: xpp,
  3185. y: ypp,
  3186. z: zpp
  3187. }, {
  3188. x: xmm,
  3189. y: ypp,
  3190. z: zpp
  3191. }, {
  3192. x: xm,
  3193. y: yp,
  3194. z: zp
  3195. }, {
  3196. x: xp,
  3197. y: yp,
  3198. z: zp
  3199. }],
  3200. enabled: frame.back.visible && !frame.bottom.visible
  3201. },
  3202. {
  3203. fill: H.color(frame.back.color).brighten(0.1).get(),
  3204. vertexes: [{
  3205. x: xmm,
  3206. y: ymm,
  3207. z: zpp
  3208. }, {
  3209. x: xpp,
  3210. y: ymm,
  3211. z: zpp
  3212. }, {
  3213. x: xp,
  3214. y: ym,
  3215. z: zp
  3216. }, {
  3217. x: xm,
  3218. y: ym,
  3219. z: zp
  3220. }],
  3221. enabled: frame.back.visible && !frame.top.visible
  3222. },
  3223. {
  3224. fill: H.color(frame.back.color).brighten(-0.1).get(),
  3225. vertexes: [{
  3226. x: xmm,
  3227. y: ypp,
  3228. z: zpp
  3229. }, {
  3230. x: xmm,
  3231. y: ymm,
  3232. z: zpp
  3233. }, {
  3234. x: xm,
  3235. y: ym,
  3236. z: zp
  3237. }, {
  3238. x: xm,
  3239. y: yp,
  3240. z: zp
  3241. }],
  3242. enabled: frame.back.visible && !frame.left.visible
  3243. },
  3244. {
  3245. fill: H.color(frame.back.color).brighten(-0.1).get(),
  3246. vertexes: [{
  3247. x: xpp,
  3248. y: ymm,
  3249. z: zpp
  3250. }, {
  3251. x: xpp,
  3252. y: ypp,
  3253. z: zpp
  3254. }, {
  3255. x: xp,
  3256. y: yp,
  3257. z: zp
  3258. }, {
  3259. x: xp,
  3260. y: ym,
  3261. z: zp
  3262. }],
  3263. enabled: frame.back.visible && !frame.right.visible
  3264. },
  3265. {
  3266. fill: H.color(frame.back.color).get(),
  3267. vertexes: [{
  3268. x: xm,
  3269. y: ym,
  3270. z: zp
  3271. }, {
  3272. x: xp,
  3273. y: ym,
  3274. z: zp
  3275. }, {
  3276. x: xp,
  3277. y: yp,
  3278. z: zp
  3279. }, {
  3280. x: xm,
  3281. y: yp,
  3282. z: zp
  3283. }],
  3284. enabled: frame.back.visible
  3285. },
  3286. {
  3287. fill: H.color(frame.back.color).get(),
  3288. vertexes: [{
  3289. x: xmm,
  3290. y: ypp,
  3291. z: zpp
  3292. }, {
  3293. x: xpp,
  3294. y: ypp,
  3295. z: zpp
  3296. }, {
  3297. x: xpp,
  3298. y: ymm,
  3299. z: zpp
  3300. }, {
  3301. x: xmm,
  3302. y: ymm,
  3303. z: zpp
  3304. }],
  3305. enabled: frame.back.visible
  3306. }]
  3307. });
  3308. this.frameShapes.front[verb]({
  3309. 'class': 'highcharts-3d-frame highcharts-3d-frame-front',
  3310. zIndex: frame.front.frontFacing ? -1000 : 1000,
  3311. faces: [{
  3312. fill: H.color(frame.front.color).brighten(0.1).get(),
  3313. vertexes: [{
  3314. x: xmm,
  3315. y: ypp,
  3316. z: zmm
  3317. }, {
  3318. x: xpp,
  3319. y: ypp,
  3320. z: zmm
  3321. }, {
  3322. x: xp,
  3323. y: yp,
  3324. z: zm
  3325. }, {
  3326. x: xm,
  3327. y: yp,
  3328. z: zm
  3329. }],
  3330. enabled: frame.front.visible && !frame.bottom.visible
  3331. },
  3332. {
  3333. fill: H.color(frame.front.color).brighten(0.1).get(),
  3334. vertexes: [{
  3335. x: xpp,
  3336. y: ymm,
  3337. z: zmm
  3338. }, {
  3339. x: xmm,
  3340. y: ymm,
  3341. z: zmm
  3342. }, {
  3343. x: xm,
  3344. y: ym,
  3345. z: zm
  3346. }, {
  3347. x: xp,
  3348. y: ym,
  3349. z: zm
  3350. }],
  3351. enabled: frame.front.visible && !frame.top.visible
  3352. },
  3353. {
  3354. fill: H.color(frame.front.color).brighten(-0.1).get(),
  3355. vertexes: [{
  3356. x: xmm,
  3357. y: ymm,
  3358. z: zmm
  3359. }, {
  3360. x: xmm,
  3361. y: ypp,
  3362. z: zmm
  3363. }, {
  3364. x: xm,
  3365. y: yp,
  3366. z: zm
  3367. }, {
  3368. x: xm,
  3369. y: ym,
  3370. z: zm
  3371. }],
  3372. enabled: frame.front.visible && !frame.left.visible
  3373. },
  3374. {
  3375. fill: H.color(frame.front.color).brighten(-0.1).get(),
  3376. vertexes: [{
  3377. x: xpp,
  3378. y: ypp,
  3379. z: zmm
  3380. }, {
  3381. x: xpp,
  3382. y: ymm,
  3383. z: zmm
  3384. }, {
  3385. x: xp,
  3386. y: ym,
  3387. z: zm
  3388. }, {
  3389. x: xp,
  3390. y: yp,
  3391. z: zm
  3392. }],
  3393. enabled: frame.front.visible && !frame.right.visible
  3394. },
  3395. {
  3396. fill: H.color(frame.front.color).get(),
  3397. vertexes: [{
  3398. x: xp,
  3399. y: ym,
  3400. z: zm
  3401. }, {
  3402. x: xm,
  3403. y: ym,
  3404. z: zm
  3405. }, {
  3406. x: xm,
  3407. y: yp,
  3408. z: zm
  3409. }, {
  3410. x: xp,
  3411. y: yp,
  3412. z: zm
  3413. }],
  3414. enabled: frame.front.visible
  3415. },
  3416. {
  3417. fill: H.color(frame.front.color).get(),
  3418. vertexes: [{
  3419. x: xpp,
  3420. y: ypp,
  3421. z: zmm
  3422. }, {
  3423. x: xmm,
  3424. y: ypp,
  3425. z: zmm
  3426. }, {
  3427. x: xmm,
  3428. y: ymm,
  3429. z: zmm
  3430. }, {
  3431. x: xpp,
  3432. y: ymm,
  3433. z: zmm
  3434. }],
  3435. enabled: frame.front.visible
  3436. }]
  3437. });
  3438. }
  3439. }
  3440. /**
  3441. * Add the required CSS classes for column sides (#6018)
  3442. * @private
  3443. */
  3444. function onAfterGetContainer() {
  3445. if (this.styledMode) {
  3446. this.renderer.definition({
  3447. tagName: 'style',
  3448. textContent: '.highcharts-3d-top{' +
  3449. 'filter: url(#highcharts-brighter)' +
  3450. '}\n' +
  3451. '.highcharts-3d-side{' +
  3452. 'filter: url(#highcharts-darker)' +
  3453. '}\n'
  3454. });
  3455. // Add add definitions used by brighter and darker faces of the
  3456. // cuboids.
  3457. [{
  3458. name: 'darker',
  3459. slope: 0.6
  3460. }, {
  3461. name: 'brighter',
  3462. slope: 1.4
  3463. }].forEach(function (cfg) {
  3464. this.renderer.definition({
  3465. tagName: 'filter',
  3466. id: 'highcharts-' + cfg.name,
  3467. children: [{
  3468. tagName: 'feComponentTransfer',
  3469. children: [{
  3470. tagName: 'feFuncR',
  3471. type: 'linear',
  3472. slope: cfg.slope
  3473. }, {
  3474. tagName: 'feFuncG',
  3475. type: 'linear',
  3476. slope: cfg.slope
  3477. }, {
  3478. tagName: 'feFuncB',
  3479. type: 'linear',
  3480. slope: cfg.slope
  3481. }]
  3482. }]
  3483. });
  3484. }, this);
  3485. }
  3486. }
  3487. /**
  3488. * Legacy support for HC < 6 to make 'scatter' series in a 3D chart route to
  3489. * the real 'scatter3d' series type. (#8407)
  3490. * @private
  3491. */
  3492. function onAfterInit() {
  3493. var options = this.options;
  3494. if (this.is3d()) {
  3495. (options.series || []).forEach(function (s) {
  3496. var type = s.type ||
  3497. options.chart.type ||
  3498. options.chart.defaultSeriesType;
  3499. if (type === 'scatter') {
  3500. s.type = 'scatter3d';
  3501. }
  3502. });
  3503. }
  3504. }
  3505. /**
  3506. * @private
  3507. */
  3508. function onAfterSetChartSize() {
  3509. var chart = this, options3d = chart.options.chart.options3d;
  3510. if (chart.chart3d &&
  3511. chart.is3d()) {
  3512. // Add a 0-360 normalisation for alfa and beta angles in 3d graph
  3513. if (options3d) {
  3514. options3d.alpha = options3d.alpha % 360 + (options3d.alpha >= 0 ? 0 : 360);
  3515. options3d.beta = options3d.beta % 360 + (options3d.beta >= 0 ? 0 : 360);
  3516. }
  3517. var inverted = chart.inverted, clipBox = chart.clipBox, margin = chart.margin, x = inverted ? 'y' : 'x', y = inverted ? 'x' : 'y', w = inverted ? 'height' : 'width', h = inverted ? 'width' : 'height';
  3518. clipBox[x] = -(margin[3] || 0);
  3519. clipBox[y] = -(margin[0] || 0);
  3520. clipBox[w] =
  3521. chart.chartWidth + (margin[3] || 0) + (margin[1] || 0);
  3522. clipBox[h] =
  3523. chart.chartHeight + (margin[0] || 0) + (margin[2] || 0);
  3524. // Set scale, used later in perspective method():
  3525. // getScale uses perspective, so scale3d has to be reset.
  3526. chart.scale3d = 1;
  3527. if (options3d.fitToPlot === true) {
  3528. chart.scale3d = chart.chart3d.getScale(options3d.depth);
  3529. }
  3530. // Recalculate the 3d frame with every call of setChartSize,
  3531. // instead of doing it after every redraw(). It avoids ticks
  3532. // and axis title outside of chart.
  3533. chart.chart3d.frame3d = chart.chart3d.get3dFrame(); // #7942
  3534. }
  3535. }
  3536. /**
  3537. * @private
  3538. */
  3539. function onBeforeRedraw() {
  3540. if (this.is3d()) {
  3541. // Set to force a redraw of all elements
  3542. this.isDirtyBox = true;
  3543. }
  3544. }
  3545. /**
  3546. * @private
  3547. */
  3548. function onBeforeRender() {
  3549. if (this.chart3d && this.is3d()) {
  3550. this.chart3d.frame3d = this.chart3d.get3dFrame();
  3551. }
  3552. }
  3553. /**
  3554. * @private
  3555. */
  3556. function onInit() {
  3557. if (!this.chart3d) {
  3558. this.chart3d = new Composition(this);
  3559. }
  3560. }
  3561. /**
  3562. * @private
  3563. */
  3564. function wrapIsInsidePlot(proceed) {
  3565. return this.is3d() || proceed.apply(this, [].slice.call(arguments, 1));
  3566. }
  3567. /**
  3568. * Draw the series in the reverse order (#3803, #3917)
  3569. * @private
  3570. */
  3571. function wrapRenderSeries(proceed) {
  3572. var series, i = this.series.length;
  3573. if (this.is3d()) {
  3574. while (i--) {
  3575. series = this.series[i];
  3576. series.translate();
  3577. series.render();
  3578. }
  3579. }
  3580. else {
  3581. proceed.call(this);
  3582. }
  3583. }
  3584. /**
  3585. * @private
  3586. */
  3587. function wrapSetClassName(proceed) {
  3588. proceed.apply(this, [].slice.call(arguments, 1));
  3589. if (this.is3d()) {
  3590. this.container.className += ' highcharts-3d-chart';
  3591. }
  3592. }
  3593. })(Chart3D || (Chart3D = {}));
  3594. Chart3D.compose(Chart, Fx);
  3595. ZAxis.ZChartComposition.compose(Chart);
  3596. Axis3D.compose(Axis);
  3597. /**
  3598. * Note: As of v5.0.12, `frame.left` or `frame.right` should be used instead.
  3599. *
  3600. * The side for the frame around a 3D chart.
  3601. *
  3602. * @deprecated
  3603. * @since 4.0
  3604. * @product highcharts
  3605. * @requires highcharts-3d
  3606. * @apioption chart.options3d.frame.side
  3607. */
  3608. /**
  3609. * The color of the panel.
  3610. *
  3611. * @deprecated
  3612. * @type {Highcharts.ColorString|Highcharts.GradientColorObject|Highcharts.PatternObject}
  3613. * @default transparent
  3614. * @since 4.0
  3615. * @product highcharts
  3616. * @apioption chart.options3d.frame.side.color
  3617. */
  3618. /**
  3619. * The thickness of the panel.
  3620. *
  3621. * @deprecated
  3622. * @type {number}
  3623. * @default 1
  3624. * @since 4.0
  3625. * @product highcharts
  3626. * @apioption chart.options3d.frame.side.size
  3627. */
  3628. ''; // adds doclets above to transpiled file
  3629. return Chart3D;
  3630. });
  3631. _registerModule(_modules, 'parts-3d/Series.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  3632. /* *
  3633. *
  3634. * (c) 2010-2020 Torstein Honsi
  3635. *
  3636. * Extension to the Series object in 3D charts.
  3637. *
  3638. * License: www.highcharts.com/license
  3639. *
  3640. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3641. *
  3642. * */
  3643. var addEvent = U.addEvent, pick = U.pick;
  3644. var perspective = H.perspective;
  3645. /* eslint-disable no-invalid-this */
  3646. // Wrap the translate method to post-translate points into 3D perspective
  3647. addEvent(H.Series, 'afterTranslate', function () {
  3648. if (this.chart.is3d()) {
  3649. this.translate3dPoints();
  3650. }
  3651. });
  3652. // Translate the plotX, plotY properties and add plotZ.
  3653. H.Series.prototype.translate3dPoints = function () {
  3654. var series = this, chart = series.chart, zAxis = pick(series.zAxis, chart.options.zAxis[0]), rawPoints = [], rawPoint, projectedPoints, projectedPoint, zValue, i;
  3655. for (i = 0; i < series.data.length; i++) {
  3656. rawPoint = series.data[i];
  3657. if (zAxis && zAxis.translate) {
  3658. zValue = zAxis.logarithmic && zAxis.val2lin ?
  3659. zAxis.val2lin(rawPoint.z) :
  3660. rawPoint.z; // #4562
  3661. rawPoint.plotZ = zAxis.translate(zValue);
  3662. rawPoint.isInside = rawPoint.isInside ?
  3663. (zValue >= zAxis.min &&
  3664. zValue <= zAxis.max) :
  3665. false;
  3666. }
  3667. else {
  3668. rawPoint.plotZ = 0;
  3669. }
  3670. rawPoint.axisXpos = rawPoint.plotX;
  3671. rawPoint.axisYpos = rawPoint.plotY;
  3672. rawPoint.axisZpos = rawPoint.plotZ;
  3673. rawPoints.push({
  3674. x: rawPoint.plotX,
  3675. y: rawPoint.plotY,
  3676. z: rawPoint.plotZ
  3677. });
  3678. }
  3679. projectedPoints = perspective(rawPoints, chart, true);
  3680. for (i = 0; i < series.data.length; i++) {
  3681. rawPoint = series.data[i];
  3682. projectedPoint = projectedPoints[i];
  3683. rawPoint.plotX = projectedPoint.x;
  3684. rawPoint.plotY = projectedPoint.y;
  3685. rawPoint.plotZ = projectedPoint.z;
  3686. }
  3687. };
  3688. });
  3689. _registerModule(_modules, 'parts-3d/Column.js', [_modules['parts/Globals.js'], _modules['parts/Stacking.js'], _modules['parts/Utilities.js']], function (H, StackItem, U) {
  3690. /* *
  3691. *
  3692. * (c) 2010-2020 Torstein Honsi
  3693. *
  3694. * License: www.highcharts.com/license
  3695. *
  3696. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3697. *
  3698. * */
  3699. var addEvent = U.addEvent, pick = U.pick, wrap = U.wrap;
  3700. var perspective = H.perspective, Series = H.Series, seriesTypes = H.seriesTypes, svg = H.svg;
  3701. /**
  3702. * Depth of the columns in a 3D column chart.
  3703. *
  3704. * @type {number}
  3705. * @default 25
  3706. * @since 4.0
  3707. * @product highcharts
  3708. * @requires highcharts-3d
  3709. * @apioption plotOptions.column.depth
  3710. */
  3711. /**
  3712. * 3D columns only. The color of the edges. Similar to `borderColor`, except it
  3713. * defaults to the same color as the column.
  3714. *
  3715. * @type {Highcharts.ColorString}
  3716. * @product highcharts
  3717. * @requires highcharts-3d
  3718. * @apioption plotOptions.column.edgeColor
  3719. */
  3720. /**
  3721. * 3D columns only. The width of the colored edges.
  3722. *
  3723. * @type {number}
  3724. * @default 1
  3725. * @product highcharts
  3726. * @requires highcharts-3d
  3727. * @apioption plotOptions.column.edgeWidth
  3728. */
  3729. /**
  3730. * The spacing between columns on the Z Axis in a 3D chart.
  3731. *
  3732. * @type {number}
  3733. * @default 1
  3734. * @since 4.0
  3735. * @product highcharts
  3736. * @requires highcharts-3d
  3737. * @apioption plotOptions.column.groupZPadding
  3738. */
  3739. /* eslint-disable no-invalid-this */
  3740. /**
  3741. * @private
  3742. * @param {Highcharts.Chart} chart
  3743. * Chart with stacks
  3744. * @param {string} stacking
  3745. * Stacking option
  3746. * @return {Highcharts.Stack3dDictionary}
  3747. */
  3748. function retrieveStacks(chart, stacking) {
  3749. var series = chart.series, stacks = {};
  3750. var stackNumber, i = 1;
  3751. series.forEach(function (s) {
  3752. stackNumber = pick(s.options.stack, (stacking ? 0 : series.length - 1 - s.index)); // #3841, #4532
  3753. if (!stacks[stackNumber]) {
  3754. stacks[stackNumber] = { series: [s], position: i };
  3755. i++;
  3756. }
  3757. else {
  3758. stacks[stackNumber].series.push(s);
  3759. }
  3760. });
  3761. stacks.totalStacks = i + 1;
  3762. return stacks;
  3763. }
  3764. wrap(seriesTypes.column.prototype, 'translate', function (proceed) {
  3765. proceed.apply(this, [].slice.call(arguments, 1));
  3766. // Do not do this if the chart is not 3D
  3767. if (this.chart.is3d()) {
  3768. this.translate3dShapes();
  3769. }
  3770. });
  3771. // Don't use justifyDataLabel when point is outsidePlot
  3772. wrap(H.Series.prototype, 'justifyDataLabel', function (proceed) {
  3773. return !(arguments[2].outside3dPlot) ?
  3774. proceed.apply(this, [].slice.call(arguments, 1)) :
  3775. false;
  3776. });
  3777. seriesTypes.column.prototype.translate3dPoints = function () { };
  3778. seriesTypes.column.prototype.translate3dShapes = function () {
  3779. var series = this, chart = series.chart, seriesOptions = series.options, depth = seriesOptions.depth, stack = seriesOptions.stacking ?
  3780. (seriesOptions.stack || 0) :
  3781. series.index, // #4743
  3782. z = stack * (depth + (seriesOptions.groupZPadding || 1)), borderCrisp = series.borderWidth % 2 ? 0.5 : 0, point2dPos; // Position of point in 2D, used for 3D position calculation.
  3783. if (chart.inverted && !series.yAxis.reversed) {
  3784. borderCrisp *= -1;
  3785. }
  3786. if (seriesOptions.grouping !== false) {
  3787. z = 0;
  3788. }
  3789. z += (seriesOptions.groupZPadding || 1);
  3790. series.data.forEach(function (point) {
  3791. // #7103 Reset outside3dPlot flag
  3792. point.outside3dPlot = null;
  3793. if (point.y !== null) {
  3794. var shapeArgs = point.shapeArgs, tooltipPos = point.tooltipPos,
  3795. // Array for final shapeArgs calculation.
  3796. // We are checking two dimensions (x and y).
  3797. dimensions = [['x', 'width'], ['y', 'height']], borderlessBase; // Crisped rects can have +/- 0.5 pixels offset.
  3798. // #3131 We need to check if column is inside plotArea.
  3799. dimensions.forEach(function (d) {
  3800. borderlessBase = shapeArgs[d[0]] - borderCrisp;
  3801. if (borderlessBase < 0) {
  3802. // If borderLessBase is smaller than 0, it is needed to set
  3803. // its value to 0 or 0.5 depending on borderWidth
  3804. // borderWidth may be even or odd.
  3805. shapeArgs[d[1]] +=
  3806. shapeArgs[d[0]] + borderCrisp;
  3807. shapeArgs[d[0]] = -borderCrisp;
  3808. borderlessBase = 0;
  3809. }
  3810. if ((borderlessBase + shapeArgs[d[1]] >
  3811. series[d[0] + 'Axis'].len) &&
  3812. // Do not change height/width of column if 0 (#6708)
  3813. shapeArgs[d[1]] !== 0) {
  3814. shapeArgs[d[1]] =
  3815. series[d[0] + 'Axis'].len -
  3816. shapeArgs[d[0]];
  3817. }
  3818. if (
  3819. // Do not remove columns with zero height/width.
  3820. (shapeArgs[d[1]] !== 0) &&
  3821. (shapeArgs[d[0]] >=
  3822. series[d[0] + 'Axis'].len ||
  3823. shapeArgs[d[0]] + shapeArgs[d[1]] <=
  3824. borderCrisp)) {
  3825. // Set args to 0 if column is outside the chart.
  3826. for (var key in shapeArgs) { // eslint-disable-line guard-for-in
  3827. shapeArgs[key] = 0;
  3828. }
  3829. // #7103 outside3dPlot flag is set on Points which are
  3830. // currently outside of plot.
  3831. point.outside3dPlot = true;
  3832. }
  3833. });
  3834. // Change from 2d to 3d
  3835. if (point.shapeType === 'rect') {
  3836. point.shapeType = 'cuboid';
  3837. }
  3838. shapeArgs.z = z;
  3839. shapeArgs.depth = depth;
  3840. shapeArgs.insidePlotArea = true;
  3841. // Point's position in 2D
  3842. point2dPos = {
  3843. x: shapeArgs.x + shapeArgs.width / 2,
  3844. y: shapeArgs.y,
  3845. z: z + depth / 2 // The center of column in Z dimension
  3846. };
  3847. // Recalculate point positions for inverted graphs
  3848. if (chart.inverted) {
  3849. point2dPos.x = shapeArgs.height;
  3850. point2dPos.y = point.clientX;
  3851. }
  3852. // Calculate and store point's position in 3D,
  3853. // using perspective method.
  3854. point.plot3d = perspective([point2dPos], chart, true, false)[0];
  3855. // Translate the tooltip position in 3d space
  3856. tooltipPos = perspective([{
  3857. x: tooltipPos[0],
  3858. y: tooltipPos[1],
  3859. z: z + depth / 2 // The center of column in Z dimension
  3860. }], chart, true, false)[0];
  3861. point.tooltipPos = [tooltipPos.x, tooltipPos.y];
  3862. }
  3863. });
  3864. // store for later use #4067
  3865. series.z = z;
  3866. };
  3867. wrap(seriesTypes.column.prototype, 'animate', function (proceed) {
  3868. if (!this.chart.is3d()) {
  3869. proceed.apply(this, [].slice.call(arguments, 1));
  3870. }
  3871. else {
  3872. var args = arguments, init = args[1], yAxis = this.yAxis, series = this, reversed = this.yAxis.reversed;
  3873. if (svg) { // VML is too slow anyway
  3874. if (init) {
  3875. series.data.forEach(function (point) {
  3876. if (point.y !== null) {
  3877. point.height = point.shapeArgs.height;
  3878. point.shapey = point.shapeArgs.y; // #2968
  3879. point.shapeArgs.height = 1;
  3880. if (!reversed) {
  3881. if (point.stackY) {
  3882. point.shapeArgs.y =
  3883. point.plotY +
  3884. yAxis.translate(point.stackY);
  3885. }
  3886. else {
  3887. point.shapeArgs.y =
  3888. point.plotY +
  3889. (point.negative ?
  3890. -point.height :
  3891. point.height);
  3892. }
  3893. }
  3894. }
  3895. });
  3896. }
  3897. else { // run the animation
  3898. series.data.forEach(function (point) {
  3899. if (point.y !== null) {
  3900. point.shapeArgs.height = point.height;
  3901. point.shapeArgs.y = point.shapey; // #2968
  3902. // null value do not have a graphic
  3903. if (point.graphic) {
  3904. point.graphic.animate(point.shapeArgs, series.options.animation);
  3905. }
  3906. }
  3907. });
  3908. // redraw datalabels to the correct position
  3909. this.drawDataLabels();
  3910. }
  3911. }
  3912. }
  3913. });
  3914. // In case of 3d columns there is no sense to add this columns to a specific
  3915. // series group - if series is added to a group all columns will have the same
  3916. // zIndex in comparison with different series.
  3917. wrap(seriesTypes.column.prototype, 'plotGroup', function (proceed, prop, name, visibility, zIndex, parent) {
  3918. if (prop !== 'dataLabelsGroup') {
  3919. if (this.chart.is3d()) {
  3920. if (this[prop]) {
  3921. delete this[prop];
  3922. }
  3923. if (parent) {
  3924. if (!this.chart.columnGroup) {
  3925. this.chart.columnGroup =
  3926. this.chart.renderer.g('columnGroup').add(parent);
  3927. }
  3928. this[prop] = this.chart.columnGroup;
  3929. this.chart.columnGroup.attr(this.getPlotBox());
  3930. this[prop].survive = true;
  3931. if (prop === 'group' || prop === 'markerGroup') {
  3932. arguments[3] = 'visible';
  3933. // For 3D column group and markerGroup should be visible
  3934. }
  3935. }
  3936. }
  3937. }
  3938. return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3939. });
  3940. // When series is not added to group it is needed to change setVisible method to
  3941. // allow correct Legend funcionality. This wrap is basing on pie chart series.
  3942. wrap(seriesTypes.column.prototype, 'setVisible', function (proceed, vis) {
  3943. var series = this, pointVis;
  3944. if (series.chart.is3d()) {
  3945. series.data.forEach(function (point) {
  3946. point.visible = point.options.visible = vis =
  3947. typeof vis === 'undefined' ?
  3948. !pick(series.visible, point.visible) : vis;
  3949. pointVis = vis ? 'visible' : 'hidden';
  3950. series.options.data[series.data.indexOf(point)] =
  3951. point.options;
  3952. if (point.graphic) {
  3953. point.graphic.attr({
  3954. visibility: pointVis
  3955. });
  3956. }
  3957. });
  3958. }
  3959. proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3960. });
  3961. seriesTypes.column.prototype
  3962. .handle3dGrouping = true;
  3963. addEvent(Series, 'afterInit', function () {
  3964. if (this.chart.is3d() &&
  3965. this.handle3dGrouping) {
  3966. var series = this, seriesOptions = this.options, grouping = seriesOptions.grouping, stacking = seriesOptions.stacking, reversedStacks = pick(this.yAxis.options.reversedStacks, true), z = 0;
  3967. // @todo grouping === true ?
  3968. if (!(typeof grouping !== 'undefined' && !grouping)) {
  3969. var stacks = retrieveStacks(this.chart, stacking), stack = seriesOptions.stack || 0, i; // position within the stack
  3970. for (i = 0; i < stacks[stack].series.length; i++) {
  3971. if (stacks[stack].series[i] === this) {
  3972. break;
  3973. }
  3974. }
  3975. z = (10 * (stacks.totalStacks - stacks[stack].position)) +
  3976. (reversedStacks ? i : -i); // #4369
  3977. // In case when axis is reversed, columns are also reversed inside
  3978. // the group (#3737)
  3979. if (!this.xAxis.reversed) {
  3980. z = (stacks.totalStacks * 10) - z;
  3981. }
  3982. }
  3983. seriesOptions.depth = seriesOptions.depth || 25;
  3984. series.z = series.z || 0;
  3985. seriesOptions.zIndex = z;
  3986. }
  3987. });
  3988. // eslint-disable-next-line valid-jsdoc
  3989. /**
  3990. * @private
  3991. */
  3992. function pointAttribs(proceed) {
  3993. var attr = proceed.apply(this, [].slice.call(arguments, 1));
  3994. if (this.chart.is3d && this.chart.is3d()) {
  3995. // Set the fill color to the fill color to provide a smooth edge
  3996. attr.stroke = this.options.edgeColor || attr.fill;
  3997. attr['stroke-width'] = pick(this.options.edgeWidth, 1); // #4055
  3998. }
  3999. return attr;
  4000. }
  4001. // eslint-disable-next-line valid-jsdoc
  4002. /**
  4003. * In 3D mode, all column-series are rendered in one main group. Because of that
  4004. * we need to apply inactive state on all points.
  4005. * @private
  4006. */
  4007. function setState(proceed, state, inherit) {
  4008. var is3d = this.chart.is3d && this.chart.is3d();
  4009. if (is3d) {
  4010. this.options.inactiveOtherPoints = true;
  4011. }
  4012. proceed.call(this, state, inherit);
  4013. if (is3d) {
  4014. this.options.inactiveOtherPoints = false;
  4015. }
  4016. }
  4017. // eslint-disable-next-line valid-jsdoc
  4018. /**
  4019. * In 3D mode, simple checking for a new shape to animate is not enough.
  4020. * Additionally check if graphic is a group of elements
  4021. * @private
  4022. */
  4023. function hasNewShapeType(proceed) {
  4024. var args = [];
  4025. for (var _i = 1; _i < arguments.length; _i++) {
  4026. args[_i - 1] = arguments[_i];
  4027. }
  4028. return this.series.chart.is3d() ?
  4029. this.graphic && this.graphic.element.nodeName !== 'g' :
  4030. proceed.apply(this, args);
  4031. }
  4032. wrap(seriesTypes.column.prototype, 'pointAttribs', pointAttribs);
  4033. wrap(seriesTypes.column.prototype, 'setState', setState);
  4034. wrap(seriesTypes.column.prototype.pointClass.prototype, 'hasNewShapeType', hasNewShapeType);
  4035. if (seriesTypes.columnrange) {
  4036. wrap(seriesTypes.columnrange.prototype, 'pointAttribs', pointAttribs);
  4037. wrap(seriesTypes.columnrange.prototype, 'setState', setState);
  4038. wrap(seriesTypes.columnrange.prototype.pointClass.prototype, 'hasNewShapeType', hasNewShapeType);
  4039. seriesTypes.columnrange.prototype.plotGroup =
  4040. seriesTypes.column.prototype.plotGroup;
  4041. seriesTypes.columnrange.prototype.setVisible =
  4042. seriesTypes.column.prototype.setVisible;
  4043. }
  4044. wrap(Series.prototype, 'alignDataLabel', function (proceed, point, dataLabel, options, alignTo) {
  4045. var chart = this.chart;
  4046. // In 3D we need to pass point.outsidePlot option to the justifyDataLabel
  4047. // method for disabling justifying dataLabels in columns outside plot
  4048. options.outside3dPlot = point.outside3dPlot;
  4049. // Only do this for 3D columns and it's derived series
  4050. if (chart.is3d() &&
  4051. this.is('column')) {
  4052. var series = this, seriesOptions = series.options, inside = pick(options.inside, !!series.options.stacking), options3d = chart.options.chart.options3d, xOffset = point.pointWidth / 2 || 0;
  4053. var dLPosition = {
  4054. x: alignTo.x + xOffset,
  4055. y: alignTo.y,
  4056. z: series.z + seriesOptions.depth / 2
  4057. };
  4058. if (chart.inverted) {
  4059. // Inside dataLabels are positioned according to above
  4060. // logic and there is no need to position them using
  4061. // non-3D algorighm (that use alignTo.width)
  4062. if (inside) {
  4063. alignTo.width = 0;
  4064. dLPosition.x += point.shapeArgs.height / 2;
  4065. }
  4066. // When chart is upside down
  4067. // (alpha angle between 180 and 360 degrees)
  4068. // it is needed to add column width to calculated value.
  4069. if (options3d.alpha >= 90 && options3d.alpha <= 270) {
  4070. dLPosition.y += point.shapeArgs.width;
  4071. }
  4072. }
  4073. // dLPosition is recalculated for 3D graphs
  4074. dLPosition = perspective([dLPosition], chart, true, false)[0];
  4075. alignTo.x = dLPosition.x - xOffset;
  4076. // #7103 If point is outside of plotArea, hide data label.
  4077. alignTo.y = point.outside3dPlot ? -9e9 : dLPosition.y;
  4078. }
  4079. proceed.apply(this, [].slice.call(arguments, 1));
  4080. });
  4081. // Added stackLabels position calculation for 3D charts.
  4082. wrap(StackItem.prototype, 'getStackBox', function (proceed, chart, stackItem, x, y, xWidth, h, axis) {
  4083. var stackBox = proceed.apply(this, [].slice.call(arguments, 1));
  4084. // Only do this for 3D graph
  4085. if (chart.is3d() && stackItem.base) {
  4086. // First element of stackItem.base is an index of base series.
  4087. var baseSeriesInd = +(stackItem.base).split(',')[0];
  4088. var columnSeries = chart.series[baseSeriesInd];
  4089. var options3d = chart.options.chart.options3d;
  4090. // Only do this if base series is a column or inherited type,
  4091. // use its barW, z and depth parameters
  4092. // for correct stackLabels position calculation
  4093. if (columnSeries &&
  4094. columnSeries instanceof seriesTypes.column) {
  4095. var dLPosition = {
  4096. x: stackBox.x + (chart.inverted ? h : xWidth / 2),
  4097. y: stackBox.y,
  4098. z: columnSeries.options.depth / 2
  4099. };
  4100. if (chart.inverted) {
  4101. // Do not use default offset calculation logic
  4102. // for 3D inverted stackLabels.
  4103. stackBox.width = 0;
  4104. // When chart is upside down
  4105. // (alpha angle between 180 and 360 degrees)
  4106. // it is needed to add column width to calculated value.
  4107. if (options3d.alpha >= 90 && options3d.alpha <= 270) {
  4108. dLPosition.y += xWidth;
  4109. }
  4110. }
  4111. dLPosition = perspective([dLPosition], chart, true, false)[0];
  4112. stackBox.x = dLPosition.x - xWidth / 2;
  4113. stackBox.y = dLPosition.y;
  4114. }
  4115. }
  4116. return stackBox;
  4117. });
  4118. });
  4119. _registerModule(_modules, 'parts-3d/Pie.js', [_modules['parts/Globals.js'], _modules['parts/Utilities.js']], function (H, U) {
  4120. /* *
  4121. *
  4122. * (c) 2010-2020 Torstein Honsi
  4123. *
  4124. * 3D pie series
  4125. *
  4126. * License: www.highcharts.com/license
  4127. *
  4128. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4129. *
  4130. * */
  4131. var pick = U.pick, wrap = U.wrap;
  4132. var deg2rad = H.deg2rad, seriesTypes = H.seriesTypes, svg = H.svg;
  4133. /**
  4134. * The thickness of a 3D pie.
  4135. *
  4136. * @type {number}
  4137. * @default 0
  4138. * @since 4.0
  4139. * @product highcharts
  4140. * @requires highcharts-3d
  4141. * @apioption plotOptions.pie.depth
  4142. */
  4143. /* eslint-disable no-invalid-this */
  4144. wrap(seriesTypes.pie.prototype, 'translate', function (proceed) {
  4145. proceed.apply(this, [].slice.call(arguments, 1));
  4146. // Do not do this if the chart is not 3D
  4147. if (!this.chart.is3d()) {
  4148. return;
  4149. }
  4150. var series = this, seriesOptions = series.options, depth = seriesOptions.depth || 0, options3d = series.chart.options.chart.options3d, alpha = options3d.alpha, beta = options3d.beta, z = seriesOptions.stacking ?
  4151. (seriesOptions.stack || 0) * depth :
  4152. series._i * depth;
  4153. z += depth / 2;
  4154. if (seriesOptions.grouping !== false) {
  4155. z = 0;
  4156. }
  4157. series.data.forEach(function (point) {
  4158. var shapeArgs = point.shapeArgs, angle;
  4159. point.shapeType = 'arc3d';
  4160. shapeArgs.z = z;
  4161. shapeArgs.depth = depth * 0.75;
  4162. shapeArgs.alpha = alpha;
  4163. shapeArgs.beta = beta;
  4164. shapeArgs.center = series.center;
  4165. angle = (shapeArgs.end + shapeArgs.start) / 2;
  4166. point.slicedTranslation = {
  4167. translateX: Math.round(Math.cos(angle) *
  4168. seriesOptions.slicedOffset *
  4169. Math.cos(alpha * deg2rad)),
  4170. translateY: Math.round(Math.sin(angle) *
  4171. seriesOptions.slicedOffset *
  4172. Math.cos(alpha * deg2rad))
  4173. };
  4174. });
  4175. });
  4176. wrap(seriesTypes.pie.prototype.pointClass.prototype, 'haloPath', function (proceed) {
  4177. var args = arguments;
  4178. return this.series.chart.is3d() ? [] : proceed.call(this, args[1]);
  4179. });
  4180. wrap(seriesTypes.pie.prototype, 'pointAttribs', function (proceed, point, state) {
  4181. var attr = proceed.call(this, point, state), options = this.options;
  4182. if (this.chart.is3d() && !this.chart.styledMode) {
  4183. attr.stroke = options.edgeColor || point.color || this.color;
  4184. attr['stroke-width'] = pick(options.edgeWidth, 1);
  4185. }
  4186. return attr;
  4187. });
  4188. wrap(seriesTypes.pie.prototype, 'drawDataLabels', function (proceed) {
  4189. if (this.chart.is3d()) {
  4190. var series = this, chart = series.chart, options3d = chart.options.chart.options3d;
  4191. series.data.forEach(function (point) {
  4192. var shapeArgs = point.shapeArgs, r = shapeArgs.r,
  4193. // #3240 issue with datalabels for 0 and null values
  4194. a1 = (shapeArgs.alpha || options3d.alpha) * deg2rad, b1 = (shapeArgs.beta || options3d.beta) * deg2rad, a2 = (shapeArgs.start + shapeArgs.end) / 2, labelPosition = point.labelPosition, connectorPosition = labelPosition.connectorPosition, yOffset = (-r * (1 - Math.cos(a1)) * Math.sin(a2)), xOffset = r * (Math.cos(b1) - 1) * Math.cos(a2);
  4195. // Apply perspective on label positions
  4196. [
  4197. labelPosition.natural,
  4198. connectorPosition.breakAt,
  4199. connectorPosition.touchingSliceAt
  4200. ].forEach(function (coordinates) {
  4201. coordinates.x += xOffset;
  4202. coordinates.y += yOffset;
  4203. });
  4204. });
  4205. }
  4206. proceed.apply(this, [].slice.call(arguments, 1));
  4207. });
  4208. wrap(seriesTypes.pie.prototype, 'addPoint', function (proceed) {
  4209. proceed.apply(this, [].slice.call(arguments, 1));
  4210. if (this.chart.is3d()) {
  4211. // destroy (and rebuild) everything!!!
  4212. this.update(this.userOptions, true); // #3845 pass the old options
  4213. }
  4214. });
  4215. wrap(seriesTypes.pie.prototype, 'animate', function (proceed) {
  4216. if (!this.chart.is3d()) {
  4217. proceed.apply(this, [].slice.call(arguments, 1));
  4218. }
  4219. else {
  4220. var args = arguments, init = args[1], animation = this.options.animation, attribs, center = this.center, group = this.group, markerGroup = this.markerGroup;
  4221. if (svg) { // VML is too slow anyway
  4222. if (animation === true) {
  4223. animation = {};
  4224. }
  4225. // Initialize the animation
  4226. if (init) {
  4227. // Scale down the group and place it in the center
  4228. group.oldtranslateX = pick(group.oldtranslateX, group.translateX);
  4229. group.oldtranslateY = pick(group.oldtranslateY, group.translateY);
  4230. attribs = {
  4231. translateX: center[0],
  4232. translateY: center[1],
  4233. scaleX: 0.001,
  4234. scaleY: 0.001
  4235. };
  4236. group.attr(attribs);
  4237. if (markerGroup) {
  4238. markerGroup.attrSetters = group.attrSetters;
  4239. markerGroup.attr(attribs);
  4240. }
  4241. // Run the animation
  4242. }
  4243. else {
  4244. attribs = {
  4245. translateX: group.oldtranslateX,
  4246. translateY: group.oldtranslateY,
  4247. scaleX: 1,
  4248. scaleY: 1
  4249. };
  4250. group.animate(attribs, animation);
  4251. if (markerGroup) {
  4252. markerGroup.animate(attribs, animation);
  4253. }
  4254. }
  4255. }
  4256. }
  4257. });
  4258. });
  4259. _registerModule(_modules, 'parts-3d/Scatter.js', [_modules['parts/Globals.js'], _modules['parts/Point.js'], _modules['parts/Utilities.js']], function (H, Point, U) {
  4260. /* *
  4261. *
  4262. * (c) 2010-2020 Torstein Honsi
  4263. *
  4264. * Scatter 3D series.
  4265. *
  4266. * License: www.highcharts.com/license
  4267. *
  4268. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4269. *
  4270. * */
  4271. var seriesType = U.seriesType;
  4272. var seriesTypes = H.seriesTypes;
  4273. /**
  4274. * @private
  4275. * @class
  4276. * @name Highcharts.seriesTypes.scatter3d
  4277. *
  4278. * @augments Highcharts.Series
  4279. */
  4280. seriesType('scatter3d', 'scatter',
  4281. /**
  4282. * A 3D scatter plot uses x, y and z coordinates to display values for three
  4283. * variables for a set of data.
  4284. *
  4285. * @sample {highcharts} highcharts/3d/scatter/
  4286. * Simple 3D scatter
  4287. * @sample {highcharts} highcharts/demo/3d-scatter-draggable
  4288. * Draggable 3d scatter
  4289. *
  4290. * @extends plotOptions.scatter
  4291. * @excluding dragDrop, cluster
  4292. * @product highcharts
  4293. * @requires highcharts-3d
  4294. * @optionparent plotOptions.scatter3d
  4295. */
  4296. {
  4297. tooltip: {
  4298. pointFormat: 'x: <b>{point.x}</b><br/>y: <b>{point.y}</b><br/>z: <b>{point.z}</b><br/>'
  4299. }
  4300. // Series class
  4301. }, {
  4302. pointAttribs: function (point) {
  4303. var attribs = seriesTypes.scatter.prototype.pointAttribs
  4304. .apply(this, arguments);
  4305. if (this.chart.is3d() && point) {
  4306. attribs.zIndex =
  4307. H.pointCameraDistance(point, this.chart);
  4308. }
  4309. return attribs;
  4310. },
  4311. axisTypes: ['xAxis', 'yAxis', 'zAxis'],
  4312. pointArrayMap: ['x', 'y', 'z'],
  4313. parallelArrays: ['x', 'y', 'z'],
  4314. // Require direct touch rather than using the k-d-tree, because the
  4315. // k-d-tree currently doesn't take the xyz coordinate system into
  4316. // account (#4552)
  4317. directTouch: true
  4318. // Point class
  4319. }, {
  4320. applyOptions: function () {
  4321. Point.prototype.applyOptions.apply(this, arguments);
  4322. if (typeof this.z === 'undefined') {
  4323. this.z = 0;
  4324. }
  4325. return this;
  4326. }
  4327. });
  4328. /**
  4329. * A `scatter3d` series. If the [type](#series.scatter3d.type) option is
  4330. * not specified, it is inherited from [chart.type](#chart.type).
  4331. *
  4332. * scatter3d](#plotOptions.scatter3d).
  4333. *
  4334. * @extends series,plotOptions.scatter3d
  4335. * @product highcharts
  4336. * @requires highcharts-3d
  4337. * @apioption series.scatter3d
  4338. */
  4339. /**
  4340. * An array of data points for the series. For the `scatter3d` series
  4341. * type, points can be given in the following ways:
  4342. *
  4343. * 1. An array of arrays with 3 values. In this case, the values correspond
  4344. * to `x,y,z`. If the first value is a string, it is applied as the name
  4345. * of the point, and the `x` value is inferred.
  4346. *
  4347. * ```js
  4348. * data: [
  4349. * [0, 0, 1],
  4350. * [1, 8, 7],
  4351. * [2, 9, 2]
  4352. * ]
  4353. * ```
  4354. *
  4355. * 3. An array of objects with named values. The following snippet shows only a
  4356. * few settings, see the complete options set below. If the total number of data
  4357. * points exceeds the series'
  4358. * [turboThreshold](#series.scatter3d.turboThreshold), this option is not
  4359. * available.
  4360. *
  4361. * ```js
  4362. * data: [{
  4363. * x: 1,
  4364. * y: 2,
  4365. * z: 24,
  4366. * name: "Point2",
  4367. * color: "#00FF00"
  4368. * }, {
  4369. * x: 1,
  4370. * y: 4,
  4371. * z: 12,
  4372. * name: "Point1",
  4373. * color: "#FF00FF"
  4374. * }]
  4375. * ```
  4376. *
  4377. * @sample {highcharts} highcharts/chart/reflow-true/
  4378. * Numerical values
  4379. * @sample {highcharts} highcharts/series/data-array-of-arrays/
  4380. * Arrays of numeric x and y
  4381. * @sample {highcharts} highcharts/series/data-array-of-arrays-datetime/
  4382. * Arrays of datetime x and y
  4383. * @sample {highcharts} highcharts/series/data-array-of-name-value/
  4384. * Arrays of point.name and y
  4385. * @sample {highcharts} highcharts/series/data-array-of-objects/
  4386. * Config objects
  4387. *
  4388. * @type {Array<Array<number>|*>}
  4389. * @extends series.scatter.data
  4390. * @product highcharts
  4391. * @apioption series.scatter3d.data
  4392. */
  4393. /**
  4394. * The z value for each data point.
  4395. *
  4396. * @type {number}
  4397. * @product highcharts
  4398. * @apioption series.scatter3d.data.z
  4399. */
  4400. ''; // adds doclets above to transpiled file
  4401. });
  4402. _registerModule(_modules, 'parts-3d/VMLAxis3D.js', [_modules['parts/Utilities.js']], function (U) {
  4403. /* *
  4404. *
  4405. * (c) 2010-2020 Torstein Honsi
  4406. *
  4407. * Extension to the VML Renderer
  4408. *
  4409. * License: www.highcharts.com/license
  4410. *
  4411. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4412. *
  4413. * */
  4414. var addEvent = U.addEvent;
  4415. /* eslint-disable valid-jsdoc */
  4416. var VMLAxis3DAdditions = /** @class */ (function () {
  4417. /* *
  4418. *
  4419. * Constructors
  4420. *
  4421. * */
  4422. function VMLAxis3DAdditions(axis) {
  4423. this.axis = axis;
  4424. }
  4425. return VMLAxis3DAdditions;
  4426. }());
  4427. var VMLAxis3D = /** @class */ (function () {
  4428. function VMLAxis3D() {
  4429. }
  4430. /* *
  4431. *
  4432. * Static Properties
  4433. *
  4434. * */
  4435. VMLAxis3D.compose = function (AxisClass) {
  4436. AxisClass.keepProps.push('vml');
  4437. addEvent(AxisClass, 'init', VMLAxis3D.onInit);
  4438. addEvent(AxisClass, 'render', VMLAxis3D.onRender);
  4439. };
  4440. /**
  4441. * @private
  4442. */
  4443. VMLAxis3D.onInit = function () {
  4444. var axis = this;
  4445. if (!axis.vml) {
  4446. axis.vml = new VMLAxis3DAdditions(axis);
  4447. }
  4448. };
  4449. /**
  4450. * @private
  4451. */
  4452. VMLAxis3D.onRender = function () {
  4453. var axis = this;
  4454. var vml = axis.vml;
  4455. // VML doesn't support a negative z-index
  4456. if (vml.sideFrame) {
  4457. vml.sideFrame.css({ zIndex: 0 });
  4458. vml.sideFrame.front.attr({
  4459. fill: vml.sideFrame.color
  4460. });
  4461. }
  4462. if (vml.bottomFrame) {
  4463. vml.bottomFrame.css({ zIndex: 1 });
  4464. vml.bottomFrame.front.attr({
  4465. fill: vml.bottomFrame.color
  4466. });
  4467. }
  4468. if (vml.backFrame) {
  4469. vml.backFrame.css({ zIndex: 0 });
  4470. vml.backFrame.front.attr({
  4471. fill: vml.backFrame.color
  4472. });
  4473. }
  4474. };
  4475. return VMLAxis3D;
  4476. }());
  4477. return VMLAxis3D;
  4478. });
  4479. _registerModule(_modules, 'parts-3d/VMLRenderer.js', [_modules['parts/Axis.js'], _modules['parts/Globals.js'], _modules['parts/SVGRenderer.js'], _modules['parts/Utilities.js'], _modules['parts-3d/VMLAxis3D.js']], function (Axis, H, SVGRenderer, U, VMLAxis3D) {
  4480. /* *
  4481. *
  4482. * (c) 2010-2020 Torstein Honsi
  4483. *
  4484. * Extension to the VML Renderer
  4485. *
  4486. * License: www.highcharts.com/license
  4487. *
  4488. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  4489. *
  4490. * */
  4491. var setOptions = U.setOptions;
  4492. var VMLRenderer = H.VMLRenderer;
  4493. if (VMLRenderer) {
  4494. setOptions({ animate: false });
  4495. VMLRenderer.prototype.face3d = SVGRenderer.prototype.face3d;
  4496. VMLRenderer.prototype.polyhedron = SVGRenderer.prototype.polyhedron;
  4497. VMLRenderer.prototype.elements3d = SVGRenderer.prototype.elements3d;
  4498. VMLRenderer.prototype.element3d = SVGRenderer.prototype.element3d;
  4499. VMLRenderer.prototype.cuboid = SVGRenderer.prototype.cuboid;
  4500. VMLRenderer.prototype.cuboidPath = SVGRenderer.prototype.cuboidPath;
  4501. VMLRenderer.prototype.toLinePath = SVGRenderer.prototype.toLinePath;
  4502. VMLRenderer.prototype.toLineSegments = SVGRenderer.prototype.toLineSegments;
  4503. VMLRenderer.prototype.arc3d = function (shapeArgs) {
  4504. var result = SVGRenderer.prototype.arc3d.call(this, shapeArgs);
  4505. result.css({ zIndex: result.zIndex });
  4506. return result;
  4507. };
  4508. H.VMLRenderer.prototype.arc3dPath = SVGRenderer.prototype.arc3dPath;
  4509. VMLAxis3D.compose(Axis);
  4510. }
  4511. });
  4512. _registerModule(_modules, 'masters/highcharts-3d.src.js', [], function () {
  4513. });
  4514. }));