boost.src.js 138 KB

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