boost.src.js 165 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835
  1. /**
  2. * @license Highcharts JS v9.1.1 (2021-06-04)
  3. *
  4. * Boost module
  5. *
  6. * (c) 2010-2021 Highsoft AS
  7. * Author: Torstein Honsi
  8. *
  9. * License: www.highcharts.com/license
  10. *
  11. * */
  12. 'use strict';
  13. (function (factory) {
  14. if (typeof module === 'object' && module.exports) {
  15. factory['default'] = factory;
  16. module.exports = factory;
  17. } else if (typeof define === 'function' && define.amd) {
  18. define('highcharts/modules/boost', ['highcharts'], function (Highcharts) {
  19. factory(Highcharts);
  20. factory.Highcharts = Highcharts;
  21. return factory;
  22. });
  23. } else {
  24. factory(typeof Highcharts !== 'undefined' ? Highcharts : undefined);
  25. }
  26. }(function (Highcharts) {
  27. var _modules = Highcharts ? Highcharts._modules : {};
  28. function _registerModule(obj, path, args, fn) {
  29. if (!obj.hasOwnProperty(path)) {
  30. obj[path] = fn.apply(null, args);
  31. }
  32. }
  33. _registerModule(_modules, 'Extensions/Boost/Boostables.js', [], function () {
  34. /* *
  35. *
  36. * Copyright (c) 2019-2021 Highsoft AS
  37. *
  38. * Boost module: stripped-down renderer for higher performance
  39. *
  40. * License: highcharts.com/license
  41. *
  42. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  43. *
  44. * */
  45. // These are the series we allow boosting for.
  46. var boostables = [
  47. 'area',
  48. 'arearange',
  49. 'column',
  50. 'columnrange',
  51. 'bar',
  52. 'line',
  53. 'scatter',
  54. 'heatmap',
  55. 'bubble',
  56. 'treemap'
  57. ];
  58. return boostables;
  59. });
  60. _registerModule(_modules, 'Extensions/Boost/BoostableMap.js', [_modules['Extensions/Boost/Boostables.js']], function (boostables) {
  61. /* *
  62. *
  63. * Copyright (c) 2019-2021 Highsoft AS
  64. *
  65. * Boost module: stripped-down renderer for higher performance
  66. *
  67. * License: highcharts.com/license
  68. *
  69. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  70. *
  71. * */
  72. // These are the series we allow boosting for.
  73. var boostableMap = {};
  74. boostables.forEach(function (item) {
  75. boostableMap[item] = 1;
  76. });
  77. return boostableMap;
  78. });
  79. _registerModule(_modules, 'Extensions/Boost/WGLShader.js', [_modules['Core/Utilities.js']], function (U) {
  80. /* *
  81. *
  82. * Copyright (c) 2019-2021 Highsoft AS
  83. *
  84. * Boost module: stripped-down renderer for higher performance
  85. *
  86. * License: highcharts.com/license
  87. *
  88. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  89. *
  90. * */
  91. var clamp = U.clamp,
  92. error = U.error,
  93. pick = U.pick;
  94. /* eslint-disable valid-jsdoc */
  95. /**
  96. * A static shader mimicing axis translation functions found in Core/Axis
  97. *
  98. * @private
  99. * @function GLShader
  100. *
  101. * @param {WebGLContext} gl
  102. * the context in which the shader is active
  103. *
  104. * @return {*}
  105. */
  106. function GLShader(gl) {
  107. var vertShade = [
  108. /* eslint-disable max-len, @typescript-eslint/indent */
  109. '#version 100',
  110. '#define LN10 2.302585092994046',
  111. 'precision highp float;',
  112. 'attribute vec4 aVertexPosition;',
  113. 'attribute vec4 aColor;',
  114. 'varying highp vec2 position;',
  115. 'varying highp vec4 vColor;',
  116. 'uniform mat4 uPMatrix;',
  117. 'uniform float pSize;',
  118. 'uniform float translatedThreshold;',
  119. 'uniform bool hasThreshold;',
  120. 'uniform bool skipTranslation;',
  121. 'uniform float xAxisTrans;',
  122. 'uniform float xAxisMin;',
  123. 'uniform float xAxisMinPad;',
  124. 'uniform float xAxisPointRange;',
  125. 'uniform float xAxisLen;',
  126. 'uniform bool xAxisPostTranslate;',
  127. 'uniform float xAxisOrdinalSlope;',
  128. 'uniform float xAxisOrdinalOffset;',
  129. 'uniform float xAxisPos;',
  130. 'uniform bool xAxisCVSCoord;',
  131. 'uniform bool xAxisIsLog;',
  132. 'uniform bool xAxisReversed;',
  133. 'uniform float yAxisTrans;',
  134. 'uniform float yAxisMin;',
  135. 'uniform float yAxisMinPad;',
  136. 'uniform float yAxisPointRange;',
  137. 'uniform float yAxisLen;',
  138. 'uniform bool yAxisPostTranslate;',
  139. 'uniform float yAxisOrdinalSlope;',
  140. 'uniform float yAxisOrdinalOffset;',
  141. 'uniform float yAxisPos;',
  142. 'uniform bool yAxisCVSCoord;',
  143. 'uniform bool yAxisIsLog;',
  144. 'uniform bool yAxisReversed;',
  145. 'uniform bool isBubble;',
  146. 'uniform bool bubbleSizeByArea;',
  147. 'uniform float bubbleZMin;',
  148. 'uniform float bubbleZMax;',
  149. 'uniform float bubbleZThreshold;',
  150. 'uniform float bubbleMinSize;',
  151. 'uniform float bubbleMaxSize;',
  152. 'uniform bool bubbleSizeAbs;',
  153. 'uniform bool isInverted;',
  154. 'float bubbleRadius(){',
  155. 'float value = aVertexPosition.w;',
  156. 'float zMax = bubbleZMax;',
  157. 'float zMin = bubbleZMin;',
  158. 'float radius = 0.0;',
  159. 'float pos = 0.0;',
  160. 'float zRange = zMax - zMin;',
  161. 'if (bubbleSizeAbs){',
  162. 'value = value - bubbleZThreshold;',
  163. 'zMax = max(zMax - bubbleZThreshold, zMin - bubbleZThreshold);',
  164. 'zMin = 0.0;',
  165. '}',
  166. 'if (value < zMin){',
  167. 'radius = bubbleZMin / 2.0 - 1.0;',
  168. '} else {',
  169. 'pos = zRange > 0.0 ? (value - zMin) / zRange : 0.5;',
  170. 'if (bubbleSizeByArea && pos > 0.0){',
  171. 'pos = sqrt(pos);',
  172. '}',
  173. 'radius = ceil(bubbleMinSize + pos * (bubbleMaxSize - bubbleMinSize)) / 2.0;',
  174. '}',
  175. 'return radius * 2.0;',
  176. '}',
  177. 'float translate(float val,',
  178. 'float pointPlacement,',
  179. 'float localA,',
  180. 'float localMin,',
  181. 'float minPixelPadding,',
  182. 'float pointRange,',
  183. 'float len,',
  184. 'bool cvsCoord,',
  185. 'bool isLog,',
  186. 'bool reversed',
  187. '){',
  188. 'float sign = 1.0;',
  189. 'float cvsOffset = 0.0;',
  190. 'if (cvsCoord) {',
  191. 'sign *= -1.0;',
  192. 'cvsOffset = len;',
  193. '}',
  194. 'if (isLog) {',
  195. 'val = log(val) / LN10;',
  196. '}',
  197. 'if (reversed) {',
  198. 'sign *= -1.0;',
  199. 'cvsOffset -= sign * len;',
  200. '}',
  201. 'return sign * (val - localMin) * localA + cvsOffset + ',
  202. '(sign * minPixelPadding);',
  203. '}',
  204. 'float xToPixels(float value) {',
  205. 'if (skipTranslation){',
  206. 'return value;// + xAxisPos;',
  207. '}',
  208. 'return translate(value, 0.0, xAxisTrans, xAxisMin, xAxisMinPad, xAxisPointRange, xAxisLen, xAxisCVSCoord, xAxisIsLog, xAxisReversed);// + xAxisPos;',
  209. '}',
  210. 'float yToPixels(float value, float checkTreshold) {',
  211. 'float v;',
  212. 'if (skipTranslation){',
  213. 'v = value;// + yAxisPos;',
  214. '} else {',
  215. 'v = translate(value, 0.0, yAxisTrans, yAxisMin, yAxisMinPad, yAxisPointRange, yAxisLen, yAxisCVSCoord, yAxisIsLog, yAxisReversed);// + yAxisPos;',
  216. 'if (v > yAxisLen) {',
  217. 'v = yAxisLen;',
  218. '}',
  219. '}',
  220. 'if (checkTreshold > 0.0 && hasThreshold) {',
  221. 'v = min(v, translatedThreshold);',
  222. '}',
  223. 'return v;',
  224. '}',
  225. 'void main(void) {',
  226. 'if (isBubble){',
  227. 'gl_PointSize = bubbleRadius();',
  228. '} else {',
  229. 'gl_PointSize = pSize;',
  230. '}',
  231. // 'gl_PointSize = 10.0;',
  232. 'vColor = aColor;',
  233. 'if (skipTranslation && isInverted) {',
  234. // If we get translated values from JS, just swap them (x, y)
  235. 'gl_Position = uPMatrix * vec4(aVertexPosition.y + yAxisPos, aVertexPosition.x + xAxisPos, 0.0, 1.0);',
  236. '} else if (isInverted) {',
  237. // But when calculating pixel positions directly,
  238. // swap axes and values (x, y)
  239. 'gl_Position = uPMatrix * vec4(yToPixels(aVertexPosition.y, aVertexPosition.z) + yAxisPos, xToPixels(aVertexPosition.x) + xAxisPos, 0.0, 1.0);',
  240. '} else {',
  241. 'gl_Position = uPMatrix * vec4(xToPixels(aVertexPosition.x) + xAxisPos, yToPixels(aVertexPosition.y, aVertexPosition.z) + yAxisPos, 0.0, 1.0);',
  242. '}',
  243. // 'gl_Position = uPMatrix * vec4(aVertexPosition.x, aVertexPosition.y, 0.0, 1.0);',
  244. '}'
  245. /* eslint-enable max-len, @typescript-eslint/indent */
  246. ].join('\n'),
  247. // Fragment shader source
  248. fragShade = [
  249. /* eslint-disable max-len, @typescript-eslint/indent */
  250. 'precision highp float;',
  251. 'uniform vec4 fillColor;',
  252. 'varying highp vec2 position;',
  253. 'varying highp vec4 vColor;',
  254. 'uniform sampler2D uSampler;',
  255. 'uniform bool isCircle;',
  256. 'uniform bool hasColor;',
  257. // 'vec4 toColor(float value, vec2 point) {',
  258. // 'return vec4(0.0, 0.0, 0.0, 0.0);',
  259. // '}',
  260. 'void main(void) {',
  261. 'vec4 col = fillColor;',
  262. 'vec4 tcol = texture2D(uSampler, gl_PointCoord.st);',
  263. 'if (hasColor) {',
  264. 'col = vColor;',
  265. '}',
  266. 'if (isCircle) {',
  267. 'col *= tcol;',
  268. 'if (tcol.r < 0.0) {',
  269. 'discard;',
  270. '} else {',
  271. 'gl_FragColor = col;',
  272. '}',
  273. '} else {',
  274. 'gl_FragColor = col;',
  275. '}',
  276. '}'
  277. /* eslint-enable max-len, @typescript-eslint/indent */
  278. ].join('\n'), uLocations = {},
  279. // The shader program
  280. shaderProgram,
  281. // Uniform handle to the perspective matrix
  282. pUniform,
  283. // Uniform for point size
  284. psUniform,
  285. // Uniform for fill color
  286. fillColorUniform,
  287. // Uniform for isBubble
  288. isBubbleUniform,
  289. // Uniform for bubble abs sizing
  290. bubbleSizeAbsUniform, bubbleSizeAreaUniform,
  291. // Skip translation uniform
  292. skipTranslationUniform,
  293. // Set to 1 if circle
  294. isCircleUniform,
  295. // Uniform for invertion
  296. isInverted,
  297. // Error stack
  298. errors = [],
  299. // Texture uniform
  300. uSamplerUniform;
  301. /**
  302. * Handle errors accumulated in errors stack
  303. * @private
  304. */
  305. function handleErrors() {
  306. if (errors.length) {
  307. error('[highcharts boost] shader error - ' + errors.join('\n'));
  308. }
  309. }
  310. /**
  311. * String to shader program
  312. * @private
  313. * @param {string} str - the program source
  314. * @param {string} type - the program type: either `vertex` or `fragment`
  315. * @returns {bool|shader}
  316. */
  317. function stringToProgram(str, type) {
  318. var t = type === 'vertex' ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER,
  319. shader = gl.createShader(t);
  320. gl.shaderSource(shader, str);
  321. gl.compileShader(shader);
  322. if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  323. errors.push('when compiling ' +
  324. type +
  325. ' shader:\n' +
  326. gl.getShaderInfoLog(shader));
  327. return false;
  328. }
  329. return shader;
  330. }
  331. /**
  332. * Create the shader.
  333. * Loads the shader program statically defined above
  334. * @private
  335. */
  336. function createShader() {
  337. var v = stringToProgram(vertShade, 'vertex'), f = stringToProgram(fragShade, 'fragment');
  338. if (!v || !f) {
  339. shaderProgram = false;
  340. handleErrors();
  341. return false;
  342. }
  343. /**
  344. * @private
  345. */
  346. function uloc(n) {
  347. return gl.getUniformLocation(shaderProgram, n);
  348. }
  349. shaderProgram = gl.createProgram();
  350. gl.attachShader(shaderProgram, v);
  351. gl.attachShader(shaderProgram, f);
  352. gl.linkProgram(shaderProgram);
  353. if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
  354. errors.push(gl.getProgramInfoLog(shaderProgram));
  355. handleErrors();
  356. shaderProgram = false;
  357. return false;
  358. }
  359. gl.useProgram(shaderProgram);
  360. gl.bindAttribLocation(shaderProgram, 0, 'aVertexPosition');
  361. pUniform = uloc('uPMatrix');
  362. psUniform = uloc('pSize');
  363. fillColorUniform = uloc('fillColor');
  364. isBubbleUniform = uloc('isBubble');
  365. bubbleSizeAbsUniform = uloc('bubbleSizeAbs');
  366. bubbleSizeAreaUniform = uloc('bubbleSizeByArea');
  367. uSamplerUniform = uloc('uSampler');
  368. skipTranslationUniform = uloc('skipTranslation');
  369. isCircleUniform = uloc('isCircle');
  370. isInverted = uloc('isInverted');
  371. return true;
  372. }
  373. /**
  374. * Destroy the shader
  375. * @private
  376. */
  377. function destroy() {
  378. if (gl && shaderProgram) {
  379. gl.deleteProgram(shaderProgram);
  380. shaderProgram = false;
  381. }
  382. }
  383. /**
  384. * Bind the shader.
  385. * This makes the shader the active one until another one is bound,
  386. * or until 0 is bound.
  387. * @private
  388. */
  389. function bind() {
  390. if (gl && shaderProgram) {
  391. gl.useProgram(shaderProgram);
  392. }
  393. }
  394. /**
  395. * Set a uniform value.
  396. * This uses a hash map to cache uniform locations.
  397. * @private
  398. * @param name {string} - the name of the uniform to set
  399. * @param val {float} - the value to set
  400. */
  401. function setUniform(name, val) {
  402. if (gl && shaderProgram) {
  403. var u = uLocations[name] = (uLocations[name] ||
  404. gl.getUniformLocation(shaderProgram,
  405. name));
  406. gl.uniform1f(u, val);
  407. }
  408. }
  409. /**
  410. * Set the active texture
  411. * @private
  412. * @param texture - the texture
  413. */
  414. function setTexture(texture) {
  415. if (gl && shaderProgram) {
  416. gl.uniform1i(uSamplerUniform, texture);
  417. }
  418. }
  419. /**
  420. * Set if inversion state
  421. * @private
  422. * @flag is the state
  423. */
  424. function setInverted(flag) {
  425. if (gl && shaderProgram) {
  426. gl.uniform1i(isInverted, flag);
  427. }
  428. }
  429. /**
  430. * Enable/disable circle drawing
  431. * @private
  432. */
  433. function setDrawAsCircle(flag) {
  434. if (gl && shaderProgram) {
  435. gl.uniform1i(isCircleUniform, flag ? 1 : 0);
  436. }
  437. }
  438. /**
  439. * Flush
  440. * @private
  441. */
  442. function reset() {
  443. if (gl && shaderProgram) {
  444. gl.uniform1i(isBubbleUniform, 0);
  445. gl.uniform1i(isCircleUniform, 0);
  446. }
  447. }
  448. /**
  449. * Set bubble uniforms
  450. * @private
  451. * @param series {Highcharts.Series} - the series to use
  452. */
  453. function setBubbleUniforms(series, zCalcMin, zCalcMax) {
  454. var seriesOptions = series.options,
  455. zMin = Number.MAX_VALUE,
  456. zMax = -Number.MAX_VALUE;
  457. if (gl && shaderProgram && series.type === 'bubble') {
  458. zMin = pick(seriesOptions.zMin, clamp(zCalcMin, seriesOptions.displayNegative === false ?
  459. seriesOptions.zThreshold : -Number.MAX_VALUE, zMin));
  460. zMax = pick(seriesOptions.zMax, Math.max(zMax, zCalcMax));
  461. gl.uniform1i(isBubbleUniform, 1);
  462. gl.uniform1i(isCircleUniform, 1);
  463. gl.uniform1i(bubbleSizeAreaUniform, (series.options.sizeBy !== 'width'));
  464. gl.uniform1i(bubbleSizeAbsUniform, series.options
  465. .sizeByAbsoluteValue);
  466. setUniform('bubbleZMin', zMin);
  467. setUniform('bubbleZMax', zMax);
  468. setUniform('bubbleZThreshold', series.options.zThreshold);
  469. setUniform('bubbleMinSize', series.minPxSize);
  470. setUniform('bubbleMaxSize', series.maxPxSize);
  471. }
  472. }
  473. /**
  474. * Set the Color uniform.
  475. * @private
  476. * @param color {Array<float>} - an array with RGBA values
  477. */
  478. function setColor(color) {
  479. if (gl && shaderProgram) {
  480. gl.uniform4f(fillColorUniform, color[0] / 255.0, color[1] / 255.0, color[2] / 255.0, color[3]);
  481. }
  482. }
  483. /**
  484. * Set skip translation
  485. * @private
  486. */
  487. function setSkipTranslation(flag) {
  488. if (gl && shaderProgram) {
  489. gl.uniform1i(skipTranslationUniform, flag === true ? 1 : 0);
  490. }
  491. }
  492. /**
  493. * Set the perspective matrix
  494. * @private
  495. * @param m {Matrix4x4} - the matrix
  496. */
  497. function setPMatrix(m) {
  498. if (gl && shaderProgram) {
  499. gl.uniformMatrix4fv(pUniform, false, m);
  500. }
  501. }
  502. /**
  503. * Set the point size.
  504. * @private
  505. * @param p {float} - point size
  506. */
  507. function setPointSize(p) {
  508. if (gl && shaderProgram) {
  509. gl.uniform1f(psUniform, p);
  510. }
  511. }
  512. /**
  513. * Get the shader program handle
  514. * @private
  515. * @return {GLInt} - the handle for the program
  516. */
  517. function getProgram() {
  518. return shaderProgram;
  519. }
  520. if (gl) {
  521. if (!createShader()) {
  522. return false;
  523. }
  524. }
  525. return {
  526. psUniform: function () {
  527. return psUniform;
  528. },
  529. pUniform: function () {
  530. return pUniform;
  531. },
  532. fillColorUniform: function () {
  533. return fillColorUniform;
  534. },
  535. setBubbleUniforms: setBubbleUniforms,
  536. bind: bind,
  537. program: getProgram,
  538. create: createShader,
  539. setUniform: setUniform,
  540. setPMatrix: setPMatrix,
  541. setColor: setColor,
  542. setPointSize: setPointSize,
  543. setSkipTranslation: setSkipTranslation,
  544. setTexture: setTexture,
  545. setDrawAsCircle: setDrawAsCircle,
  546. reset: reset,
  547. setInverted: setInverted,
  548. destroy: destroy
  549. };
  550. }
  551. return GLShader;
  552. });
  553. _registerModule(_modules, 'Extensions/Boost/WGLVBuffer.js', [], function () {
  554. /* *
  555. *
  556. * Copyright (c) 2019-2021 Highsoft AS
  557. *
  558. * Boost module: stripped-down renderer for higher performance
  559. *
  560. * License: highcharts.com/license
  561. *
  562. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  563. *
  564. * */
  565. /* eslint-disable valid-jsdoc */
  566. /**
  567. * Vertex Buffer abstraction.
  568. * A vertex buffer is a set of vertices which are passed to the GPU
  569. * in a single call.
  570. *
  571. * @private
  572. * @function GLVertexBuffer
  573. *
  574. * @param {WebGLContext} gl
  575. * the context in which to create the buffer
  576. *
  577. * @param {GLShader} shader
  578. * the shader to use
  579. *
  580. * @return {*}
  581. */
  582. function GLVertexBuffer(gl, shader, dataComponents
  583. /* , type */
  584. ) {
  585. var buffer = false,
  586. vertAttribute = false,
  587. components = dataComponents || 2,
  588. preAllocated = false,
  589. iterator = 0,
  590. // farray = false,
  591. data;
  592. // type = type || 'float';
  593. /**
  594. * @private
  595. */
  596. function destroy() {
  597. if (buffer) {
  598. gl.deleteBuffer(buffer);
  599. buffer = false;
  600. vertAttribute = false;
  601. }
  602. iterator = 0;
  603. components = dataComponents || 2;
  604. data = [];
  605. }
  606. /**
  607. * Build the buffer
  608. * @private
  609. * @param dataIn {Array<float>} - a 0 padded array of indices
  610. * @param attrib {String} - the name of the Attribute to bind the buffer to
  611. * @param dataComponents {Integer} - the number of components per. indice
  612. */
  613. function build(dataIn, attrib, dataComponents) {
  614. var farray;
  615. data = dataIn || [];
  616. if ((!data || data.length === 0) && !preAllocated) {
  617. // console.error('trying to render empty vbuffer');
  618. destroy();
  619. return false;
  620. }
  621. components = dataComponents || components;
  622. if (buffer) {
  623. gl.deleteBuffer(buffer);
  624. }
  625. if (!preAllocated) {
  626. farray = new Float32Array(data);
  627. }
  628. buffer = gl.createBuffer();
  629. gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  630. gl.bufferData(gl.ARRAY_BUFFER, preAllocated || farray, gl.STATIC_DRAW);
  631. // gl.bindAttribLocation(shader.program(), 0, 'aVertexPosition');
  632. vertAttribute = gl.getAttribLocation(shader.program(), attrib);
  633. gl.enableVertexAttribArray(vertAttribute);
  634. // Trigger cleanup
  635. farray = false;
  636. return true;
  637. }
  638. /**
  639. * Bind the buffer
  640. * @private
  641. */
  642. function bind() {
  643. if (!buffer) {
  644. return false;
  645. }
  646. // gl.bindAttribLocation(shader.program(), 0, 'aVertexPosition');
  647. // gl.enableVertexAttribArray(vertAttribute);
  648. // gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  649. gl.vertexAttribPointer(vertAttribute, components, gl.FLOAT, false, 0, 0);
  650. // gl.enableVertexAttribArray(vertAttribute);
  651. }
  652. /**
  653. * Render the buffer
  654. * @private
  655. * @param from {Integer} - the start indice
  656. * @param to {Integer} - the end indice
  657. * @param drawMode {String} - the draw mode
  658. */
  659. function render(from, to, drawMode) {
  660. var length = preAllocated ? preAllocated.length : data.length;
  661. if (!buffer) {
  662. return false;
  663. }
  664. if (!length) {
  665. return false;
  666. }
  667. if (!from || from > length || from < 0) {
  668. from = 0;
  669. }
  670. if (!to || to > length) {
  671. to = length;
  672. }
  673. drawMode = drawMode || 'points';
  674. gl.drawArrays(gl[drawMode.toUpperCase()], from / components, (to - from) / components);
  675. return true;
  676. }
  677. /**
  678. * @private
  679. */
  680. function push(x, y, a, b) {
  681. if (preAllocated) { // && iterator <= preAllocated.length - 4) {
  682. preAllocated[++iterator] = x;
  683. preAllocated[++iterator] = y;
  684. preAllocated[++iterator] = a;
  685. preAllocated[++iterator] = b;
  686. }
  687. }
  688. /**
  689. * Note about pre-allocated buffers:
  690. * - This is slower for charts with many series
  691. * @private
  692. */
  693. function allocate(size) {
  694. size *= 4;
  695. iterator = -1;
  696. preAllocated = new Float32Array(size);
  697. }
  698. // /////////////////////////////////////////////////////////////////////////
  699. return {
  700. destroy: destroy,
  701. bind: bind,
  702. data: data,
  703. build: build,
  704. render: render,
  705. allocate: allocate,
  706. push: push
  707. };
  708. }
  709. return GLVertexBuffer;
  710. });
  711. _registerModule(_modules, 'Extensions/Boost/WGLRenderer.js', [_modules['Core/Color/Color.js'], _modules['Extensions/Boost/WGLShader.js'], _modules['Extensions/Boost/WGLVBuffer.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Color, GLShader, GLVertexBuffer, H, U) {
  712. /* *
  713. *
  714. * Copyright (c) 2019-2021 Highsoft AS
  715. *
  716. * Boost module: stripped-down renderer for higher performance
  717. *
  718. * License: highcharts.com/license
  719. *
  720. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  721. *
  722. * */
  723. var color = Color.parse;
  724. var doc = H.doc;
  725. var isNumber = U.isNumber,
  726. isObject = U.isObject,
  727. merge = U.merge,
  728. objectEach = U.objectEach,
  729. pick = U.pick;
  730. /* eslint-disable valid-jsdoc */
  731. /**
  732. * Main renderer. Used to render series.
  733. *
  734. * Notes to self:
  735. * - May be able to build a point map by rendering to a separate canvas and
  736. * encoding values in the color data.
  737. * - Need to figure out a way to transform the data quicker
  738. *
  739. * @private
  740. * @function GLRenderer
  741. *
  742. * @param {Function} postRenderCallback
  743. *
  744. * @return {*}
  745. */
  746. function GLRenderer(postRenderCallback) {
  747. // // Shader
  748. var shader = false,
  749. // Vertex buffers - keyed on shader attribute name
  750. vbuffer = false,
  751. vlen = 0,
  752. // Opengl context
  753. gl = false,
  754. // Width of our viewport in pixels
  755. width = 0,
  756. // Height of our viewport in pixels
  757. height = 0,
  758. // The data to render - array of coordinates
  759. data = false,
  760. // The marker data
  761. markerData = false,
  762. // Exports
  763. exports = {},
  764. // Is it inited?
  765. isInited = false,
  766. // The series stack
  767. series = [],
  768. // Texture handles
  769. textureHandles = {},
  770. // Things to draw as "rectangles" (i.e lines)
  771. asBar = {
  772. 'column': true,
  773. 'columnrange': true,
  774. 'bar': true,
  775. 'area': true,
  776. 'arearange': true
  777. },
  778. asCircle = {
  779. 'scatter': true,
  780. 'bubble': true
  781. },
  782. // Render settings
  783. settings = {
  784. pointSize: 1,
  785. lineWidth: 1,
  786. fillColor: '#AA00AA',
  787. useAlpha: true,
  788. usePreallocated: false,
  789. useGPUTranslations: false,
  790. debug: {
  791. timeRendering: false,
  792. timeSeriesProcessing: false,
  793. timeSetup: false,
  794. timeBufferCopy: false,
  795. timeKDTree: false,
  796. showSkipSummary: false
  797. }
  798. };
  799. // /////////////////////////////////////////////////////////////////////////
  800. /**
  801. * @private
  802. */
  803. function setOptions(options) {
  804. merge(true, settings, options);
  805. }
  806. /**
  807. * @private
  808. */
  809. function seriesPointCount(series) {
  810. var isStacked,
  811. xData,
  812. s;
  813. if (series.isSeriesBoosting) {
  814. isStacked = !!series.options.stacking;
  815. xData = (series.xData ||
  816. series.options.xData ||
  817. series.processedXData);
  818. s = (isStacked ? series.data : (xData || series.options.data))
  819. .length;
  820. if (series.type === 'treemap') {
  821. s *= 12;
  822. }
  823. else if (series.type === 'heatmap') {
  824. s *= 6;
  825. }
  826. else if (asBar[series.type]) {
  827. s *= 2;
  828. }
  829. return s;
  830. }
  831. return 0;
  832. }
  833. /**
  834. * Allocate a float buffer to fit all series
  835. * @private
  836. */
  837. function allocateBuffer(chart) {
  838. var s = 0;
  839. if (!settings.usePreallocated) {
  840. return;
  841. }
  842. chart.series.forEach(function (series) {
  843. if (series.isSeriesBoosting) {
  844. s += seriesPointCount(series);
  845. }
  846. });
  847. vbuffer.allocate(s);
  848. }
  849. /**
  850. * @private
  851. */
  852. function allocateBufferForSingleSeries(series) {
  853. var s = 0;
  854. if (!settings.usePreallocated) {
  855. return;
  856. }
  857. if (series.isSeriesBoosting) {
  858. s = seriesPointCount(series);
  859. }
  860. vbuffer.allocate(s);
  861. }
  862. /**
  863. * Returns an orthographic perspective matrix
  864. * @private
  865. * @param {number} width - the width of the viewport in pixels
  866. * @param {number} height - the height of the viewport in pixels
  867. */
  868. function orthoMatrix(width, height) {
  869. var near = 0,
  870. far = 1;
  871. return [
  872. 2 / width, 0, 0, 0,
  873. 0, -(2 / height), 0, 0,
  874. 0, 0, -2 / (far - near), 0,
  875. -1, 1, -(far + near) / (far - near), 1
  876. ];
  877. }
  878. /**
  879. * Clear the depth and color buffer
  880. * @private
  881. */
  882. function clear() {
  883. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  884. }
  885. /**
  886. * Get the WebGL context
  887. * @private
  888. * @returns {WebGLContext} - the context
  889. */
  890. function getGL() {
  891. return gl;
  892. }
  893. /**
  894. * Push data for a single series
  895. * This calculates additional vertices and transforms the data to be
  896. * aligned correctly in memory
  897. * @private
  898. */
  899. function pushSeriesData(series, inst) {
  900. var isRange = (series.pointArrayMap &&
  901. series.pointArrayMap.join(',') === 'low,high'), chart = series.chart, options = series.options, isStacked = !!options.stacking, rawData = options.data, xExtremes = series.xAxis.getExtremes(), xMin = xExtremes.min, xMax = xExtremes.max, yExtremes = series.yAxis.getExtremes(), yMin = yExtremes.min, yMax = yExtremes.max, xData = series.xData || options.xData || series.processedXData, yData = series.yData || options.yData || series.processedYData, zData = (series.zData || options.zData ||
  902. series.processedZData), yAxis = series.yAxis, xAxis = series.xAxis,
  903. // plotHeight = series.chart.plotHeight,
  904. plotWidth = series.chart.plotWidth, useRaw = !xData || xData.length === 0,
  905. // threshold = options.threshold,
  906. // yBottom = chart.yAxis[0].getThreshold(threshold),
  907. // hasThreshold = isNumber(threshold),
  908. // colorByPoint = series.options.colorByPoint,
  909. // This is required for color by point, so make sure this is
  910. // uncommented if enabling that
  911. // colorIndex = 0,
  912. // Required for color axis support
  913. // caxis,
  914. connectNulls = options.connectNulls,
  915. // For some reason eslint/TypeScript don't pick up that this is
  916. // actually used: --- bre1470: it is never read, just set
  917. // maxVal: (number|undefined), // eslint-disable-line no-unused-vars
  918. points = series.points || false, lastX = false, lastY = false, minVal, scolor, sdata = isStacked ? series.data : (xData || rawData), closestLeft = { x: Number.MAX_VALUE, y: 0 }, closestRight = { x: -Number.MAX_VALUE, y: 0 },
  919. //
  920. skipped = 0, hadPoints = false,
  921. //
  922. cullXThreshold = 1, cullYThreshold = 1,
  923. // The following are used in the builder while loop
  924. x, y, d, z, i = -1, px = false, nx = false, low, chartDestroyed = typeof chart.index === 'undefined', nextInside = false, prevInside = false, pcolor = false, drawAsBar = asBar[series.type], isXInside = false, isYInside = true, firstPoint = true, zoneAxis = options.zoneAxis || 'y', zones = options.zones || false, zoneColors, zoneDefColor = false, threshold = options.threshold, gapSize = false;
  925. if (options.boostData && options.boostData.length > 0) {
  926. return;
  927. }
  928. if (options.gapSize) {
  929. gapSize = options.gapUnit !== 'value' ?
  930. options.gapSize * series.closestPointRange :
  931. options.gapSize;
  932. }
  933. if (zones) {
  934. zoneColors = [];
  935. zones.forEach(function (zone, i) {
  936. if (zone.color) {
  937. var zoneColor = color(zone.color).rgba;
  938. zoneColor[0] /= 255.0;
  939. zoneColor[1] /= 255.0;
  940. zoneColor[2] /= 255.0;
  941. zoneColors[i] = zoneColor;
  942. if (!zoneDefColor && typeof zone.value === 'undefined') {
  943. zoneDefColor = zoneColor;
  944. }
  945. }
  946. });
  947. if (!zoneDefColor) {
  948. var seriesColor = ((series.pointAttribs && series.pointAttribs().fill) ||
  949. series.color);
  950. zoneDefColor = color(seriesColor).rgba;
  951. zoneDefColor[0] /= 255.0;
  952. zoneDefColor[1] /= 255.0;
  953. zoneDefColor[2] /= 255.0;
  954. }
  955. }
  956. if (chart.inverted) {
  957. // plotHeight = series.chart.plotWidth;
  958. plotWidth = series.chart.plotHeight;
  959. }
  960. series.closestPointRangePx = Number.MAX_VALUE;
  961. /**
  962. * Push color to color buffer - need to do this per vertex.
  963. * @private
  964. */
  965. function pushColor(color) {
  966. if (color) {
  967. inst.colorData.push(color[0]);
  968. inst.colorData.push(color[1]);
  969. inst.colorData.push(color[2]);
  970. inst.colorData.push(color[3]);
  971. }
  972. }
  973. /**
  974. * Push a vertice to the data buffer.
  975. * @private
  976. */
  977. function vertice(x, y, checkTreshold, pointSize, color) {
  978. pushColor(color);
  979. if (settings.usePreallocated) {
  980. vbuffer.push(x, y, checkTreshold ? 1 : 0, pointSize || 1);
  981. vlen += 4;
  982. }
  983. else {
  984. data.push(x);
  985. data.push(y);
  986. data.push(checkTreshold ? 1 : 0);
  987. data.push(pointSize || 1);
  988. }
  989. }
  990. /**
  991. * @private
  992. */
  993. function closeSegment() {
  994. if (inst.segments.length) {
  995. inst.segments[inst.segments.length - 1].to = data.length || vlen;
  996. }
  997. }
  998. /**
  999. * Create a new segment for the current set.
  1000. * @private
  1001. */
  1002. function beginSegment() {
  1003. // Insert a segment on the series.
  1004. // A segment is just a start indice.
  1005. // When adding a segment, if one exists from before, it should
  1006. // set the previous segment's end
  1007. if (inst.segments.length &&
  1008. inst.segments[inst.segments.length - 1].from === (data.length || vlen)) {
  1009. return;
  1010. }
  1011. closeSegment();
  1012. inst.segments.push({
  1013. from: data.length || vlen
  1014. });
  1015. }
  1016. /**
  1017. * Push a rectangle to the data buffer.
  1018. * @private
  1019. */
  1020. function pushRect(x, y, w, h, color) {
  1021. pushColor(color);
  1022. vertice(x + w, y);
  1023. pushColor(color);
  1024. vertice(x, y);
  1025. pushColor(color);
  1026. vertice(x, y + h);
  1027. pushColor(color);
  1028. vertice(x, y + h);
  1029. pushColor(color);
  1030. vertice(x + w, y + h);
  1031. pushColor(color);
  1032. vertice(x + w, y);
  1033. }
  1034. // Create the first segment
  1035. beginSegment();
  1036. // Special case for point shapes
  1037. if (points && points.length > 0) {
  1038. // If we're doing points, we assume that the points are already
  1039. // translated, so we skip the shader translation.
  1040. inst.skipTranslation = true;
  1041. // Force triangle draw mode
  1042. inst.drawMode = 'triangles';
  1043. // We don't have a z component in the shader, so we need to sort.
  1044. if (points[0].node && points[0].node.levelDynamic) {
  1045. points.sort(function (a, b) {
  1046. if (a.node) {
  1047. if (a.node.levelDynamic >
  1048. b.node.levelDynamic) {
  1049. return 1;
  1050. }
  1051. if (a.node.levelDynamic <
  1052. b.node.levelDynamic) {
  1053. return -1;
  1054. }
  1055. }
  1056. return 0;
  1057. });
  1058. }
  1059. points.forEach(function (point) {
  1060. var plotY = point.plotY,
  1061. swidth,
  1062. pointAttr;
  1063. if (typeof plotY !== 'undefined' &&
  1064. !isNaN(plotY) &&
  1065. point.y !== null &&
  1066. point.shapeArgs) {
  1067. var _a = point.shapeArgs,
  1068. _b = _a.x,
  1069. x_1 = _b === void 0 ? 0 : _b,
  1070. _c = _a.y,
  1071. y_1 = _c === void 0 ? 0 : _c,
  1072. _d = _a.width,
  1073. width_1 = _d === void 0 ? 0 : _d,
  1074. _e = _a.height,
  1075. height_1 = _e === void 0 ? 0 : _e;
  1076. pointAttr = chart.styledMode ?
  1077. point.series
  1078. .colorAttribs(point) :
  1079. pointAttr = point.series.pointAttribs(point);
  1080. swidth = pointAttr['stroke-width'] || 0;
  1081. // Handle point colors
  1082. pcolor = color(pointAttr.fill).rgba;
  1083. pcolor[0] /= 255.0;
  1084. pcolor[1] /= 255.0;
  1085. pcolor[2] /= 255.0;
  1086. // So there are two ways of doing this. Either we can
  1087. // create a rectangle of two triangles, or we can do a
  1088. // point and use point size. Latter is faster, but
  1089. // only supports squares. So we're doing triangles.
  1090. // We could also use one color per. vertice to get
  1091. // better color interpolation.
  1092. // If there's stroking, we do an additional rect
  1093. if (series.type === 'treemap') {
  1094. swidth = swidth || 1;
  1095. scolor = color(pointAttr.stroke).rgba;
  1096. scolor[0] /= 255.0;
  1097. scolor[1] /= 255.0;
  1098. scolor[2] /= 255.0;
  1099. pushRect(x_1, y_1, width_1, height_1, scolor);
  1100. swidth /= 2;
  1101. }
  1102. // } else {
  1103. // swidth = 0;
  1104. // }
  1105. // Fixes issues with inverted heatmaps (see #6981)
  1106. // The root cause is that the coordinate system is flipped.
  1107. // In other words, instead of [0,0] being top-left, it's
  1108. // bottom-right. This causes a vertical and horizontal flip
  1109. // in the resulting image, making it rotated 180 degrees.
  1110. if (series.type === 'heatmap' && chart.inverted) {
  1111. x_1 = xAxis.len - x_1;
  1112. y_1 = yAxis.len - y_1;
  1113. width_1 = -width_1;
  1114. height_1 = -height_1;
  1115. }
  1116. pushRect(x_1 + swidth, y_1 + swidth, width_1 - (swidth * 2), height_1 - (swidth * 2), pcolor);
  1117. }
  1118. });
  1119. closeSegment();
  1120. return;
  1121. }
  1122. var _loop_1 = function () {
  1123. d = sdata[++i];
  1124. if (typeof d === 'undefined') {
  1125. return "continue";
  1126. }
  1127. // px = x = y = z = nx = low = false;
  1128. // chartDestroyed = typeof chart.index === 'undefined';
  1129. // nextInside = prevInside = pcolor = isXInside = isYInside = false;
  1130. // drawAsBar = asBar[series.type];
  1131. if (chartDestroyed) {
  1132. return "break";
  1133. }
  1134. // Uncomment this to enable color by point.
  1135. // This currently left disabled as the charts look really ugly
  1136. // when enabled and there's a lot of points.
  1137. // Leaving in for the future (tm).
  1138. // if (colorByPoint) {
  1139. // colorIndex = ++colorIndex %
  1140. // series.chart.options.colors.length;
  1141. // pcolor = toRGBAFast(series.chart.options.colors[colorIndex]);
  1142. // pcolor[0] /= 255.0;
  1143. // pcolor[1] /= 255.0;
  1144. // pcolor[2] /= 255.0;
  1145. // }
  1146. // Handle the point.color option (#5999)
  1147. var pointOptions = rawData && rawData[i];
  1148. if (!useRaw && isObject(pointOptions, true)) {
  1149. if (pointOptions.color) {
  1150. pcolor = color(pointOptions.color).rgba;
  1151. pcolor[0] /= 255.0;
  1152. pcolor[1] /= 255.0;
  1153. pcolor[2] /= 255.0;
  1154. }
  1155. }
  1156. if (useRaw) {
  1157. x = d[0];
  1158. y = d[1];
  1159. if (sdata[i + 1]) {
  1160. nx = sdata[i + 1][0];
  1161. }
  1162. if (sdata[i - 1]) {
  1163. px = sdata[i - 1][0];
  1164. }
  1165. if (d.length >= 3) {
  1166. z = d[2];
  1167. if (d[2] > inst.zMax) {
  1168. inst.zMax = d[2];
  1169. }
  1170. if (d[2] < inst.zMin) {
  1171. inst.zMin = d[2];
  1172. }
  1173. }
  1174. }
  1175. else {
  1176. x = d;
  1177. y = yData[i];
  1178. if (sdata[i + 1]) {
  1179. nx = sdata[i + 1];
  1180. }
  1181. if (sdata[i - 1]) {
  1182. px = sdata[i - 1];
  1183. }
  1184. if (zData && zData.length) {
  1185. z = zData[i];
  1186. if (zData[i] > inst.zMax) {
  1187. inst.zMax = zData[i];
  1188. }
  1189. if (zData[i] < inst.zMin) {
  1190. inst.zMin = zData[i];
  1191. }
  1192. }
  1193. }
  1194. if (!connectNulls && (x === null || y === null)) {
  1195. beginSegment();
  1196. return "continue";
  1197. }
  1198. if (nx && nx >= xMin && nx <= xMax) {
  1199. nextInside = true;
  1200. }
  1201. if (px && px >= xMin && px <= xMax) {
  1202. prevInside = true;
  1203. }
  1204. if (isRange) {
  1205. if (useRaw) {
  1206. y = d.slice(1, 3);
  1207. }
  1208. low = y[0];
  1209. y = y[1];
  1210. }
  1211. else if (isStacked) {
  1212. x = d.x;
  1213. y = d.stackY;
  1214. low = y - d.y;
  1215. }
  1216. if (yMin !== null &&
  1217. typeof yMin !== 'undefined' &&
  1218. yMax !== null &&
  1219. typeof yMax !== 'undefined') {
  1220. isYInside = y >= yMin && y <= yMax;
  1221. }
  1222. if (x > xMax && closestRight.x < xMax) {
  1223. closestRight.x = x;
  1224. closestRight.y = y;
  1225. }
  1226. if (x < xMin && closestLeft.x > xMin) {
  1227. closestLeft.x = x;
  1228. closestLeft.y = y;
  1229. }
  1230. if (y === null && connectNulls) {
  1231. return "continue";
  1232. }
  1233. // Cull points outside the extremes
  1234. if (y === null || (!isYInside && !nextInside && !prevInside)) {
  1235. beginSegment();
  1236. return "continue";
  1237. }
  1238. // The first point before and first after extremes should be
  1239. // rendered (#9962)
  1240. if ((nx >= xMin || x >= xMin) &&
  1241. (px <= xMax || x <= xMax)) {
  1242. isXInside = true;
  1243. }
  1244. if (!isXInside && !nextInside && !prevInside) {
  1245. return "continue";
  1246. }
  1247. if (gapSize && x - px > gapSize) {
  1248. beginSegment();
  1249. }
  1250. // Note: Boost requires that zones are sorted!
  1251. if (zones) {
  1252. var zoneColor_1;
  1253. zones.some(function (// eslint-disable-line no-loop-func
  1254. zone, i) {
  1255. var last = zones[i - 1];
  1256. if (zoneAxis === 'x') {
  1257. if (typeof zone.value !== 'undefined' && x <= zone.value) {
  1258. if (zoneColors[i] && (!last || x >= last.value)) {
  1259. zoneColor_1 = zoneColors[i];
  1260. }
  1261. return true;
  1262. }
  1263. return false;
  1264. }
  1265. if (typeof zone.value !== 'undefined' && y <= zone.value) {
  1266. if (zoneColors[i] && (!last || y >= last.value)) {
  1267. zoneColor_1 = zoneColors[i];
  1268. }
  1269. return true;
  1270. }
  1271. return false;
  1272. });
  1273. pcolor = zoneColor_1 || zoneDefColor || pcolor;
  1274. }
  1275. // Skip translations - temporary floating point fix
  1276. if (!settings.useGPUTranslations) {
  1277. inst.skipTranslation = true;
  1278. x = xAxis.toPixels(x, true);
  1279. y = yAxis.toPixels(y, true);
  1280. // Make sure we're not drawing outside of the chart area.
  1281. // See #6594. Update: this is no longer required as far as I
  1282. // can tell. Leaving in for git blame in case there are edge
  1283. // cases I've not found. Having this in breaks #10246.
  1284. // if (y > plotHeight) {
  1285. // y = plotHeight;
  1286. // }
  1287. if (x > plotWidth) {
  1288. // If this is rendered as a point, just skip drawing it
  1289. // entirely, as we're not dependandt on lineTo'ing to it.
  1290. // See #8197
  1291. if (inst.drawMode === 'points') {
  1292. return "continue";
  1293. }
  1294. // Having this here will clamp markers and make the angle
  1295. // of the last line wrong. See 9166.
  1296. // x = plotWidth;
  1297. }
  1298. }
  1299. // No markers on out of bounds things.
  1300. // Out of bound things are shown if and only if the next
  1301. // or previous point is inside the rect.
  1302. if (inst.hasMarkers && isXInside) {
  1303. // x = Highcharts.correctFloat(
  1304. // Math.min(Math.max(-1e5, xAxis.translate(
  1305. // x,
  1306. // 0,
  1307. // 0,
  1308. // 0,
  1309. // 1,
  1310. // 0.5,
  1311. // false
  1312. // )), 1e5)
  1313. // );
  1314. if (lastX !== false) {
  1315. series.closestPointRangePx = Math.min(series.closestPointRangePx, Math.abs(x - lastX));
  1316. }
  1317. }
  1318. // If the last _drawn_ point is closer to this point than the
  1319. // threshold, skip it. Shaves off 20-100ms in processing.
  1320. if (!settings.useGPUTranslations &&
  1321. !settings.usePreallocated &&
  1322. (lastX && Math.abs(x - lastX) < cullXThreshold) &&
  1323. (lastY && Math.abs(y - lastY) < cullYThreshold)) {
  1324. if (settings.debug.showSkipSummary) {
  1325. ++skipped;
  1326. }
  1327. return "continue";
  1328. }
  1329. if (drawAsBar) {
  1330. // maxVal = y;
  1331. minVal = low;
  1332. if (low === false || typeof low === 'undefined') {
  1333. if (y < 0) {
  1334. minVal = y;
  1335. }
  1336. else {
  1337. minVal = 0;
  1338. }
  1339. }
  1340. if (!isRange && !isStacked) {
  1341. minVal = Math.max(threshold === null ? yMin : threshold, // #5268
  1342. yMin); // #8731
  1343. }
  1344. if (!settings.useGPUTranslations) {
  1345. minVal = yAxis.toPixels(minVal, true);
  1346. }
  1347. // Need to add an extra point here
  1348. vertice(x, minVal, 0, 0, pcolor);
  1349. }
  1350. // Do step line if enabled.
  1351. // Draws an additional point at the old Y at the new X.
  1352. // See #6976.
  1353. if (options.step && !firstPoint) {
  1354. vertice(x, lastY, 0, 2, pcolor);
  1355. }
  1356. vertice(x, y, 0, series.type === 'bubble' ? (z || 1) : 2, pcolor);
  1357. // Uncomment this to support color axis.
  1358. // if (caxis) {
  1359. // pcolor = color(caxis.toColor(y)).rgba;
  1360. // inst.colorData.push(color[0] / 255.0);
  1361. // inst.colorData.push(color[1] / 255.0);
  1362. // inst.colorData.push(color[2] / 255.0);
  1363. // inst.colorData.push(color[3]);
  1364. // }
  1365. lastX = x;
  1366. lastY = y;
  1367. hadPoints = true;
  1368. firstPoint = false;
  1369. };
  1370. // Extract color axis
  1371. // (chart.axes || []).forEach(function (a) {
  1372. // if (H.ColorAxis && a instanceof H.ColorAxis) {
  1373. // caxis = a;
  1374. // }
  1375. // });
  1376. while (i < sdata.length - 1) {
  1377. var state_1 = _loop_1();
  1378. if (state_1 === "break")
  1379. break;
  1380. }
  1381. if (settings.debug.showSkipSummary) {
  1382. console.log('skipped points:', skipped); // eslint-disable-line no-console
  1383. }
  1384. /**
  1385. * @private
  1386. */
  1387. function pushSupplementPoint(point, atStart) {
  1388. if (!settings.useGPUTranslations) {
  1389. inst.skipTranslation = true;
  1390. point.x = xAxis.toPixels(point.x, true);
  1391. point.y = yAxis.toPixels(point.y, true);
  1392. }
  1393. // We should only do this for lines, and we should ignore markers
  1394. // since there's no point here that would have a marker.
  1395. if (atStart) {
  1396. data = [point.x, point.y, 0, 2].concat(data);
  1397. return;
  1398. }
  1399. vertice(point.x, point.y, 0, 2);
  1400. }
  1401. if (!hadPoints &&
  1402. connectNulls !== false &&
  1403. series.drawMode === 'line_strip') {
  1404. if (closestLeft.x < Number.MAX_VALUE) {
  1405. // We actually need to push this *before* the complete buffer.
  1406. pushSupplementPoint(closestLeft, true);
  1407. }
  1408. if (closestRight.x > -Number.MAX_VALUE) {
  1409. pushSupplementPoint(closestRight);
  1410. }
  1411. }
  1412. closeSegment();
  1413. }
  1414. /**
  1415. * Push a series to the renderer
  1416. * If we render the series immediatly, we don't have to loop later
  1417. * @private
  1418. * @param s {Highchart.Series} - the series to push
  1419. */
  1420. function pushSeries(s) {
  1421. if (series.length > 0) {
  1422. // series[series.length - 1].to = data.length;
  1423. if (series[series.length - 1].hasMarkers) {
  1424. series[series.length - 1].markerTo = markerData.length;
  1425. }
  1426. }
  1427. if (settings.debug.timeSeriesProcessing) {
  1428. console.time('building ' + s.type + ' series'); // eslint-disable-line no-console
  1429. }
  1430. var obj = {
  1431. segments: [],
  1432. // from: data.length,
  1433. markerFrom: markerData.length,
  1434. // Push RGBA values to this array to use per. point coloring.
  1435. // It should be 0-padded, so each component should be pushed in
  1436. // succession.
  1437. colorData: [],
  1438. series: s,
  1439. zMin: Number.MAX_VALUE,
  1440. zMax: -Number.MAX_VALUE,
  1441. hasMarkers: s.options.marker ?
  1442. s.options.marker.enabled !== false :
  1443. false,
  1444. showMarkers: true,
  1445. drawMode: {
  1446. 'area': 'lines',
  1447. 'arearange': 'lines',
  1448. 'areaspline': 'line_strip',
  1449. 'column': 'lines',
  1450. 'columnrange': 'lines',
  1451. 'bar': 'lines',
  1452. 'line': 'line_strip',
  1453. 'scatter': 'points',
  1454. 'heatmap': 'triangles',
  1455. 'treemap': 'triangles',
  1456. 'bubble': 'points'
  1457. }[s.type] || 'line_strip'
  1458. };
  1459. if (s.index >= series.length) {
  1460. series.push(obj);
  1461. }
  1462. else {
  1463. series[s.index] = obj;
  1464. }
  1465. // Add the series data to our buffer(s)
  1466. pushSeriesData(s, obj);
  1467. if (settings.debug.timeSeriesProcessing) {
  1468. console.timeEnd('building ' + s.type + ' series'); // eslint-disable-line no-console
  1469. }
  1470. }
  1471. /**
  1472. * Flush the renderer.
  1473. * This removes pushed series and vertices.
  1474. * Should be called after clearing and before rendering
  1475. * @private
  1476. */
  1477. function flush() {
  1478. series = [];
  1479. exports.data = data = [];
  1480. markerData = [];
  1481. if (vbuffer) {
  1482. vbuffer.destroy();
  1483. }
  1484. }
  1485. /**
  1486. * Pass x-axis to shader
  1487. * @private
  1488. * @param axis {Highcharts.Axis} - the x-axis
  1489. */
  1490. function setXAxis(axis) {
  1491. if (!shader) {
  1492. return;
  1493. }
  1494. shader.setUniform('xAxisTrans', axis.transA);
  1495. shader.setUniform('xAxisMin', axis.min);
  1496. shader.setUniform('xAxisMinPad', axis.minPixelPadding);
  1497. shader.setUniform('xAxisPointRange', axis.pointRange);
  1498. shader.setUniform('xAxisLen', axis.len);
  1499. shader.setUniform('xAxisPos', axis.pos);
  1500. shader.setUniform('xAxisCVSCoord', (!axis.horiz));
  1501. shader.setUniform('xAxisIsLog', (!!axis.logarithmic));
  1502. shader.setUniform('xAxisReversed', (!!axis.reversed));
  1503. }
  1504. /**
  1505. * Pass y-axis to shader
  1506. * @private
  1507. * @param axis {Highcharts.Axis} - the y-axis
  1508. */
  1509. function setYAxis(axis) {
  1510. if (!shader) {
  1511. return;
  1512. }
  1513. shader.setUniform('yAxisTrans', axis.transA);
  1514. shader.setUniform('yAxisMin', axis.min);
  1515. shader.setUniform('yAxisMinPad', axis.minPixelPadding);
  1516. shader.setUniform('yAxisPointRange', axis.pointRange);
  1517. shader.setUniform('yAxisLen', axis.len);
  1518. shader.setUniform('yAxisPos', axis.pos);
  1519. shader.setUniform('yAxisCVSCoord', (!axis.horiz));
  1520. shader.setUniform('yAxisIsLog', (!!axis.logarithmic));
  1521. shader.setUniform('yAxisReversed', (!!axis.reversed));
  1522. }
  1523. /**
  1524. * Set the translation threshold
  1525. * @private
  1526. * @param has {boolean} - has threshold flag
  1527. * @param translation {Float} - the threshold
  1528. */
  1529. function setThreshold(has, translation) {
  1530. shader.setUniform('hasThreshold', has);
  1531. shader.setUniform('translatedThreshold', translation);
  1532. }
  1533. /**
  1534. * Render the data
  1535. * This renders all pushed series.
  1536. * @private
  1537. */
  1538. function render(chart) {
  1539. if (chart) {
  1540. if (!chart.chartHeight || !chart.chartWidth) {
  1541. // chart.setChartSize();
  1542. }
  1543. width = chart.chartWidth || 800;
  1544. height = chart.chartHeight || 400;
  1545. }
  1546. else {
  1547. return false;
  1548. }
  1549. if (!gl || !width || !height || !shader) {
  1550. return false;
  1551. }
  1552. if (settings.debug.timeRendering) {
  1553. console.time('gl rendering'); // eslint-disable-line no-console
  1554. }
  1555. gl.canvas.width = width;
  1556. gl.canvas.height = height;
  1557. shader.bind();
  1558. gl.viewport(0, 0, width, height);
  1559. shader.setPMatrix(orthoMatrix(width, height));
  1560. if (settings.lineWidth > 1 && !H.isMS) {
  1561. gl.lineWidth(settings.lineWidth);
  1562. }
  1563. vbuffer.build(exports.data, 'aVertexPosition', 4);
  1564. vbuffer.bind();
  1565. shader.setInverted(chart.inverted);
  1566. // Render the series
  1567. series.forEach(function (s, si) {
  1568. var options = s.series.options,
  1569. shapeOptions = options.marker,
  1570. sindex,
  1571. lineWidth = (typeof options.lineWidth !== 'undefined' ?
  1572. options.lineWidth :
  1573. 1),
  1574. threshold = options.threshold,
  1575. hasThreshold = isNumber(threshold),
  1576. yBottom = s.series.yAxis.getThreshold(threshold),
  1577. translatedThreshold = yBottom,
  1578. cbuffer,
  1579. showMarkers = pick(options.marker ? options.marker.enabled : null,
  1580. s.series.xAxis.isRadial ? true : null,
  1581. s.series.closestPointRangePx >
  1582. 2 * ((options.marker ?
  1583. options.marker.radius :
  1584. 10) || 10)),
  1585. fillColor,
  1586. shapeTexture = textureHandles[(shapeOptions && shapeOptions.symbol) ||
  1587. s.series.symbol] || textureHandles.circle,
  1588. scolor = [];
  1589. if (s.segments.length === 0 ||
  1590. s.segments[0].from === s.segments[0].to) {
  1591. return;
  1592. }
  1593. if (shapeTexture.isReady) {
  1594. gl.bindTexture(gl.TEXTURE_2D, shapeTexture.handle);
  1595. shader.setTexture(shapeTexture.handle);
  1596. }
  1597. if (chart.styledMode) {
  1598. fillColor = (s.series.markerGroup &&
  1599. s.series.markerGroup.getStyle('fill'));
  1600. }
  1601. else {
  1602. fillColor =
  1603. (s.drawMode === 'points' && // #14260
  1604. s.series.pointAttribs &&
  1605. s.series.pointAttribs().fill) ||
  1606. s.series.color;
  1607. if (options.colorByPoint) {
  1608. fillColor = s.series.chart.options.colors[si];
  1609. }
  1610. }
  1611. if (s.series.fillOpacity && options.fillOpacity) {
  1612. fillColor = new Color(fillColor).setOpacity(pick(options.fillOpacity, 1.0)).get();
  1613. }
  1614. scolor = color(fillColor).rgba;
  1615. if (!settings.useAlpha) {
  1616. scolor[3] = 1.0;
  1617. }
  1618. // This is very much temporary
  1619. if (s.drawMode === 'lines' &&
  1620. settings.useAlpha &&
  1621. scolor[3] < 1) {
  1622. scolor[3] /= 10;
  1623. }
  1624. // Blending
  1625. if (options.boostBlending === 'add') {
  1626. gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
  1627. gl.blendEquation(gl.FUNC_ADD);
  1628. }
  1629. else if (options.boostBlending === 'mult' ||
  1630. options.boostBlending === 'multiply') {
  1631. gl.blendFunc(gl.DST_COLOR, gl.ZERO);
  1632. }
  1633. else if (options.boostBlending === 'darken') {
  1634. gl.blendFunc(gl.ONE, gl.ONE);
  1635. gl.blendEquation(gl.FUNC_MIN);
  1636. }
  1637. else {
  1638. // gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  1639. // gl.blendEquation(gl.FUNC_ADD);
  1640. gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
  1641. }
  1642. shader.reset();
  1643. // If there are entries in the colorData buffer, build and bind it.
  1644. if (s.colorData.length > 0) {
  1645. shader.setUniform('hasColor', 1.0);
  1646. cbuffer = GLVertexBuffer(gl, shader); // eslint-disable-line new-cap
  1647. cbuffer.build(s.colorData, 'aColor', 4);
  1648. cbuffer.bind();
  1649. }
  1650. // Set series specific uniforms
  1651. shader.setColor(scolor);
  1652. setXAxis(s.series.xAxis);
  1653. setYAxis(s.series.yAxis);
  1654. setThreshold(hasThreshold, translatedThreshold);
  1655. if (s.drawMode === 'points') {
  1656. if (options.marker && isNumber(options.marker.radius)) {
  1657. shader.setPointSize(options.marker.radius * 2.0);
  1658. }
  1659. else {
  1660. shader.setPointSize(1);
  1661. }
  1662. }
  1663. // If set to true, the toPixels translations in the shader
  1664. // is skipped, i.e it's assumed that the value is a pixel coord.
  1665. shader.setSkipTranslation(s.skipTranslation);
  1666. if (s.series.type === 'bubble') {
  1667. shader.setBubbleUniforms(s.series, s.zMin, s.zMax);
  1668. }
  1669. shader.setDrawAsCircle(asCircle[s.series.type] || false);
  1670. // Do the actual rendering
  1671. // If the line width is < 0, skip rendering of the lines. See #7833.
  1672. if (lineWidth > 0 || s.drawMode !== 'line_strip') {
  1673. for (sindex = 0; sindex < s.segments.length; sindex++) {
  1674. // if (s.segments[sindex].from < s.segments[sindex].to) {
  1675. vbuffer.render(s.segments[sindex].from, s.segments[sindex].to, s.drawMode);
  1676. // }
  1677. }
  1678. }
  1679. if (s.hasMarkers && showMarkers) {
  1680. if (options.marker && isNumber(options.marker.radius)) {
  1681. shader.setPointSize(options.marker.radius * 2.0);
  1682. }
  1683. else {
  1684. shader.setPointSize(10);
  1685. }
  1686. shader.setDrawAsCircle(true);
  1687. for (sindex = 0; sindex < s.segments.length; sindex++) {
  1688. // if (s.segments[sindex].from < s.segments[sindex].to) {
  1689. vbuffer.render(s.segments[sindex].from, s.segments[sindex].to, 'POINTS');
  1690. // }
  1691. }
  1692. }
  1693. });
  1694. if (settings.debug.timeRendering) {
  1695. console.timeEnd('gl rendering'); // eslint-disable-line no-console
  1696. }
  1697. if (postRenderCallback) {
  1698. postRenderCallback();
  1699. }
  1700. flush();
  1701. }
  1702. /**
  1703. * Render the data when ready
  1704. * @private
  1705. */
  1706. function renderWhenReady(chart) {
  1707. clear();
  1708. if (chart.renderer.forExport) {
  1709. return render(chart);
  1710. }
  1711. if (isInited) {
  1712. render(chart);
  1713. }
  1714. else {
  1715. setTimeout(function () {
  1716. renderWhenReady(chart);
  1717. }, 1);
  1718. }
  1719. }
  1720. /**
  1721. * Set the viewport size in pixels
  1722. * Creates an orthographic perspective matrix and applies it.
  1723. * @private
  1724. * @param w {Integer} - the width of the viewport
  1725. * @param h {Integer} - the height of the viewport
  1726. */
  1727. function setSize(w, h) {
  1728. // Skip if there's no change, or if we have no valid shader
  1729. if ((width === w && height === h) || !shader) {
  1730. return;
  1731. }
  1732. width = w;
  1733. height = h;
  1734. shader.bind();
  1735. shader.setPMatrix(orthoMatrix(width, height));
  1736. }
  1737. /**
  1738. * Init OpenGL
  1739. * @private
  1740. * @param canvas {HTMLCanvas} - the canvas to render to
  1741. */
  1742. function init(canvas, noFlush) {
  1743. var i = 0,
  1744. contexts = [
  1745. 'webgl',
  1746. 'experimental-webgl',
  1747. 'moz-webgl',
  1748. 'webkit-3d'
  1749. ];
  1750. isInited = false;
  1751. if (!canvas) {
  1752. return false;
  1753. }
  1754. if (settings.debug.timeSetup) {
  1755. console.time('gl setup'); // eslint-disable-line no-console
  1756. }
  1757. for (; i < contexts.length; i++) {
  1758. gl = canvas.getContext(contexts[i], {
  1759. // premultipliedAlpha: false
  1760. });
  1761. if (gl) {
  1762. break;
  1763. }
  1764. }
  1765. if (gl) {
  1766. if (!noFlush) {
  1767. flush();
  1768. }
  1769. }
  1770. else {
  1771. return false;
  1772. }
  1773. gl.enable(gl.BLEND);
  1774. // gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
  1775. gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
  1776. gl.disable(gl.DEPTH_TEST);
  1777. // gl.depthMask(gl.FALSE);
  1778. gl.depthFunc(gl.LESS);
  1779. shader = GLShader(gl); // eslint-disable-line new-cap
  1780. if (!shader) {
  1781. // We need to abort, there's no shader context
  1782. return false;
  1783. }
  1784. vbuffer = GLVertexBuffer(gl, shader); // eslint-disable-line new-cap
  1785. /**
  1786. * @private
  1787. */
  1788. function createTexture(name, fn) {
  1789. var props = {
  1790. isReady: false,
  1791. texture: doc.createElement('canvas'),
  1792. handle: gl.createTexture()
  1793. },
  1794. ctx = props.texture.getContext('2d');
  1795. textureHandles[name] = props;
  1796. props.texture.width = 512;
  1797. props.texture.height = 512;
  1798. ctx.mozImageSmoothingEnabled = false;
  1799. ctx.webkitImageSmoothingEnabled = false;
  1800. ctx.msImageSmoothingEnabled = false;
  1801. ctx.imageSmoothingEnabled = false;
  1802. ctx.strokeStyle = 'rgba(255, 255, 255, 0)';
  1803. ctx.fillStyle = '#FFF';
  1804. fn(ctx);
  1805. try {
  1806. gl.activeTexture(gl.TEXTURE0);
  1807. gl.bindTexture(gl.TEXTURE_2D, props.handle);
  1808. // gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
  1809. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, props.texture);
  1810. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  1811. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  1812. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  1813. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  1814. // gl.generateMipmap(gl.TEXTURE_2D);
  1815. gl.bindTexture(gl.TEXTURE_2D, null);
  1816. props.isReady = true;
  1817. }
  1818. catch (e) {
  1819. // silent error
  1820. }
  1821. }
  1822. // Circle shape
  1823. createTexture('circle', function (ctx) {
  1824. ctx.beginPath();
  1825. ctx.arc(256, 256, 256, 0, 2 * Math.PI);
  1826. ctx.stroke();
  1827. ctx.fill();
  1828. });
  1829. // Square shape
  1830. createTexture('square', function (ctx) {
  1831. ctx.fillRect(0, 0, 512, 512);
  1832. });
  1833. // Diamond shape
  1834. createTexture('diamond', function (ctx) {
  1835. ctx.beginPath();
  1836. ctx.moveTo(256, 0);
  1837. ctx.lineTo(512, 256);
  1838. ctx.lineTo(256, 512);
  1839. ctx.lineTo(0, 256);
  1840. ctx.lineTo(256, 0);
  1841. ctx.fill();
  1842. });
  1843. // Triangle shape
  1844. createTexture('triangle', function (ctx) {
  1845. ctx.beginPath();
  1846. ctx.moveTo(0, 512);
  1847. ctx.lineTo(256, 0);
  1848. ctx.lineTo(512, 512);
  1849. ctx.lineTo(0, 512);
  1850. ctx.fill();
  1851. });
  1852. // Triangle shape (rotated)
  1853. createTexture('triangle-down', function (ctx) {
  1854. ctx.beginPath();
  1855. ctx.moveTo(0, 0);
  1856. ctx.lineTo(256, 512);
  1857. ctx.lineTo(512, 0);
  1858. ctx.lineTo(0, 0);
  1859. ctx.fill();
  1860. });
  1861. isInited = true;
  1862. if (settings.debug.timeSetup) {
  1863. console.timeEnd('gl setup'); // eslint-disable-line no-console
  1864. }
  1865. return true;
  1866. }
  1867. /**
  1868. * Check if we have a valid OGL context
  1869. * @private
  1870. * @returns {Boolean} - true if the context is valid
  1871. */
  1872. function valid() {
  1873. return gl !== false;
  1874. }
  1875. /**
  1876. * Check if the renderer has been initialized
  1877. * @private
  1878. * @returns {Boolean} - true if it has, false if not
  1879. */
  1880. function inited() {
  1881. return isInited;
  1882. }
  1883. /**
  1884. * @private
  1885. */
  1886. function destroy() {
  1887. flush();
  1888. vbuffer.destroy();
  1889. shader.destroy();
  1890. if (gl) {
  1891. objectEach(textureHandles, function (texture) {
  1892. if (texture.handle) {
  1893. gl.deleteTexture(texture.handle);
  1894. }
  1895. });
  1896. gl.canvas.width = 1;
  1897. gl.canvas.height = 1;
  1898. }
  1899. }
  1900. // /////////////////////////////////////////////////////////////////////////
  1901. exports = {
  1902. allocateBufferForSingleSeries: allocateBufferForSingleSeries,
  1903. pushSeries: pushSeries,
  1904. setSize: setSize,
  1905. inited: inited,
  1906. setThreshold: setThreshold,
  1907. init: init,
  1908. render: renderWhenReady,
  1909. settings: settings,
  1910. valid: valid,
  1911. clear: clear,
  1912. flush: flush,
  1913. setXAxis: setXAxis,
  1914. setYAxis: setYAxis,
  1915. data: data,
  1916. gl: getGL,
  1917. allocateBuffer: allocateBuffer,
  1918. destroy: destroy,
  1919. setOptions: setOptions
  1920. };
  1921. return exports;
  1922. }
  1923. return GLRenderer;
  1924. });
  1925. _registerModule(_modules, 'Extensions/Boost/BoostAttach.js', [_modules['Core/Chart/Chart.js'], _modules['Extensions/Boost/WGLRenderer.js'], _modules['Core/Globals.js'], _modules['Core/Utilities.js']], function (Chart, GLRenderer, H, U) {
  1926. /* *
  1927. *
  1928. * Copyright (c) 2019-2021 Highsoft AS
  1929. *
  1930. * Boost module: stripped-down renderer for higher performance
  1931. *
  1932. * License: highcharts.com/license
  1933. *
  1934. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  1935. *
  1936. * */
  1937. var doc = H.doc;
  1938. var error = U.error;
  1939. var mainCanvas;
  1940. /**
  1941. * Create a canvas + context and attach it to the target
  1942. *
  1943. * @private
  1944. * @function createAndAttachRenderer
  1945. *
  1946. * @param {Highcharts.Chart} chart
  1947. * the chart
  1948. *
  1949. * @param {Highcharts.Series} series
  1950. * the series
  1951. *
  1952. * @return {Highcharts.BoostGLRenderer}
  1953. * the canvas renderer
  1954. */
  1955. function createAndAttachRenderer(chart, series) {
  1956. var width = chart.chartWidth, height = chart.chartHeight, target = chart, targetGroup = chart.seriesGroup || series.group, alpha = 1, foSupported = doc.implementation.hasFeature('www.http://w3.org/TR/SVG11/feature#Extensibility', '1.1');
  1957. if (chart.isChartSeriesBoosting()) {
  1958. target = chart;
  1959. }
  1960. else {
  1961. target = series;
  1962. }
  1963. // Support for foreignObject is flimsy as best.
  1964. // IE does not support it, and Chrome has a bug which messes up
  1965. // the canvas draw order.
  1966. // As such, we force the Image fallback for now, but leaving the
  1967. // actual Canvas path in-place in case this changes in the future.
  1968. foSupported = false;
  1969. if (!mainCanvas) {
  1970. mainCanvas = doc.createElement('canvas');
  1971. }
  1972. if (!target.renderTarget) {
  1973. target.canvas = mainCanvas;
  1974. // Fall back to image tag if foreignObject isn't supported,
  1975. // or if we're exporting.
  1976. if (chart.renderer.forExport || !foSupported) {
  1977. target.renderTarget = chart.renderer.image('', 0, 0, width, height)
  1978. .addClass('highcharts-boost-canvas')
  1979. .add(targetGroup);
  1980. target.boostClear = function () {
  1981. target.renderTarget.attr({ href: '' });
  1982. };
  1983. target.boostCopy = function () {
  1984. target.boostResizeTarget();
  1985. target.renderTarget.attr({
  1986. href: target.canvas.toDataURL('image/png')
  1987. });
  1988. };
  1989. }
  1990. else {
  1991. target.renderTargetFo = chart.renderer
  1992. .createElement('foreignObject')
  1993. .add(targetGroup);
  1994. target.renderTarget = doc.createElement('canvas');
  1995. target.renderTargetCtx =
  1996. target.renderTarget.getContext('2d');
  1997. target.renderTargetFo.element.appendChild(target.renderTarget);
  1998. target.boostClear = function () {
  1999. target.renderTarget.width =
  2000. target.canvas.width;
  2001. target.renderTarget.height =
  2002. target.canvas.height;
  2003. };
  2004. target.boostCopy = function () {
  2005. target.renderTarget.width =
  2006. target.canvas.width;
  2007. target.renderTarget.height =
  2008. target.canvas.height;
  2009. target.renderTargetCtx
  2010. .drawImage(target.canvas, 0, 0);
  2011. };
  2012. }
  2013. target.boostResizeTarget = function () {
  2014. width = chart.chartWidth;
  2015. height = chart.chartHeight;
  2016. (target.renderTargetFo || target.renderTarget)
  2017. .attr({
  2018. x: 0,
  2019. y: 0,
  2020. width: width,
  2021. height: height
  2022. })
  2023. .css({
  2024. pointerEvents: 'none',
  2025. mixedBlendMode: 'normal',
  2026. opacity: alpha
  2027. });
  2028. if (target instanceof Chart) {
  2029. target.markerGroup.translate(chart.plotLeft, chart.plotTop);
  2030. }
  2031. };
  2032. target.boostClipRect = chart.renderer.clipRect();
  2033. (target.renderTargetFo || target.renderTarget)
  2034. .clip(target.boostClipRect);
  2035. if (target instanceof Chart) {
  2036. target.markerGroup = target.renderer.g().add(targetGroup);
  2037. target.markerGroup.translate(series.xAxis.pos, series.yAxis.pos);
  2038. }
  2039. }
  2040. target.canvas.width = width;
  2041. target.canvas.height = height;
  2042. target.boostClipRect.attr(chart.getBoostClipRect(target));
  2043. target.boostResizeTarget();
  2044. target.boostClear();
  2045. if (!target.ogl) {
  2046. target.ogl = GLRenderer(function () {
  2047. if (target.ogl.settings.debug.timeBufferCopy) {
  2048. console.time('buffer copy'); // eslint-disable-line no-console
  2049. }
  2050. target.boostCopy();
  2051. if (target.ogl.settings.debug.timeBufferCopy) {
  2052. console.timeEnd('buffer copy'); // eslint-disable-line no-console
  2053. }
  2054. });
  2055. if (!target.ogl.init(target.canvas)) {
  2056. // The OGL renderer couldn't be inited.
  2057. // This likely means a shader error as we wouldn't get to this point
  2058. // if there was no WebGL support.
  2059. error('[highcharts boost] - unable to init WebGL renderer');
  2060. }
  2061. // target.ogl.clear();
  2062. target.ogl.setOptions(chart.options.boost || {});
  2063. if (target instanceof Chart) {
  2064. target.ogl.allocateBuffer(chart);
  2065. }
  2066. }
  2067. target.ogl.setSize(width, height);
  2068. return target.ogl;
  2069. }
  2070. return createAndAttachRenderer;
  2071. });
  2072. _registerModule(_modules, 'Extensions/Boost/BoostUtils.js', [_modules['Core/Globals.js'], _modules['Extensions/Boost/BoostableMap.js'], _modules['Extensions/Boost/BoostAttach.js'], _modules['Core/Utilities.js']], function (H, boostableMap, createAndAttachRenderer, U) {
  2073. /* *
  2074. *
  2075. * Copyright (c) 2019-2021 Highsoft AS
  2076. *
  2077. * Boost module: stripped-down renderer for higher performance
  2078. *
  2079. * License: highcharts.com/license
  2080. *
  2081. * This files contains generic utility functions used by the boost module.
  2082. *
  2083. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2084. *
  2085. * */
  2086. var win = H.win,
  2087. doc = H.doc;
  2088. var pick = U.pick;
  2089. // This should be a const.
  2090. var CHUNK_SIZE = 3000;
  2091. /**
  2092. * Tolerant max() function.
  2093. *
  2094. * @private
  2095. * @function patientMax
  2096. *
  2097. * @param {...Array<Array<unknown>>} args
  2098. * Max arguments
  2099. *
  2100. * @return {number}
  2101. * Max value
  2102. */
  2103. function patientMax() {
  2104. var args = [];
  2105. for (var _i = 0; _i < arguments.length; _i++) {
  2106. args[_i] = arguments[_i];
  2107. }
  2108. var r = -Number.MAX_VALUE;
  2109. args.forEach(function (t) {
  2110. if (typeof t !== 'undefined' &&
  2111. t !== null &&
  2112. typeof t.length !== 'undefined') {
  2113. // r = r < t.length ? t.length : r;
  2114. if (t.length > 0) {
  2115. r = t.length;
  2116. return true;
  2117. }
  2118. }
  2119. });
  2120. return r;
  2121. }
  2122. /**
  2123. * Return true if ths boost.enabled option is true
  2124. *
  2125. * @private
  2126. * @function boostEnabled
  2127. *
  2128. * @param {Highcharts.Chart} chart
  2129. * The chart
  2130. *
  2131. * @return {boolean}
  2132. * True, if boost is enabled.
  2133. */
  2134. function boostEnabled(chart) {
  2135. return pick((chart &&
  2136. chart.options &&
  2137. chart.options.boost &&
  2138. chart.options.boost.enabled), true);
  2139. }
  2140. /**
  2141. * Returns true if we should force boosting the chart
  2142. * @private
  2143. * @function shouldForceChartSeriesBoosting
  2144. *
  2145. * @param {Highcharts.Chart} chart
  2146. * The chart to check for forcing on
  2147. *
  2148. * @return {boolean}
  2149. * True, if boosting should be forced.
  2150. */
  2151. function shouldForceChartSeriesBoosting(chart) {
  2152. // If there are more than five series currently boosting,
  2153. // we should boost the whole chart to avoid running out of webgl contexts.
  2154. var sboostCount = 0,
  2155. canBoostCount = 0,
  2156. allowBoostForce = pick(chart.options.boost && chart.options.boost.allowForce,
  2157. true),
  2158. series;
  2159. if (typeof chart.boostForceChartBoost !== 'undefined') {
  2160. return chart.boostForceChartBoost;
  2161. }
  2162. if (chart.series.length > 1) {
  2163. for (var i = 0; i < chart.series.length; i++) {
  2164. series = chart.series[i];
  2165. // Don't count series with boostThreshold set to 0
  2166. // See #8950
  2167. // Also don't count if the series is hidden.
  2168. // See #9046
  2169. if (series.options.boostThreshold === 0 ||
  2170. series.visible === false) {
  2171. continue;
  2172. }
  2173. // Don't count heatmap series as they are handled differently.
  2174. // In the future we should make the heatmap/treemap path compatible
  2175. // with forcing. See #9636.
  2176. if (series.type === 'heatmap') {
  2177. continue;
  2178. }
  2179. if (boostableMap[series.type]) {
  2180. ++canBoostCount;
  2181. }
  2182. if (patientMax(series.processedXData, series.options.data,
  2183. // series.xData,
  2184. series.points) >= (series.options.boostThreshold || Number.MAX_VALUE)) {
  2185. ++sboostCount;
  2186. }
  2187. }
  2188. }
  2189. chart.boostForceChartBoost = allowBoostForce && ((canBoostCount === chart.series.length &&
  2190. sboostCount > 0) ||
  2191. sboostCount > 5);
  2192. return chart.boostForceChartBoost;
  2193. }
  2194. /* eslint-disable valid-jsdoc */
  2195. /**
  2196. * Performs the actual render if the renderer is
  2197. * attached to the series.
  2198. * @private
  2199. * @param renderer {OGLRenderer} - the renderer
  2200. * @param series {Highcharts.Series} - the series
  2201. */
  2202. function renderIfNotSeriesBoosting(renderer, series, chart) {
  2203. if (renderer &&
  2204. series.renderTarget &&
  2205. series.canvas &&
  2206. !(chart || series.chart).isChartSeriesBoosting()) {
  2207. renderer.render(chart || series.chart);
  2208. }
  2209. }
  2210. /**
  2211. * @private
  2212. */
  2213. function allocateIfNotSeriesBoosting(renderer, series) {
  2214. if (renderer &&
  2215. series.renderTarget &&
  2216. series.canvas &&
  2217. !series.chart.isChartSeriesBoosting()) {
  2218. renderer.allocateBufferForSingleSeries(series);
  2219. }
  2220. }
  2221. /**
  2222. * An "async" foreach loop. Uses a setTimeout to keep the loop from blocking the
  2223. * UI thread.
  2224. *
  2225. * @private
  2226. *
  2227. * @param arr {Array} - the array to loop through
  2228. * @param fn {Function} - the callback to call for each item
  2229. * @param finalFunc {Function} - the callback to call when done
  2230. * @param chunkSize {Number} - the number of iterations per timeout
  2231. * @param i {Number} - the current index
  2232. * @param noTimeout {Boolean} - set to true to skip timeouts
  2233. */
  2234. function eachAsync(arr, fn, finalFunc, chunkSize, i, noTimeout) {
  2235. i = i || 0;
  2236. chunkSize = chunkSize || CHUNK_SIZE;
  2237. var threshold = i + chunkSize,
  2238. proceed = true;
  2239. while (proceed && i < threshold && i < arr.length) {
  2240. proceed = fn(arr[i], i);
  2241. ++i;
  2242. }
  2243. if (proceed) {
  2244. if (i < arr.length) {
  2245. if (noTimeout) {
  2246. eachAsync(arr, fn, finalFunc, chunkSize, i, noTimeout);
  2247. }
  2248. else if (win.requestAnimationFrame) {
  2249. // If available, do requestAnimationFrame - shaves off a few ms
  2250. win.requestAnimationFrame(function () {
  2251. eachAsync(arr, fn, finalFunc, chunkSize, i);
  2252. });
  2253. }
  2254. else {
  2255. setTimeout(function () {
  2256. eachAsync(arr, fn, finalFunc, chunkSize, i);
  2257. });
  2258. }
  2259. }
  2260. else if (finalFunc) {
  2261. finalFunc();
  2262. }
  2263. }
  2264. }
  2265. /**
  2266. * Returns true if the current browser supports webgl
  2267. *
  2268. * @private
  2269. * @function hasWebGLSupport
  2270. *
  2271. * @return {boolean}
  2272. */
  2273. function hasWebGLSupport() {
  2274. var i = 0, canvas, contexts = ['webgl', 'experimental-webgl', 'moz-webgl', 'webkit-3d'], context = false;
  2275. if (typeof win.WebGLRenderingContext !== 'undefined') {
  2276. canvas = doc.createElement('canvas');
  2277. for (; i < contexts.length; i++) {
  2278. try {
  2279. context = canvas.getContext(contexts[i]);
  2280. if (typeof context !== 'undefined' && context !== null) {
  2281. return true;
  2282. }
  2283. }
  2284. catch (e) {
  2285. // silent error
  2286. }
  2287. }
  2288. }
  2289. return false;
  2290. }
  2291. /* eslint-disable no-invalid-this */
  2292. /**
  2293. * Used for treemap|heatmap.drawPoints
  2294. *
  2295. * @private
  2296. * @function pointDrawHandler
  2297. *
  2298. * @param {Function} proceed
  2299. *
  2300. * @return {*}
  2301. */
  2302. function pointDrawHandler(proceed) {
  2303. var enabled = true,
  2304. renderer;
  2305. if (this.chart.options && this.chart.options.boost) {
  2306. enabled = typeof this.chart.options.boost.enabled === 'undefined' ?
  2307. true :
  2308. this.chart.options.boost.enabled;
  2309. }
  2310. if (!enabled || !this.isSeriesBoosting) {
  2311. return proceed.call(this);
  2312. }
  2313. this.chart.isBoosting = true;
  2314. // Make sure we have a valid OGL context
  2315. renderer = createAndAttachRenderer(this.chart, this);
  2316. if (renderer) {
  2317. allocateIfNotSeriesBoosting(renderer, this);
  2318. renderer.pushSeries(this);
  2319. }
  2320. renderIfNotSeriesBoosting(renderer, this);
  2321. }
  2322. /* eslint-enable no-invalid-this, valid-jsdoc */
  2323. var funs = {
  2324. patientMax: patientMax,
  2325. boostEnabled: boostEnabled,
  2326. shouldForceChartSeriesBoosting: shouldForceChartSeriesBoosting,
  2327. renderIfNotSeriesBoosting: renderIfNotSeriesBoosting,
  2328. allocateIfNotSeriesBoosting: allocateIfNotSeriesBoosting,
  2329. eachAsync: eachAsync,
  2330. hasWebGLSupport: hasWebGLSupport,
  2331. pointDrawHandler: pointDrawHandler
  2332. };
  2333. // This needs to be fixed.
  2334. H.hasWebGLSupport = hasWebGLSupport;
  2335. return funs;
  2336. });
  2337. _registerModule(_modules, 'Extensions/Boost/BoostInit.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Globals.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js'], _modules['Extensions/Boost/BoostUtils.js'], _modules['Extensions/Boost/BoostAttach.js']], function (Chart, H, Series, SeriesRegistry, U, butils, createAndAttachRenderer) {
  2338. /* *
  2339. *
  2340. * Copyright (c) 2019-2021 Highsoft AS
  2341. *
  2342. * Boost module: stripped-down renderer for higher performance
  2343. *
  2344. * License: highcharts.com/license
  2345. *
  2346. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2347. *
  2348. * */
  2349. var noop = H.noop;
  2350. var seriesTypes = SeriesRegistry.seriesTypes;
  2351. var addEvent = U.addEvent,
  2352. extend = U.extend,
  2353. fireEvent = U.fireEvent,
  2354. wrap = U.wrap;
  2355. var eachAsync = butils.eachAsync,
  2356. pointDrawHandler = butils.pointDrawHandler,
  2357. allocateIfNotSeriesBoosting = butils.allocateIfNotSeriesBoosting,
  2358. renderIfNotSeriesBoosting = butils.renderIfNotSeriesBoosting,
  2359. shouldForceChartSeriesBoosting = butils.shouldForceChartSeriesBoosting,
  2360. index;
  2361. /* eslint-disable valid-jsdoc */
  2362. /**
  2363. * Initialize the boot module.
  2364. *
  2365. * @private
  2366. * @return {void}
  2367. */
  2368. function init() {
  2369. extend(Series.prototype, {
  2370. /**
  2371. * @private
  2372. * @function Highcharts.Series#renderCanvas
  2373. */
  2374. renderCanvas: function () {
  2375. var series = this, options = series.options || {}, renderer = false, chart = series.chart, xAxis = this.xAxis, yAxis = this.yAxis, xData = options.xData || series.processedXData, yData = options.yData || series.processedYData, rawData = options.data, xExtremes = xAxis.getExtremes(), xMin = xExtremes.min, xMax = xExtremes.max, yExtremes = yAxis.getExtremes(), yMin = yExtremes.min, yMax = yExtremes.max, pointTaken = {}, lastClientX, sampling = !!series.sampling, points, enableMouseTracking = options.enableMouseTracking !== false, threshold = options.threshold, yBottom = yAxis.getThreshold(threshold), isRange = series.pointArrayMap &&
  2376. series.pointArrayMap.join(',') === 'low,high', isStacked = !!options.stacking, cropStart = series.cropStart || 0, requireSorting = series.requireSorting, useRaw = !xData, minVal, maxVal, minI, maxI, boostOptions, compareX = options.findNearestPointBy === 'x', xDataFull = (this.xData ||
  2377. this.options.xData ||
  2378. this.processedXData ||
  2379. false), addKDPoint = function (clientX, plotY, i) {
  2380. // We need to do ceil on the clientX to make things
  2381. // snap to pixel values. The renderer will frequently
  2382. // draw stuff on "sub-pixels".
  2383. clientX = Math.ceil(clientX);
  2384. // Shaves off about 60ms compared to repeated concatenation
  2385. index = compareX ? clientX : clientX + ',' + plotY;
  2386. // The k-d tree requires series points.
  2387. // Reduce the amount of points, since the time to build the
  2388. // tree increases exponentially.
  2389. if (enableMouseTracking && !pointTaken[index]) {
  2390. pointTaken[index] = true;
  2391. if (chart.inverted) {
  2392. clientX = xAxis.len - clientX;
  2393. plotY = yAxis.len - plotY;
  2394. }
  2395. points.push({
  2396. x: xDataFull ? xDataFull[cropStart + i] : false,
  2397. clientX: clientX,
  2398. plotX: clientX,
  2399. plotY: plotY,
  2400. i: cropStart + i
  2401. });
  2402. }
  2403. };
  2404. // Get or create the renderer
  2405. renderer = createAndAttachRenderer(chart, series);
  2406. chart.isBoosting = true;
  2407. boostOptions = renderer.settings;
  2408. if (!this.visible) {
  2409. return;
  2410. }
  2411. // If we are zooming out from SVG mode, destroy the graphics
  2412. if (this.points || this.graph) {
  2413. this.destroyGraphics();
  2414. }
  2415. // If we're rendering per. series we should create the marker groups
  2416. // as usual.
  2417. if (!chart.isChartSeriesBoosting()) {
  2418. // If all series were boosting, but are not anymore
  2419. // restore private markerGroup
  2420. if (this.markerGroup === chart.markerGroup) {
  2421. this.markerGroup = void 0;
  2422. }
  2423. this.markerGroup = series.plotGroup('markerGroup', 'markers', true, 1, chart.seriesGroup);
  2424. }
  2425. else {
  2426. // If series has a private markeGroup, remove that
  2427. // and use common markerGroup
  2428. if (this.markerGroup &&
  2429. this.markerGroup !== chart.markerGroup) {
  2430. this.markerGroup.destroy();
  2431. }
  2432. // Use a single group for the markers
  2433. this.markerGroup = chart.markerGroup;
  2434. // When switching from chart boosting mode, destroy redundant
  2435. // series boosting targets
  2436. if (this.renderTarget) {
  2437. this.renderTarget = this.renderTarget.destroy();
  2438. }
  2439. }
  2440. points = this.points = [];
  2441. // Do not start building while drawing
  2442. series.buildKDTree = noop;
  2443. if (renderer) {
  2444. allocateIfNotSeriesBoosting(renderer, this);
  2445. renderer.pushSeries(series);
  2446. // Perform the actual renderer if we're on series level
  2447. renderIfNotSeriesBoosting(renderer, this, chart);
  2448. }
  2449. /**
  2450. * This builds the KD-tree
  2451. * @private
  2452. */
  2453. function processPoint(d, i) {
  2454. var x,
  2455. y,
  2456. clientX,
  2457. plotY,
  2458. isNull,
  2459. low = false,
  2460. chartDestroyed = typeof chart.index === 'undefined',
  2461. isYInside = true;
  2462. if (typeof d === 'undefined') {
  2463. return true;
  2464. }
  2465. if (!chartDestroyed) {
  2466. if (useRaw) {
  2467. x = d[0];
  2468. y = d[1];
  2469. }
  2470. else {
  2471. x = d;
  2472. y = yData[i];
  2473. }
  2474. // Resolve low and high for range series
  2475. if (isRange) {
  2476. if (useRaw) {
  2477. y = d.slice(1, 3);
  2478. }
  2479. low = y[0];
  2480. y = y[1];
  2481. }
  2482. else if (isStacked) {
  2483. x = d.x;
  2484. y = d.stackY;
  2485. low = y - d.y;
  2486. }
  2487. isNull = y === null;
  2488. // Optimize for scatter zooming
  2489. if (!requireSorting) {
  2490. isYInside = y >= yMin && y <= yMax;
  2491. }
  2492. if (!isNull && x >= xMin && x <= xMax && isYInside) {
  2493. clientX = xAxis.toPixels(x, true);
  2494. if (sampling) {
  2495. if (typeof minI === 'undefined' ||
  2496. clientX === lastClientX) {
  2497. if (!isRange) {
  2498. low = y;
  2499. }
  2500. if (typeof maxI === 'undefined' ||
  2501. y > maxVal) {
  2502. maxVal = y;
  2503. maxI = i;
  2504. }
  2505. if (typeof minI === 'undefined' ||
  2506. low < minVal) {
  2507. minVal = low;
  2508. minI = i;
  2509. }
  2510. }
  2511. // Add points and reset
  2512. if (clientX !== lastClientX) {
  2513. // maxI is number too:
  2514. if (typeof minI !== 'undefined') {
  2515. plotY =
  2516. yAxis.toPixels(maxVal, true);
  2517. yBottom =
  2518. yAxis.toPixels(minVal, true);
  2519. addKDPoint(clientX, plotY, maxI);
  2520. if (yBottom !== plotY) {
  2521. addKDPoint(clientX, yBottom, minI);
  2522. }
  2523. }
  2524. minI = maxI = void 0;
  2525. lastClientX = clientX;
  2526. }
  2527. }
  2528. else {
  2529. plotY = Math.ceil(yAxis.toPixels(y, true));
  2530. addKDPoint(clientX, plotY, i);
  2531. }
  2532. }
  2533. }
  2534. return !chartDestroyed;
  2535. }
  2536. /**
  2537. * @private
  2538. */
  2539. function doneProcessing() {
  2540. fireEvent(series, 'renderedCanvas');
  2541. // Go back to prototype, ready to build
  2542. delete series.buildKDTree;
  2543. series.buildKDTree();
  2544. if (boostOptions.debug.timeKDTree) {
  2545. console.timeEnd('kd tree building'); // eslint-disable-line no-console
  2546. }
  2547. }
  2548. // Loop over the points to build the k-d tree - skip this if
  2549. // exporting
  2550. if (!chart.renderer.forExport) {
  2551. if (boostOptions.debug.timeKDTree) {
  2552. console.time('kd tree building'); // eslint-disable-line no-console
  2553. }
  2554. eachAsync(isStacked ? series.data : (xData || rawData), processPoint, doneProcessing);
  2555. }
  2556. }
  2557. });
  2558. /*
  2559. * We need to handle heatmaps separatly, since we can't perform the
  2560. * size/color calculations in the shader easily.
  2561. *
  2562. * This likely needs future optimization.
  2563. */
  2564. ['heatmap', 'treemap'].forEach(function (t) {
  2565. if (seriesTypes[t]) {
  2566. wrap(seriesTypes[t].prototype, 'drawPoints', pointDrawHandler);
  2567. }
  2568. });
  2569. /* eslint-disable no-invalid-this */
  2570. if (seriesTypes.bubble) {
  2571. // By default, the bubble series does not use the KD-tree, so force it
  2572. // to.
  2573. delete seriesTypes.bubble.prototype.buildKDTree;
  2574. // seriesTypes.bubble.prototype.directTouch = false;
  2575. // Needed for markers to work correctly
  2576. wrap(seriesTypes.bubble.prototype, 'markerAttribs', function (proceed) {
  2577. if (this.isSeriesBoosting) {
  2578. return false;
  2579. }
  2580. return proceed.apply(this, [].slice.call(arguments, 1));
  2581. });
  2582. }
  2583. seriesTypes.scatter.prototype.fill = true;
  2584. extend(seriesTypes.area.prototype, {
  2585. fill: true,
  2586. fillOpacity: true,
  2587. sampling: true
  2588. });
  2589. extend(seriesTypes.column.prototype, {
  2590. fill: true,
  2591. sampling: true
  2592. });
  2593. Chart.prototype.propsRequireUpdateSeries.push('boost');
  2594. // Take care of the canvas blitting
  2595. Chart.prototype.callbacks.push(function (chart) {
  2596. /**
  2597. * Convert chart-level canvas to image.
  2598. * @private
  2599. */
  2600. function canvasToSVG() {
  2601. if (chart.ogl && chart.isChartSeriesBoosting()) {
  2602. chart.ogl.render(chart);
  2603. }
  2604. }
  2605. /**
  2606. * Clear chart-level canvas.
  2607. * @private
  2608. */
  2609. function preRender() {
  2610. // Reset force state
  2611. chart.boostForceChartBoost = void 0;
  2612. chart.boostForceChartBoost = shouldForceChartSeriesBoosting(chart);
  2613. chart.isBoosting = false;
  2614. if (!chart.isChartSeriesBoosting() && chart.didBoost) {
  2615. chart.didBoost = false;
  2616. }
  2617. // Clear the canvas
  2618. if (chart.boostClear) {
  2619. chart.boostClear();
  2620. }
  2621. if (chart.canvas && chart.ogl && chart.isChartSeriesBoosting()) {
  2622. chart.didBoost = true;
  2623. // Allocate
  2624. chart.ogl.allocateBuffer(chart);
  2625. }
  2626. // see #6518 + #6739
  2627. if (chart.markerGroup &&
  2628. chart.xAxis &&
  2629. chart.xAxis.length > 0 &&
  2630. chart.yAxis &&
  2631. chart.yAxis.length > 0) {
  2632. chart.markerGroup.translate(chart.xAxis[0].pos, chart.yAxis[0].pos);
  2633. }
  2634. }
  2635. addEvent(chart, 'predraw', preRender);
  2636. addEvent(chart, 'render', canvasToSVG);
  2637. // addEvent(chart, 'zoom', function () {
  2638. // chart.boostForceChartBoost =
  2639. // shouldForceChartSeriesBoosting(chart);
  2640. // });
  2641. var prevX = -1;
  2642. var prevY = -1;
  2643. addEvent(chart.pointer, 'afterGetHoverData', function () {
  2644. var series = chart.hoverSeries;
  2645. if (chart.markerGroup && series) {
  2646. var xAxis = chart.inverted ? series.yAxis : series.xAxis;
  2647. var yAxis = chart.inverted ? series.xAxis : series.yAxis;
  2648. if ((xAxis && xAxis.pos !== prevX) ||
  2649. (yAxis && yAxis.pos !== prevY)) {
  2650. // #10464: Keep the marker group position in sync with the
  2651. // position of the hovered series axes since there is only
  2652. // one shared marker group when boosting.
  2653. chart.markerGroup.translate(xAxis.pos, yAxis.pos);
  2654. prevX = xAxis.pos;
  2655. prevY = yAxis.pos;
  2656. }
  2657. }
  2658. });
  2659. });
  2660. /* eslint-enable no-invalid-this */
  2661. }
  2662. return init;
  2663. });
  2664. _registerModule(_modules, 'Extensions/BoostCanvas.js', [_modules['Core/Chart/Chart.js'], _modules['Core/Color/Color.js'], _modules['Core/Globals.js'], _modules['Core/Color/Palette.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js']], function (Chart, Color, H, palette, Series, SeriesRegistry, U) {
  2665. /* *
  2666. *
  2667. * License: www.highcharts.com/license
  2668. * Author: Torstein Honsi, Christer Vasseng
  2669. *
  2670. * This module serves as a fallback for the Boost module in IE9 and IE10. Newer
  2671. * browsers support WebGL which is faster.
  2672. *
  2673. * It is recommended to include this module in conditional comments targeting
  2674. * IE9 and IE10.
  2675. *
  2676. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  2677. *
  2678. * */
  2679. var color = Color.parse;
  2680. var doc = H.doc,
  2681. noop = H.noop;
  2682. var seriesTypes = SeriesRegistry.seriesTypes;
  2683. var addEvent = U.addEvent,
  2684. extend = U.extend,
  2685. fireEvent = U.fireEvent,
  2686. isNumber = U.isNumber,
  2687. merge = U.merge,
  2688. pick = U.pick,
  2689. wrap = U.wrap;
  2690. var CHUNK_SIZE = 50000,
  2691. destroyLoadingDiv;
  2692. /* eslint-disable no-invalid-this, valid-jsdoc */
  2693. /**
  2694. * Initialize the canvas boost.
  2695. *
  2696. * @function Highcharts.initCanvasBoost
  2697. */
  2698. var initCanvasBoost = function () {
  2699. if (H.seriesTypes.heatmap) {
  2700. wrap(H.seriesTypes.heatmap.prototype, 'drawPoints',
  2701. function () {
  2702. var chart = this.chart,
  2703. ctx = this.getContext(),
  2704. inverted = this.chart.inverted,
  2705. xAxis = this.xAxis,
  2706. yAxis = this.yAxis;
  2707. if (ctx) {
  2708. // draw the columns
  2709. this.points.forEach(function (point) {
  2710. var plotY = point.plotY,
  2711. pointAttr;
  2712. if (typeof plotY !== 'undefined' &&
  2713. !isNaN(plotY) &&
  2714. point.y !== null &&
  2715. ctx) {
  2716. var _a = point.shapeArgs || {},
  2717. _b = _a.x,
  2718. x = _b === void 0 ? 0 : _b,
  2719. _c = _a.y,
  2720. y = _c === void 0 ? 0 : _c,
  2721. _d = _a.width,
  2722. width = _d === void 0 ? 0 : _d,
  2723. _e = _a.height,
  2724. height = _e === void 0 ? 0 : _e;
  2725. if (!chart.styledMode) {
  2726. pointAttr = point.series.pointAttribs(point);
  2727. }
  2728. else {
  2729. pointAttr = point.series.colorAttribs(point);
  2730. }
  2731. ctx.fillStyle = pointAttr.fill;
  2732. if (inverted) {
  2733. ctx.fillRect(yAxis.len - y + xAxis.left, xAxis.len - x + yAxis.top, -height, -width);
  2734. }
  2735. else {
  2736. ctx.fillRect(x + xAxis.left, y + yAxis.top, width, height);
  2737. }
  2738. }
  2739. });
  2740. this.canvasToSVG();
  2741. }
  2742. else {
  2743. this.chart.showLoading('Your browser doesn\'t support HTML5 canvas, <br>' +
  2744. 'please use a modern browser');
  2745. // Uncomment this to provide low-level (slow) support in oldIE.
  2746. // It will cause script errors on charts with more than a few
  2747. // thousand points.
  2748. // arguments[0].call(this);
  2749. }
  2750. });
  2751. }
  2752. extend(Series.prototype, {
  2753. /**
  2754. * Create a hidden canvas to draw the graph on. The contents is later
  2755. * copied over to an SVG image element.
  2756. *
  2757. * @private
  2758. * @function Highcharts.Series#getContext
  2759. */
  2760. getContext: function () {
  2761. var chart = this.chart,
  2762. width = chart.chartWidth,
  2763. height = chart.chartHeight,
  2764. targetGroup = chart.seriesGroup || this.group,
  2765. target = this,
  2766. ctx,
  2767. swapXY = function (proceed,
  2768. x,
  2769. y,
  2770. a,
  2771. b,
  2772. c,
  2773. d) {
  2774. proceed.call(this,
  2775. y,
  2776. x,
  2777. a,
  2778. b,
  2779. c,
  2780. d);
  2781. };
  2782. if (chart.isChartSeriesBoosting()) {
  2783. target = chart;
  2784. targetGroup = chart.seriesGroup;
  2785. }
  2786. ctx = target.ctx;
  2787. if (!target.canvas) {
  2788. target.canvas = doc.createElement('canvas');
  2789. target.renderTarget = chart.renderer
  2790. .image('', 0, 0, width, height)
  2791. .addClass('highcharts-boost-canvas')
  2792. .add(targetGroup);
  2793. target.ctx = ctx = target.canvas.getContext('2d');
  2794. if (chart.inverted) {
  2795. ['moveTo', 'lineTo', 'rect', 'arc'].forEach(function (fn) {
  2796. wrap(ctx, fn, swapXY);
  2797. });
  2798. }
  2799. target.boostCopy = function () {
  2800. target.renderTarget.attr({
  2801. href: target.canvas.toDataURL('image/png')
  2802. });
  2803. };
  2804. target.boostClear = function () {
  2805. ctx.clearRect(0, 0, target.canvas.width, target.canvas.height);
  2806. if (target === this) {
  2807. target.renderTarget.attr({ href: '' });
  2808. }
  2809. };
  2810. target.boostClipRect = chart.renderer.clipRect();
  2811. target.renderTarget.clip(target.boostClipRect);
  2812. }
  2813. else if (!(target instanceof Chart)) {
  2814. // ctx.clearRect(0, 0, width, height);
  2815. }
  2816. if (target.canvas.width !== width) {
  2817. target.canvas.width = width;
  2818. }
  2819. if (target.canvas.height !== height) {
  2820. target.canvas.height = height;
  2821. }
  2822. target.renderTarget.attr({
  2823. x: 0,
  2824. y: 0,
  2825. width: width,
  2826. height: height,
  2827. style: 'pointer-events: none',
  2828. href: ''
  2829. });
  2830. target.boostClipRect.attr(chart.getBoostClipRect(target));
  2831. return ctx;
  2832. },
  2833. /**
  2834. * Draw the canvas image inside an SVG image
  2835. *
  2836. * @private
  2837. * @function Highcharts.Series#canvasToSVG
  2838. */
  2839. canvasToSVG: function () {
  2840. if (!this.chart.isChartSeriesBoosting()) {
  2841. if (this.boostCopy || this.chart.boostCopy) {
  2842. (this.boostCopy || this.chart.boostCopy)();
  2843. }
  2844. }
  2845. else {
  2846. if (this.boostClear) {
  2847. this.boostClear();
  2848. }
  2849. }
  2850. },
  2851. cvsLineTo: function (ctx, clientX, plotY) {
  2852. ctx.lineTo(clientX, plotY);
  2853. },
  2854. renderCanvas: function () {
  2855. var series = this, options = series.options, chart = series.chart, xAxis = this.xAxis, yAxis = this.yAxis, activeBoostSettings = chart.options.boost || {}, boostSettings = {
  2856. timeRendering: activeBoostSettings.timeRendering || false,
  2857. timeSeriesProcessing: activeBoostSettings.timeSeriesProcessing || false,
  2858. timeSetup: activeBoostSettings.timeSetup || false
  2859. }, ctx, c = 0, xData = series.processedXData, yData = series.processedYData, rawData = options.data, xExtremes = xAxis.getExtremes(), xMin = xExtremes.min, xMax = xExtremes.max, yExtremes = yAxis.getExtremes(), yMin = yExtremes.min, yMax = yExtremes.max, pointTaken = {}, lastClientX, sampling = !!series.sampling, points, r = options.marker && options.marker.radius, cvsDrawPoint = this.cvsDrawPoint, cvsLineTo = options.lineWidth ? this.cvsLineTo : void 0, cvsMarker = (r && r <= 1 ?
  2860. this.cvsMarkerSquare :
  2861. this.cvsMarkerCircle), strokeBatch = this.cvsStrokeBatch || 1000, enableMouseTracking = options.enableMouseTracking !== false, lastPoint, threshold = options.threshold, yBottom = yAxis.getThreshold(threshold), hasThreshold = isNumber(threshold), translatedThreshold = yBottom, doFill = this.fill, isRange = (series.pointArrayMap &&
  2862. series.pointArrayMap.join(',') === 'low,high'), isStacked = !!options.stacking, cropStart = series.cropStart || 0, loadingOptions = chart.options.loading, requireSorting = series.requireSorting, wasNull, connectNulls = options.connectNulls, useRaw = !xData, minVal, maxVal, minI, maxI, index, sdata = (isStacked ?
  2863. series.data :
  2864. (xData || rawData)), fillColor = (series.fillOpacity ?
  2865. new Color(series.color).setOpacity(pick(options.fillOpacity, 0.75)).get() :
  2866. series.color),
  2867. //
  2868. stroke = function () {
  2869. if (doFill) {
  2870. ctx.fillStyle = fillColor;
  2871. ctx.fill();
  2872. }
  2873. else {
  2874. ctx.strokeStyle = series.color;
  2875. ctx.lineWidth = options.lineWidth;
  2876. ctx.stroke();
  2877. }
  2878. },
  2879. //
  2880. drawPoint = function (clientX, plotY, yBottom, i) {
  2881. if (c === 0) {
  2882. ctx.beginPath();
  2883. if (cvsLineTo) {
  2884. ctx.lineJoin = 'round';
  2885. }
  2886. }
  2887. if (chart.scroller &&
  2888. series.options.className ===
  2889. 'highcharts-navigator-series') {
  2890. plotY += chart.scroller.top;
  2891. if (yBottom) {
  2892. yBottom += chart.scroller.top;
  2893. }
  2894. }
  2895. else {
  2896. plotY += chart.plotTop;
  2897. }
  2898. clientX += chart.plotLeft;
  2899. if (wasNull) {
  2900. ctx.moveTo(clientX, plotY);
  2901. }
  2902. else {
  2903. if (cvsDrawPoint) {
  2904. cvsDrawPoint(ctx, clientX, plotY, yBottom, lastPoint);
  2905. }
  2906. else if (cvsLineTo) {
  2907. cvsLineTo(ctx, clientX, plotY);
  2908. }
  2909. else if (cvsMarker) {
  2910. cvsMarker.call(series, ctx, clientX, plotY, r, i);
  2911. }
  2912. }
  2913. // We need to stroke the line for every 1000 pixels. It will
  2914. // crash the browser memory use if we stroke too
  2915. // infrequently.
  2916. c = c + 1;
  2917. if (c === strokeBatch) {
  2918. stroke();
  2919. c = 0;
  2920. }
  2921. // Area charts need to keep track of the last point
  2922. lastPoint = {
  2923. clientX: clientX,
  2924. plotY: plotY,
  2925. yBottom: yBottom
  2926. };
  2927. },
  2928. //
  2929. compareX = options.findNearestPointBy === 'x',
  2930. //
  2931. xDataFull = (this.xData ||
  2932. this.options.xData ||
  2933. this.processedXData ||
  2934. false),
  2935. //
  2936. addKDPoint = function (clientX, plotY, i) {
  2937. // Shaves off about 60ms compared to repeated concatenation
  2938. index = compareX ? clientX : clientX + ',' + plotY;
  2939. // The k-d tree requires series points.
  2940. // Reduce the amount of points, since the time to build the
  2941. // tree increases exponentially.
  2942. if (enableMouseTracking && !pointTaken[index]) {
  2943. pointTaken[index] = true;
  2944. if (chart.inverted) {
  2945. clientX = xAxis.len - clientX;
  2946. plotY = yAxis.len - plotY;
  2947. }
  2948. points.push({
  2949. x: xDataFull ?
  2950. xDataFull[cropStart + i] :
  2951. false,
  2952. clientX: clientX,
  2953. plotX: clientX,
  2954. plotY: plotY,
  2955. i: cropStart + i
  2956. });
  2957. }
  2958. };
  2959. if (this.renderTarget) {
  2960. this.renderTarget.attr({ 'href': '' });
  2961. }
  2962. // If we are zooming out from SVG mode, destroy the graphics
  2963. if (this.points || this.graph) {
  2964. this.destroyGraphics();
  2965. }
  2966. // The group
  2967. series.plotGroup('group', 'series', series.visible ? 'visible' : 'hidden', options.zIndex, chart.seriesGroup);
  2968. series.markerGroup = series.group;
  2969. addEvent(series, 'destroy', function () {
  2970. // Prevent destroy twice
  2971. series.markerGroup = null;
  2972. });
  2973. points = this.points = [];
  2974. ctx = this.getContext();
  2975. series.buildKDTree = noop; // Do not start building while drawing
  2976. if (this.boostClear) {
  2977. this.boostClear();
  2978. }
  2979. // if (this.canvas) {
  2980. // ctx.clearRect(
  2981. // 0,
  2982. // 0,
  2983. // this.canvas.width,
  2984. // this.canvas.height
  2985. // );
  2986. // }
  2987. if (!this.visible) {
  2988. return;
  2989. }
  2990. // Display a loading indicator
  2991. if (rawData.length > 99999) {
  2992. chart.options.loading = merge(loadingOptions, {
  2993. labelStyle: {
  2994. backgroundColor: color(palette.backgroundColor).setOpacity(0.75).get(),
  2995. padding: '1em',
  2996. borderRadius: '0.5em'
  2997. },
  2998. style: {
  2999. backgroundColor: 'none',
  3000. opacity: 1
  3001. }
  3002. });
  3003. U.clearTimeout(destroyLoadingDiv);
  3004. chart.showLoading('Drawing...');
  3005. chart.options.loading = loadingOptions; // reset
  3006. }
  3007. if (boostSettings.timeRendering) {
  3008. console.time('canvas rendering'); // eslint-disable-line no-console
  3009. }
  3010. // Loop over the points
  3011. H.eachAsync(sdata, function (d, i) {
  3012. var x,
  3013. y,
  3014. clientX,
  3015. plotY,
  3016. isNull,
  3017. low,
  3018. isNextInside = false,
  3019. isPrevInside = false,
  3020. nx = false,
  3021. px = false,
  3022. chartDestroyed = typeof chart.index === 'undefined',
  3023. isYInside = true;
  3024. if (!chartDestroyed) {
  3025. if (useRaw) {
  3026. x = d[0];
  3027. y = d[1];
  3028. if (sdata[i + 1]) {
  3029. nx = sdata[i + 1][0];
  3030. }
  3031. if (sdata[i - 1]) {
  3032. px = sdata[i - 1][0];
  3033. }
  3034. }
  3035. else {
  3036. x = d;
  3037. y = yData[i];
  3038. if (sdata[i + 1]) {
  3039. nx = sdata[i + 1];
  3040. }
  3041. if (sdata[i - 1]) {
  3042. px = sdata[i - 1];
  3043. }
  3044. }
  3045. if (nx && nx >= xMin && nx <= xMax) {
  3046. isNextInside = true;
  3047. }
  3048. if (px && px >= xMin && px <= xMax) {
  3049. isPrevInside = true;
  3050. }
  3051. // Resolve low and high for range series
  3052. if (isRange) {
  3053. if (useRaw) {
  3054. y = d.slice(1, 3);
  3055. }
  3056. low = y[0];
  3057. y = y[1];
  3058. }
  3059. else if (isStacked) {
  3060. x = d.x;
  3061. y = d.stackY;
  3062. low = y - d.y;
  3063. }
  3064. isNull = y === null;
  3065. // Optimize for scatter zooming
  3066. if (!requireSorting) {
  3067. isYInside = y >= yMin && y <= yMax;
  3068. }
  3069. if (!isNull &&
  3070. ((x >= xMin && x <= xMax && isYInside) ||
  3071. (isNextInside || isPrevInside))) {
  3072. clientX = Math.round(xAxis.toPixels(x, true));
  3073. if (sampling) {
  3074. if (typeof minI === 'undefined' ||
  3075. clientX === lastClientX) {
  3076. if (!isRange) {
  3077. low = y;
  3078. }
  3079. if (typeof maxI === 'undefined' || y > maxVal) {
  3080. maxVal = y;
  3081. maxI = i;
  3082. }
  3083. if (typeof minI === 'undefined' ||
  3084. low < minVal) {
  3085. minVal = low;
  3086. minI = i;
  3087. }
  3088. }
  3089. // Add points and reset
  3090. if (clientX !== lastClientX) {
  3091. // maxI also a number:
  3092. if (typeof minI !== 'undefined') {
  3093. plotY = yAxis.toPixels(maxVal, true);
  3094. yBottom = yAxis.toPixels(minVal, true);
  3095. drawPoint(clientX, hasThreshold ?
  3096. Math.min(plotY, translatedThreshold) : plotY, hasThreshold ?
  3097. Math.max(yBottom, translatedThreshold) : yBottom, i);
  3098. addKDPoint(clientX, plotY, maxI);
  3099. if (yBottom !== plotY) {
  3100. addKDPoint(clientX, yBottom, minI);
  3101. }
  3102. }
  3103. minI = maxI = void 0;
  3104. lastClientX = clientX;
  3105. }
  3106. }
  3107. else {
  3108. plotY = Math.round(yAxis.toPixels(y, true));
  3109. drawPoint(clientX, plotY, yBottom, i);
  3110. addKDPoint(clientX, plotY, i);
  3111. }
  3112. }
  3113. wasNull = isNull && !connectNulls;
  3114. if (i % CHUNK_SIZE === 0) {
  3115. if (series.boostCopy || series.chart.boostCopy) {
  3116. (series.boostCopy || series.chart.boostCopy)();
  3117. }
  3118. }
  3119. }
  3120. return !chartDestroyed;
  3121. }, function () {
  3122. var loadingDiv = chart.loadingDiv,
  3123. loadingShown = chart.loadingShown;
  3124. stroke();
  3125. // if (series.boostCopy || series.chart.boostCopy) {
  3126. // (series.boostCopy || series.chart.boostCopy)();
  3127. // }
  3128. series.canvasToSVG();
  3129. if (boostSettings.timeRendering) {
  3130. console.timeEnd('canvas rendering'); // eslint-disable-line no-console
  3131. }
  3132. fireEvent(series, 'renderedCanvas');
  3133. // Do not use chart.hideLoading, as it runs JS animation and
  3134. // will be blocked by buildKDTree. CSS animation looks good, but
  3135. // then it must be deleted in timeout. If we add the module to
  3136. // core, change hideLoading so we can skip this block.
  3137. if (loadingShown) {
  3138. extend(loadingDiv.style, {
  3139. transition: 'opacity 250ms',
  3140. opacity: 0
  3141. });
  3142. chart.loadingShown = false;
  3143. destroyLoadingDiv = setTimeout(function () {
  3144. if (loadingDiv.parentNode) { // In exporting it is falsy
  3145. loadingDiv.parentNode.removeChild(loadingDiv);
  3146. }
  3147. chart.loadingDiv = chart.loadingSpan = null;
  3148. }, 250);
  3149. }
  3150. // Go back to prototype, ready to build
  3151. delete series.buildKDTree;
  3152. series.buildKDTree();
  3153. // Don't do async on export, the exportChart, getSVGForExport and
  3154. // getSVG methods are not chained for it.
  3155. }, chart.renderer.forExport ? Number.MAX_VALUE : void 0);
  3156. }
  3157. });
  3158. seriesTypes.scatter.prototype.cvsMarkerCircle = function (ctx, clientX, plotY, r) {
  3159. ctx.moveTo(clientX, plotY);
  3160. ctx.arc(clientX, plotY, r, 0, 2 * Math.PI, false);
  3161. };
  3162. // Rect is twice as fast as arc, should be used for small markers
  3163. seriesTypes.scatter.prototype.cvsMarkerSquare = function (ctx, clientX, plotY, r) {
  3164. ctx.rect(clientX - r, plotY - r, r * 2, r * 2);
  3165. };
  3166. seriesTypes.scatter.prototype.fill = true;
  3167. if (seriesTypes.bubble) {
  3168. seriesTypes.bubble.prototype.cvsMarkerCircle = function (ctx, clientX, plotY, r, i) {
  3169. ctx.moveTo(clientX, plotY);
  3170. ctx.arc(clientX, plotY, this.radii && this.radii[i], 0, 2 * Math.PI, false);
  3171. };
  3172. seriesTypes.bubble.prototype.cvsStrokeBatch = 1;
  3173. }
  3174. extend(seriesTypes.area.prototype, {
  3175. cvsDrawPoint: function (ctx, clientX, plotY, yBottom, lastPoint) {
  3176. if (lastPoint && clientX !== lastPoint.clientX) {
  3177. ctx.moveTo(lastPoint.clientX, lastPoint.yBottom);
  3178. ctx.lineTo(lastPoint.clientX, lastPoint.plotY);
  3179. ctx.lineTo(clientX, plotY);
  3180. ctx.lineTo(clientX, yBottom);
  3181. }
  3182. },
  3183. fill: true,
  3184. fillOpacity: true,
  3185. sampling: true
  3186. });
  3187. extend(seriesTypes.column.prototype, {
  3188. cvsDrawPoint: function (ctx, clientX, plotY, yBottom) {
  3189. ctx.rect(clientX - 1, plotY, 1, yBottom - plotY);
  3190. },
  3191. fill: true,
  3192. sampling: true
  3193. });
  3194. Chart.prototype.callbacks.push(function (chart) {
  3195. /**
  3196. * @private
  3197. */
  3198. function canvasToSVG() {
  3199. if (chart.boostCopy) {
  3200. chart.boostCopy();
  3201. }
  3202. }
  3203. /**
  3204. * @private
  3205. */
  3206. function clear() {
  3207. if (chart.renderTarget) {
  3208. chart.renderTarget.attr({ href: '' });
  3209. }
  3210. if (chart.canvas) {
  3211. chart.canvas.getContext('2d').clearRect(0, 0, chart.canvas.width, chart.canvas.height);
  3212. }
  3213. }
  3214. addEvent(chart, 'predraw', clear);
  3215. addEvent(chart, 'render', canvasToSVG);
  3216. });
  3217. };
  3218. return initCanvasBoost;
  3219. });
  3220. _registerModule(_modules, 'Extensions/Boost/BoostOverrides.js', [_modules['Core/Chart/Chart.js'], _modules['Core/DefaultOptions.js'], _modules['Core/Series/Point.js'], _modules['Core/Series/Series.js'], _modules['Core/Series/SeriesRegistry.js'], _modules['Core/Utilities.js'], _modules['Extensions/Boost/BoostUtils.js'], _modules['Extensions/Boost/Boostables.js'], _modules['Extensions/Boost/BoostableMap.js']], function (Chart, D, Point, Series, SeriesRegistry, U, butils, boostable, boostableMap) {
  3221. /* *
  3222. *
  3223. * Copyright (c) 2019-2021 Highsoft AS
  3224. *
  3225. * Boost module: stripped-down renderer for higher performance
  3226. *
  3227. * License: highcharts.com/license
  3228. *
  3229. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3230. *
  3231. * */
  3232. var getOptions = D.getOptions;
  3233. var seriesTypes = SeriesRegistry.seriesTypes;
  3234. var addEvent = U.addEvent,
  3235. error = U.error,
  3236. isArray = U.isArray,
  3237. isNumber = U.isNumber,
  3238. pick = U.pick,
  3239. wrap = U.wrap;
  3240. var boostEnabled = butils.boostEnabled,
  3241. shouldForceChartSeriesBoosting = butils.shouldForceChartSeriesBoosting,
  3242. plotOptions = getOptions().plotOptions;
  3243. /**
  3244. * Returns true if the chart is in series boost mode.
  3245. *
  3246. * @function Highcharts.Chart#isChartSeriesBoosting
  3247. *
  3248. * @param {Highcharts.Chart} chart
  3249. * the chart to check
  3250. *
  3251. * @return {boolean}
  3252. * true if the chart is in series boost mode
  3253. */
  3254. Chart.prototype.isChartSeriesBoosting = function () {
  3255. var isSeriesBoosting,
  3256. threshold = pick(this.options.boost && this.options.boost.seriesThreshold, 50);
  3257. isSeriesBoosting = threshold <= this.series.length ||
  3258. shouldForceChartSeriesBoosting(this);
  3259. return isSeriesBoosting;
  3260. };
  3261. /* eslint-disable valid-jsdoc */
  3262. /**
  3263. * Get the clip rectangle for a target, either a series or the chart. For the
  3264. * chart, we need to consider the maximum extent of its Y axes, in case of
  3265. * Highcharts Stock panes and navigator.
  3266. *
  3267. * @private
  3268. * @function Highcharts.Chart#getBoostClipRect
  3269. *
  3270. * @param {Highcharts.Chart} target
  3271. *
  3272. * @return {Highcharts.BBoxObject}
  3273. */
  3274. Chart.prototype.getBoostClipRect = function (target) {
  3275. var clipBox = {
  3276. x: this.plotLeft,
  3277. y: this.plotTop,
  3278. width: this.plotWidth,
  3279. height: this.plotHeight
  3280. };
  3281. if (target === this) {
  3282. var verticalAxes = this.inverted ? this.xAxis : this.yAxis; // #14444
  3283. if (verticalAxes.length <= 1) {
  3284. clipBox.y = Math.min(verticalAxes[0].pos,
  3285. clipBox.y);
  3286. clipBox.height = verticalAxes[0].pos - this.plotTop + verticalAxes[0].len;
  3287. }
  3288. else {
  3289. clipBox.height = this.plotHeight;
  3290. }
  3291. }
  3292. return clipBox;
  3293. };
  3294. /**
  3295. * Return a full Point object based on the index.
  3296. * The boost module uses stripped point objects for performance reasons.
  3297. *
  3298. * @function Highcharts.Series#getPoint
  3299. *
  3300. * @param {object|Highcharts.Point} boostPoint
  3301. * A stripped-down point object
  3302. *
  3303. * @return {Highcharts.Point}
  3304. * A Point object as per https://api.highcharts.com/highcharts#Point
  3305. */
  3306. Series.prototype.getPoint = function (boostPoint) {
  3307. var point = boostPoint,
  3308. xData = (this.xData || this.options.xData || this.processedXData ||
  3309. false);
  3310. if (boostPoint && !(boostPoint instanceof this.pointClass)) {
  3311. point = (new this.pointClass()).init(// eslint-disable-line new-cap
  3312. this, this.options.data[boostPoint.i], xData ? xData[boostPoint.i] : void 0);
  3313. point.category = pick(this.xAxis.categories ?
  3314. this.xAxis.categories[point.x] :
  3315. point.x, // @todo simplify
  3316. point.x);
  3317. point.dist = boostPoint.dist;
  3318. point.distX = boostPoint.distX;
  3319. point.plotX = boostPoint.plotX;
  3320. point.plotY = boostPoint.plotY;
  3321. point.index = boostPoint.i;
  3322. point.isInside = this.isPointInside(boostPoint);
  3323. }
  3324. return point;
  3325. };
  3326. /* eslint-disable no-invalid-this */
  3327. // Return a point instance from the k-d-tree
  3328. wrap(Series.prototype, 'searchPoint', function (proceed) {
  3329. return this.getPoint(proceed.apply(this, [].slice.call(arguments, 1)));
  3330. });
  3331. // For inverted series, we need to swap X-Y values before running base methods
  3332. wrap(Point.prototype, 'haloPath', function (proceed) {
  3333. var halo,
  3334. point = this,
  3335. series = point.series,
  3336. chart = series.chart,
  3337. plotX = point.plotX,
  3338. plotY = point.plotY,
  3339. inverted = chart.inverted;
  3340. if (series.isSeriesBoosting && inverted) {
  3341. point.plotX = series.yAxis.len - plotY;
  3342. point.plotY = series.xAxis.len - plotX;
  3343. }
  3344. halo = proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3345. if (series.isSeriesBoosting && inverted) {
  3346. point.plotX = plotX;
  3347. point.plotY = plotY;
  3348. }
  3349. return halo;
  3350. });
  3351. wrap(Series.prototype, 'markerAttribs', function (proceed, point) {
  3352. var attribs,
  3353. series = this,
  3354. chart = series.chart,
  3355. plotX = point.plotX,
  3356. plotY = point.plotY,
  3357. inverted = chart.inverted;
  3358. if (series.isSeriesBoosting && inverted) {
  3359. point.plotX = series.yAxis.len - plotY;
  3360. point.plotY = series.xAxis.len - plotX;
  3361. }
  3362. attribs = proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3363. if (series.isSeriesBoosting && inverted) {
  3364. point.plotX = plotX;
  3365. point.plotY = plotY;
  3366. }
  3367. return attribs;
  3368. });
  3369. /*
  3370. * Extend series.destroy to also remove the fake k-d-tree points (#5137).
  3371. * Normally this is handled by Series.destroy that calls Point.destroy,
  3372. * but the fake search points are not registered like that.
  3373. */
  3374. addEvent(Series, 'destroy', function () {
  3375. var series = this,
  3376. chart = series.chart;
  3377. if (chart.markerGroup === series.markerGroup) {
  3378. series.markerGroup = null;
  3379. }
  3380. if (chart.hoverPoints) {
  3381. chart.hoverPoints = chart.hoverPoints.filter(function (point) {
  3382. return point.series === series;
  3383. });
  3384. }
  3385. if (chart.hoverPoint && chart.hoverPoint.series === series) {
  3386. chart.hoverPoint = null;
  3387. }
  3388. });
  3389. /*
  3390. * Do not compute extremes when min and max are set.
  3391. * If we use this in the core, we can add the hook
  3392. * to hasExtremes to the methods directly.
  3393. */
  3394. wrap(Series.prototype, 'getExtremes', function (proceed) {
  3395. if (!this.isSeriesBoosting || (!this.hasExtremes || !this.hasExtremes())) {
  3396. return proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3397. }
  3398. return {};
  3399. });
  3400. /*
  3401. * Override a bunch of methods the same way. If the number of points is
  3402. * below the threshold, run the original method. If not, check for a
  3403. * canvas version or do nothing.
  3404. *
  3405. * Note that we're not overriding any of these for heatmaps.
  3406. */
  3407. [
  3408. 'translate',
  3409. 'generatePoints',
  3410. 'drawTracker',
  3411. 'drawPoints',
  3412. 'render'
  3413. ].forEach(function (method) {
  3414. /**
  3415. * @private
  3416. */
  3417. function branch(proceed) {
  3418. var letItPass = this.options.stacking &&
  3419. (method === 'translate' || method === 'generatePoints');
  3420. if (!this.isSeriesBoosting ||
  3421. letItPass ||
  3422. !boostEnabled(this.chart) ||
  3423. this.type === 'heatmap' ||
  3424. this.type === 'treemap' ||
  3425. !boostableMap[this.type] ||
  3426. this.options.boostThreshold === 0) {
  3427. proceed.call(this);
  3428. // If a canvas version of the method exists, like renderCanvas(), run
  3429. }
  3430. else if (this[method + 'Canvas']) {
  3431. this[method + 'Canvas']();
  3432. }
  3433. }
  3434. wrap(Series.prototype, method, branch);
  3435. // A special case for some types - their translate method is already wrapped
  3436. if (method === 'translate') {
  3437. [
  3438. 'column',
  3439. 'bar',
  3440. 'arearange',
  3441. 'columnrange',
  3442. 'heatmap',
  3443. 'treemap'
  3444. ].forEach(function (type) {
  3445. if (seriesTypes[type]) {
  3446. wrap(seriesTypes[type].prototype, method, branch);
  3447. }
  3448. });
  3449. }
  3450. });
  3451. // If the series is a heatmap or treemap, or if the series is not boosting
  3452. // do the default behaviour. Otherwise, process if the series has no extremes.
  3453. wrap(Series.prototype, 'processData', function (proceed) {
  3454. var series = this,
  3455. dataToMeasure = this.options.data,
  3456. firstPoint;
  3457. /**
  3458. * Used twice in this function, first on this.options.data, the second
  3459. * time it runs the check again after processedXData is built.
  3460. * @private
  3461. * @todo Check what happens with data grouping
  3462. */
  3463. function getSeriesBoosting(data) {
  3464. return series.chart.isChartSeriesBoosting() || ((data ? data.length : 0) >=
  3465. (series.options.boostThreshold || Number.MAX_VALUE));
  3466. }
  3467. if (boostEnabled(this.chart) && boostableMap[this.type]) {
  3468. // If there are no extremes given in the options, we also need to
  3469. // process the data to read the data extremes. If this is a heatmap, do
  3470. // default behaviour.
  3471. if (!getSeriesBoosting(dataToMeasure) || // First pass with options.data
  3472. this.type === 'heatmap' ||
  3473. this.type === 'treemap' ||
  3474. this.options.stacking || // processedYData for the stack (#7481)
  3475. !this.hasExtremes ||
  3476. !this.hasExtremes(true)) {
  3477. proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3478. dataToMeasure = this.processedXData;
  3479. }
  3480. // Set the isBoosting flag, second pass with processedXData to see if we
  3481. // have zoomed.
  3482. this.isSeriesBoosting = getSeriesBoosting(dataToMeasure);
  3483. // Enter or exit boost mode
  3484. if (this.isSeriesBoosting) {
  3485. // Force turbo-mode:
  3486. if (this.options.data && this.options.data.length) {
  3487. firstPoint = this.getFirstValidPoint(this.options.data);
  3488. if (!isNumber(firstPoint) && !isArray(firstPoint)) {
  3489. error(12, false, this.chart);
  3490. }
  3491. }
  3492. this.enterBoost();
  3493. }
  3494. else if (this.exitBoost) {
  3495. this.exitBoost();
  3496. }
  3497. // The series type is not boostable
  3498. }
  3499. else {
  3500. proceed.apply(this, Array.prototype.slice.call(arguments, 1));
  3501. }
  3502. });
  3503. addEvent(Series, 'hide', function () {
  3504. if (this.canvas && this.renderTarget) {
  3505. if (this.ogl) {
  3506. this.ogl.clear();
  3507. }
  3508. this.boostClear();
  3509. }
  3510. });
  3511. /**
  3512. * Enter boost mode and apply boost-specific properties.
  3513. *
  3514. * @function Highcharts.Series#enterBoost
  3515. */
  3516. Series.prototype.enterBoost = function () {
  3517. this.alteredByBoost = [];
  3518. // Save the original values, including whether it was an own property or
  3519. // inherited from the prototype.
  3520. ['allowDG', 'directTouch', 'stickyTracking'].forEach(function (prop) {
  3521. this.alteredByBoost.push({
  3522. prop: prop,
  3523. val: this[prop],
  3524. own: Object.hasOwnProperty.call(this, prop)
  3525. });
  3526. }, this);
  3527. this.allowDG = false;
  3528. this.directTouch = false;
  3529. this.stickyTracking = true;
  3530. // Prevent animation when zooming in on boosted series(#13421).
  3531. this.finishedAnimating = true;
  3532. // Hide series label if any
  3533. if (this.labelBySeries) {
  3534. this.labelBySeries = this.labelBySeries.destroy();
  3535. }
  3536. };
  3537. /**
  3538. * Exit from boost mode and restore non-boost properties.
  3539. *
  3540. * @function Highcharts.Series#exitBoost
  3541. */
  3542. Series.prototype.exitBoost = function () {
  3543. // Reset instance properties and/or delete instance properties and go back
  3544. // to prototype
  3545. (this.alteredByBoost || []).forEach(function (setting) {
  3546. if (setting.own) {
  3547. this[setting.prop] = setting.val;
  3548. }
  3549. else {
  3550. // Revert to prototype
  3551. delete this[setting.prop];
  3552. }
  3553. }, this);
  3554. // Clear previous run
  3555. if (this.boostClear) {
  3556. this.boostClear();
  3557. }
  3558. };
  3559. /**
  3560. * @private
  3561. * @function Highcharts.Series#hasExtremes
  3562. *
  3563. * @param {boolean} checkX
  3564. *
  3565. * @return {boolean}
  3566. */
  3567. Series.prototype.hasExtremes = function (checkX) {
  3568. var options = this.options,
  3569. data = options.data,
  3570. xAxis = this.xAxis && this.xAxis.options,
  3571. yAxis = this.yAxis && this.yAxis.options,
  3572. colorAxis = this.colorAxis && this.colorAxis.options;
  3573. return data.length > (options.boostThreshold || Number.MAX_VALUE) &&
  3574. // Defined yAxis extremes
  3575. isNumber(yAxis.min) &&
  3576. isNumber(yAxis.max) &&
  3577. // Defined (and required) xAxis extremes
  3578. (!checkX ||
  3579. (isNumber(xAxis.min) && isNumber(xAxis.max))) &&
  3580. // Defined (e.g. heatmap) colorAxis extremes
  3581. (!colorAxis ||
  3582. (isNumber(colorAxis.min) && isNumber(colorAxis.max)));
  3583. };
  3584. /**
  3585. * If implemented in the core, parts of this can probably be
  3586. * shared with other similar methods in Highcharts.
  3587. *
  3588. * @function Highcharts.Series#destroyGraphics
  3589. */
  3590. Series.prototype.destroyGraphics = function () {
  3591. var _this = this;
  3592. var series = this,
  3593. points = this.points,
  3594. point,
  3595. i;
  3596. if (points) {
  3597. for (i = 0; i < points.length; i = i + 1) {
  3598. point = points[i];
  3599. if (point && point.destroyElements) {
  3600. point.destroyElements(); // #7557
  3601. }
  3602. }
  3603. }
  3604. ['graph', 'area', 'tracker'].forEach(function (prop) {
  3605. if (series[prop]) {
  3606. series[prop] = series[prop].destroy();
  3607. }
  3608. });
  3609. if (this.getZonesGraphs) {
  3610. var props = this.getZonesGraphs([['graph', 'highcharts-graph']]);
  3611. props.forEach(function (prop) {
  3612. var zoneGraph = _this[prop[0]];
  3613. if (zoneGraph) {
  3614. _this[prop[0]] = zoneGraph.destroy();
  3615. }
  3616. });
  3617. }
  3618. };
  3619. // Set default options
  3620. boostable.forEach(function (type) {
  3621. if (plotOptions[type]) {
  3622. plotOptions[type].boostThreshold = 5000;
  3623. plotOptions[type].boostData = [];
  3624. seriesTypes[type].prototype.fillOpacity = true;
  3625. }
  3626. });
  3627. });
  3628. _registerModule(_modules, 'Extensions/Boost/NamedColors.js', [_modules['Core/Color/Color.js']], function (Color) {
  3629. /* *
  3630. *
  3631. * Copyright (c) 2019-2021 Highsoft AS
  3632. *
  3633. * Boost module: stripped-down renderer for higher performance
  3634. *
  3635. * License: highcharts.com/license
  3636. *
  3637. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3638. *
  3639. * */
  3640. // Register color names since GL can't render those directly.
  3641. // TODO: When supporting modern syntax, make this a const and a named export
  3642. var defaultHTMLColorMap = {
  3643. aliceblue: '#f0f8ff',
  3644. antiquewhite: '#faebd7',
  3645. aqua: '#00ffff',
  3646. aquamarine: '#7fffd4',
  3647. azure: '#f0ffff',
  3648. beige: '#f5f5dc',
  3649. bisque: '#ffe4c4',
  3650. black: '#000000',
  3651. blanchedalmond: '#ffebcd',
  3652. blue: '#0000ff',
  3653. blueviolet: '#8a2be2',
  3654. brown: '#a52a2a',
  3655. burlywood: '#deb887',
  3656. cadetblue: '#5f9ea0',
  3657. chartreuse: '#7fff00',
  3658. chocolate: '#d2691e',
  3659. coral: '#ff7f50',
  3660. cornflowerblue: '#6495ed',
  3661. cornsilk: '#fff8dc',
  3662. crimson: '#dc143c',
  3663. cyan: '#00ffff',
  3664. darkblue: '#00008b',
  3665. darkcyan: '#008b8b',
  3666. darkgoldenrod: '#b8860b',
  3667. darkgray: '#a9a9a9',
  3668. darkgreen: '#006400',
  3669. darkkhaki: '#bdb76b',
  3670. darkmagenta: '#8b008b',
  3671. darkolivegreen: '#556b2f',
  3672. darkorange: '#ff8c00',
  3673. darkorchid: '#9932cc',
  3674. darkred: '#8b0000',
  3675. darksalmon: '#e9967a',
  3676. darkseagreen: '#8fbc8f',
  3677. darkslateblue: '#483d8b',
  3678. darkslategray: '#2f4f4f',
  3679. darkturquoise: '#00ced1',
  3680. darkviolet: '#9400d3',
  3681. deeppink: '#ff1493',
  3682. deepskyblue: '#00bfff',
  3683. dimgray: '#696969',
  3684. dodgerblue: '#1e90ff',
  3685. feldspar: '#d19275',
  3686. firebrick: '#b22222',
  3687. floralwhite: '#fffaf0',
  3688. forestgreen: '#228b22',
  3689. fuchsia: '#ff00ff',
  3690. gainsboro: '#dcdcdc',
  3691. ghostwhite: '#f8f8ff',
  3692. gold: '#ffd700',
  3693. goldenrod: '#daa520',
  3694. gray: '#808080',
  3695. green: '#008000',
  3696. greenyellow: '#adff2f',
  3697. honeydew: '#f0fff0',
  3698. hotpink: '#ff69b4',
  3699. indianred: '#cd5c5c',
  3700. indigo: '#4b0082',
  3701. ivory: '#fffff0',
  3702. khaki: '#f0e68c',
  3703. lavender: '#e6e6fa',
  3704. lavenderblush: '#fff0f5',
  3705. lawngreen: '#7cfc00',
  3706. lemonchiffon: '#fffacd',
  3707. lightblue: '#add8e6',
  3708. lightcoral: '#f08080',
  3709. lightcyan: '#e0ffff',
  3710. lightgoldenrodyellow: '#fafad2',
  3711. lightgrey: '#d3d3d3',
  3712. lightgreen: '#90ee90',
  3713. lightpink: '#ffb6c1',
  3714. lightsalmon: '#ffa07a',
  3715. lightseagreen: '#20b2aa',
  3716. lightskyblue: '#87cefa',
  3717. lightslateblue: '#8470ff',
  3718. lightslategray: '#778899',
  3719. lightsteelblue: '#b0c4de',
  3720. lightyellow: '#ffffe0',
  3721. lime: '#00ff00',
  3722. limegreen: '#32cd32',
  3723. linen: '#faf0e6',
  3724. magenta: '#ff00ff',
  3725. maroon: '#800000',
  3726. mediumaquamarine: '#66cdaa',
  3727. mediumblue: '#0000cd',
  3728. mediumorchid: '#ba55d3',
  3729. mediumpurple: '#9370d8',
  3730. mediumseagreen: '#3cb371',
  3731. mediumslateblue: '#7b68ee',
  3732. mediumspringgreen: '#00fa9a',
  3733. mediumturquoise: '#48d1cc',
  3734. mediumvioletred: '#c71585',
  3735. midnightblue: '#191970',
  3736. mintcream: '#f5fffa',
  3737. mistyrose: '#ffe4e1',
  3738. moccasin: '#ffe4b5',
  3739. navajowhite: '#ffdead',
  3740. navy: '#000080',
  3741. oldlace: '#fdf5e6',
  3742. olive: '#808000',
  3743. olivedrab: '#6b8e23',
  3744. orange: '#ffa500',
  3745. orangered: '#ff4500',
  3746. orchid: '#da70d6',
  3747. palegoldenrod: '#eee8aa',
  3748. palegreen: '#98fb98',
  3749. paleturquoise: '#afeeee',
  3750. palevioletred: '#d87093',
  3751. papayawhip: '#ffefd5',
  3752. peachpuff: '#ffdab9',
  3753. peru: '#cd853f',
  3754. pink: '#ffc0cb',
  3755. plum: '#dda0dd',
  3756. powderblue: '#b0e0e6',
  3757. purple: '#800080',
  3758. red: '#ff0000',
  3759. rosybrown: '#bc8f8f',
  3760. royalblue: '#4169e1',
  3761. saddlebrown: '#8b4513',
  3762. salmon: '#fa8072',
  3763. sandybrown: '#f4a460',
  3764. seagreen: '#2e8b57',
  3765. seashell: '#fff5ee',
  3766. sienna: '#a0522d',
  3767. silver: '#c0c0c0',
  3768. skyblue: '#87ceeb',
  3769. slateblue: '#6a5acd',
  3770. slategray: '#708090',
  3771. snow: '#fffafa',
  3772. springgreen: '#00ff7f',
  3773. steelblue: '#4682b4',
  3774. tan: '#d2b48c',
  3775. teal: '#008080',
  3776. thistle: '#d8bfd8',
  3777. tomato: '#ff6347',
  3778. turquoise: '#40e0d0',
  3779. violet: '#ee82ee',
  3780. violetred: '#d02090',
  3781. wheat: '#f5deb3',
  3782. white: '#ffffff',
  3783. whitesmoke: '#f5f5f5',
  3784. yellow: '#ffff00',
  3785. yellowgreen: '#9acd32'
  3786. };
  3787. Color.names = defaultHTMLColorMap;
  3788. return defaultHTMLColorMap;
  3789. });
  3790. _registerModule(_modules, 'Extensions/Boost/Boost.js', [_modules['Extensions/Boost/BoostUtils.js'], _modules['Extensions/Boost/BoostInit.js'], _modules['Extensions/BoostCanvas.js'], _modules['Core/Utilities.js']], function (butils, init, initCanvasBoost, U) {
  3791. /* *
  3792. *
  3793. * Copyright (c) 2019-2021 Highsoft AS
  3794. *
  3795. * Boost module: stripped-down renderer for higher performance
  3796. *
  3797. * License: highcharts.com/license
  3798. *
  3799. * !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
  3800. *
  3801. * */
  3802. var error = U.error;
  3803. // These need to be fixed when we support named imports
  3804. var hasWebGLSupport = butils.hasWebGLSupport;
  3805. if (!hasWebGLSupport()) {
  3806. if (typeof initCanvasBoost !== 'undefined') {
  3807. // Fallback to canvas boost
  3808. initCanvasBoost();
  3809. }
  3810. else {
  3811. error(26);
  3812. }
  3813. }
  3814. else {
  3815. // WebGL support is alright, and we're good to go.
  3816. init();
  3817. }
  3818. });
  3819. _registerModule(_modules, 'masters/modules/boost.src.js', [], function () {
  3820. });
  3821. }));