uPlot.iife.js 100 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431
  1. /**
  2. * Copyright (c) 2021, Leon Sorokin
  3. * All rights reserved. (MIT Licensed)
  4. *
  5. * uPlot.js (μPlot)
  6. * A small, fast chart for time series, lines, areas, ohlc & bars
  7. * https://github.com/leeoniya/uPlot (v1.6.1)
  8. */
  9. var uPlot = (function () {
  10. 'use strict';
  11. var FEAT_TIME = true;
  12. function debounce(fn, time) {
  13. var pending = null;
  14. function run() {
  15. pending = null;
  16. fn();
  17. }
  18. return function() {
  19. clearTimeout(pending);
  20. pending = setTimeout(run, time);
  21. }
  22. }
  23. // binary search for index of closest value
  24. function closestIdx(num, arr, lo, hi) {
  25. var mid;
  26. lo = lo || 0;
  27. hi = hi || arr.length - 1;
  28. var bitwise = hi <= 2147483647;
  29. while (hi - lo > 1) {
  30. mid = bitwise ? (lo + hi) >> 1 : floor((lo + hi) / 2);
  31. if (arr[mid] < num)
  32. { lo = mid; }
  33. else
  34. { hi = mid; }
  35. }
  36. if (num - arr[lo] <= arr[hi] - num)
  37. { return lo; }
  38. return hi;
  39. }
  40. function nonNullIdx(data, _i0, _i1, dir) {
  41. for (var i = dir == 1 ? _i0 : _i1; i >= _i0 && i <= _i1; i += dir) {
  42. if (data[i] != null)
  43. { return i; }
  44. }
  45. return -1;
  46. }
  47. function getMinMax(data, _i0, _i1, sorted) {
  48. // console.log("getMinMax()");
  49. var _min = inf;
  50. var _max = -inf;
  51. if (sorted == 1) {
  52. _min = data[_i0];
  53. _max = data[_i1];
  54. }
  55. else if (sorted == -1) {
  56. _min = data[_i1];
  57. _max = data[_i0];
  58. }
  59. else {
  60. for (var i = _i0; i <= _i1; i++) {
  61. if (data[i] != null) {
  62. _min = min(_min, data[i]);
  63. _max = max(_max, data[i]);
  64. }
  65. }
  66. }
  67. return [_min, _max];
  68. }
  69. function getMinMaxLog(data, _i0, _i1) {
  70. // console.log("getMinMax()");
  71. var _min = inf;
  72. var _max = -inf;
  73. for (var i = _i0; i <= _i1; i++) {
  74. if (data[i] > 0) {
  75. _min = min(_min, data[i]);
  76. _max = max(_max, data[i]);
  77. }
  78. }
  79. return [
  80. _min == inf ? 1 : _min,
  81. _max == -inf ? 10 : _max ];
  82. }
  83. var _fixedTuple = [0, 0];
  84. function fixIncr(minIncr, maxIncr, minExp, maxExp) {
  85. _fixedTuple[0] = minExp < 0 ? roundDec(minIncr, -minExp) : minIncr;
  86. _fixedTuple[1] = maxExp < 0 ? roundDec(maxIncr, -maxExp) : maxIncr;
  87. return _fixedTuple;
  88. }
  89. function rangeLog(min, max, base, fullMags) {
  90. var logFn = base == 10 ? log10 : log2;
  91. if (min == max) {
  92. min /= base;
  93. max *= base;
  94. }
  95. var minExp, maxExp, minMaxIncrs;
  96. if (fullMags) {
  97. minExp = floor(logFn(min));
  98. maxExp = ceil(logFn(max));
  99. minMaxIncrs = fixIncr(pow(base, minExp), pow(base, maxExp), minExp, maxExp);
  100. min = minMaxIncrs[0];
  101. max = minMaxIncrs[1];
  102. }
  103. else {
  104. minExp = floor(logFn(min));
  105. maxExp = floor(logFn(max));
  106. minMaxIncrs = fixIncr(pow(base, minExp), pow(base, maxExp), minExp, maxExp);
  107. min = incrRoundDn(min, minMaxIncrs[0]);
  108. max = incrRoundUp(max, minMaxIncrs[1]);
  109. }
  110. return [min, max];
  111. }
  112. var _eqRangePart = {
  113. pad: 0,
  114. soft: null,
  115. mode: 0,
  116. };
  117. var _eqRange = {
  118. min: _eqRangePart,
  119. max: _eqRangePart,
  120. };
  121. // this ensures that non-temporal/numeric y-axes get multiple-snapped padding added above/below
  122. // TODO: also account for incrs when snapping to ensure top of axis gets a tick & value
  123. function rangeNum(_min, _max, mult, extra) {
  124. if (isObj(mult))
  125. { return _rangeNum(_min, _max, mult); }
  126. _eqRangePart.pad = mult;
  127. _eqRangePart.soft = extra ? 0 : null;
  128. _eqRangePart.mode = extra ? 3 : 0;
  129. return _rangeNum(_min, _max, _eqRange);
  130. }
  131. // nullish coalesce
  132. function ifNull(lh, rh) {
  133. return lh == null ? rh : lh;
  134. }
  135. function _rangeNum(_min, _max, cfg) {
  136. var cmin = cfg.min;
  137. var cmax = cfg.max;
  138. var padMin = ifNull(cmin.pad, 0);
  139. var padMax = ifNull(cmax.pad, 0);
  140. var hardMin = ifNull(cmin.hard, -inf);
  141. var hardMax = ifNull(cmax.hard, inf);
  142. var softMin = ifNull(cmin.soft, inf);
  143. var softMax = ifNull(cmax.soft, -inf);
  144. var softMinMode = ifNull(cmin.mode, 0);
  145. var softMaxMode = ifNull(cmax.mode, 0);
  146. var delta = _max - _min;
  147. var nonZeroDelta = delta || abs(_max) || 1e3;
  148. var mag = log10(nonZeroDelta);
  149. var base = pow(10, floor(mag));
  150. var _padMin = nonZeroDelta * (delta == 0 ? (_min == 0 ? .1 : 1) : padMin);
  151. var _newMin = roundDec(incrRoundDn(_min - _padMin, base/10), 6);
  152. var _softMin = _min >= softMin && (softMinMode == 1 || softMinMode == 3 && _newMin <= softMin || softMinMode == 2 && _newMin >= softMin) ? softMin : inf;
  153. var minLim = max(hardMin, _newMin < _softMin && _min >= _softMin ? _softMin : min(_softMin, _newMin));
  154. var _padMax = nonZeroDelta * (delta == 0 ? (_max == 0 ? .1 : 1) : padMax);
  155. var _newMax = roundDec(incrRoundUp(_max + _padMax, base/10), 6);
  156. var _softMax = _max <= softMax && (softMaxMode == 1 || softMaxMode == 3 && _newMax >= softMax || softMaxMode == 2 && _newMax <= softMax) ? softMax : -inf;
  157. var maxLim = min(hardMax, _newMax > _softMax && _max <= _softMax ? _softMax : max(_softMax, _newMax));
  158. if (minLim == maxLim && minLim == 0)
  159. { maxLim = 100; }
  160. return [minLim, maxLim];
  161. }
  162. // alternative: https://stackoverflow.com/a/2254896
  163. var fmtNum = new Intl.NumberFormat(navigator.language).format;
  164. var M = Math;
  165. var abs = M.abs;
  166. var floor = M.floor;
  167. var round = M.round;
  168. var ceil = M.ceil;
  169. var min = M.min;
  170. var max = M.max;
  171. var pow = M.pow;
  172. var sqrt = M.sqrt;
  173. var log10 = M.log10;
  174. var log2 = M.log2;
  175. var PI = M.PI;
  176. var inf = Infinity;
  177. function incrRound(num, incr) {
  178. return round(num/incr)*incr;
  179. }
  180. function clamp(num, _min, _max) {
  181. return min(max(num, _min), _max);
  182. }
  183. function fnOrSelf(v) {
  184. return typeof v == "function" ? v : () => v;
  185. }
  186. var retArg1 = (_0, _1) => _1;
  187. var retNull = _ => null;
  188. function incrRoundUp(num, incr) {
  189. return ceil(num/incr)*incr;
  190. }
  191. function incrRoundDn(num, incr) {
  192. return floor(num/incr)*incr;
  193. }
  194. function roundDec(val, dec) {
  195. return round(val * (dec = Math.pow( 10, dec ))) / dec;
  196. }
  197. var fixedDec = new Map();
  198. function guessDec(num) {
  199. return ((""+num).split(".")[1] || "").length;
  200. }
  201. function genIncrs(base, minExp, maxExp, mults) {
  202. var incrs = [];
  203. var multDec = mults.map(guessDec);
  204. for (var exp = minExp; exp < maxExp; exp++) {
  205. var expa = abs(exp);
  206. var mag = roundDec(pow(base, exp), expa);
  207. for (var i = 0; i < mults.length; i++) {
  208. var _incr = mults[i] * mag;
  209. var dec = (_incr >= 0 && exp >= 0 ? 0 : expa) + (exp >= multDec[i] ? 0 : multDec[i]);
  210. var incr = roundDec(_incr, dec);
  211. incrs.push(incr);
  212. fixedDec.set(incr, dec);
  213. }
  214. }
  215. return incrs;
  216. }
  217. //export const assign = Object.assign;
  218. var EMPTY_OBJ = {};
  219. var isArr = Array.isArray;
  220. function isStr(v) {
  221. return typeof v == 'string';
  222. }
  223. function isObj(v) {
  224. var is = false;
  225. if (v != null) {
  226. var c = v.constructor;
  227. is = c == null || c == Object;
  228. }
  229. return is;
  230. }
  231. function copy(o) {
  232. var out;
  233. if (isArr(o))
  234. { out = o.map(copy); }
  235. else if (isObj(o)) {
  236. out = {};
  237. for (var k in o)
  238. { out[k] = copy(o[k]); }
  239. }
  240. else
  241. { out = o; }
  242. return out;
  243. }
  244. function assign(targ) {
  245. var args = arguments;
  246. for (var i = 1; i < args.length; i++) {
  247. var src = args[i];
  248. for (var key in src) {
  249. if (isObj(targ[key]))
  250. { assign(targ[key], copy(src[key])); }
  251. else
  252. { targ[key] = copy(src[key]); }
  253. }
  254. }
  255. return targ;
  256. }
  257. // nullModes
  258. var NULL_IGNORE = 0; // all nulls are ignored by isGap
  259. var NULL_GAP = 1; // alignment nulls are ignored by isGap (default)
  260. var NULL_EXPAND = 2; // nulls are expand to include adjacent alignment nulls
  261. // nullModes is a tables-matched array indicating how to treat nulls in each series
  262. function join(tables, nullModes) {
  263. if (tables.length == 1) {
  264. return {
  265. data: tables[0],
  266. isGap: nullModes ? (u, seriesIdx, dataIdx) => nullModes[0][seriesIdx] != NULL_IGNORE : () => true,
  267. };
  268. }
  269. var xVals = new Set();
  270. var xNulls = [new Set()];
  271. for (var ti = 0; ti < tables.length; ti++) {
  272. var t = tables[ti];
  273. var xs = t[0];
  274. var len = xs.length;
  275. for (var i = 0; i < len; i++)
  276. { xVals.add(xs[i]); }
  277. for (var si = 1; si < t.length; si++) {
  278. var nulls = new Set();
  279. // cache original nulls for isGap lookup
  280. if (nullModes == null || nullModes[ti][si] == NULL_GAP || nullModes[ti][si] == NULL_EXPAND) {
  281. var ys = t[si];
  282. for (var i$1 = 0; i$1 < len; i$1++) {
  283. if (ys[i$1] == null)
  284. { nulls.add(xs[i$1]); }
  285. }
  286. }
  287. xNulls.push(nulls);
  288. }
  289. }
  290. var data = [Array.from(xVals).sort((a, b) => a - b)];
  291. var alignedLen = data[0].length;
  292. var xIdxs = new Map();
  293. for (var i$2 = 0; i$2 < alignedLen; i$2++)
  294. { xIdxs.set(data[0][i$2], i$2); }
  295. var gsi = 1;
  296. for (var ti$1 = 0; ti$1 < tables.length; ti$1++) {
  297. var t$1 = tables[ti$1];
  298. var xs$1 = t$1[0];
  299. for (var si$1 = 1; si$1 < t$1.length; si$1++) {
  300. var ys$1 = t$1[si$1];
  301. var yVals = Array(alignedLen).fill(null);
  302. for (var i$3 = 0; i$3 < ys$1.length; i$3++)
  303. { yVals[xIdxs.get(xs$1[i$3])] = ys$1[i$3]; }
  304. // mark all filler nulls as explicit when adjacent to existing explicit nulls (minesweeper)
  305. if (nullModes && nullModes[ti$1][si$1] == NULL_EXPAND) {
  306. var nulls$1 = xNulls[gsi];
  307. var size = nulls$1.size;
  308. var i$4 = 0;
  309. var xi = (void 0);
  310. var lastAddedX = -inf;
  311. for (var xVal of nulls$1.values()) {
  312. if (i$4++ == size)
  313. { break; }
  314. if (xVal > lastAddedX) {
  315. var xIdx = xIdxs.get(xVal);
  316. xi = xIdx - 1;
  317. while (yVals[xi] === null) {
  318. nulls$1.add(data[0][xi]);
  319. xi--;
  320. }
  321. xi = xIdx + 1;
  322. while (yVals[xi] === null) {
  323. nulls$1.add(lastAddedX = data[0][xi]);
  324. xi++;
  325. }
  326. }
  327. }
  328. }
  329. data.push(yVals);
  330. gsi++;
  331. }
  332. }
  333. return {
  334. data: data,
  335. isGap: function isGap(u, seriesIdx, dataIdx) {
  336. var xVal = u._data[0][dataIdx];
  337. return xNulls[seriesIdx].has(xVal);
  338. },
  339. };
  340. }
  341. var microTask = typeof queueMicrotask == "undefined" ? fn => Promise.resolve().then(fn) : queueMicrotask;
  342. var WIDTH = "width";
  343. var HEIGHT = "height";
  344. var TOP = "top";
  345. var BOTTOM = "bottom";
  346. var LEFT = "left";
  347. var RIGHT = "right";
  348. var hexBlack = "#000";
  349. var transparent = hexBlack + "0";
  350. var mousemove = "mousemove";
  351. var mousedown = "mousedown";
  352. var mouseup = "mouseup";
  353. var mouseenter = "mouseenter";
  354. var mouseleave = "mouseleave";
  355. var dblclick = "dblclick";
  356. var resize = "resize";
  357. var scroll = "scroll";
  358. var pre = "u-";
  359. var UPLOT = "uplot";
  360. var ORI_HZ = pre + "hz";
  361. var ORI_VT = pre + "vt";
  362. var TITLE = pre + "title";
  363. var WRAP = pre + "wrap";
  364. var UNDER = pre + "under";
  365. var OVER = pre + "over";
  366. var OFF = pre + "off";
  367. var SELECT = pre + "select";
  368. var CURSOR_X = pre + "cursor-x";
  369. var CURSOR_Y = pre + "cursor-y";
  370. var CURSOR_PT = pre + "cursor-pt";
  371. var LEGEND = pre + "legend";
  372. var LEGEND_LIVE = pre + "live";
  373. var LEGEND_INLINE = pre + "inline";
  374. var LEGEND_THEAD = pre + "thead";
  375. var LEGEND_SERIES = pre + "series";
  376. var LEGEND_MARKER = pre + "marker";
  377. var LEGEND_LABEL = pre + "label";
  378. var LEGEND_VALUE = pre + "value";
  379. var doc = document;
  380. var win = window;
  381. var pxRatio = devicePixelRatio;
  382. function addClass(el, c) {
  383. c != null && el.classList.add(c);
  384. }
  385. function remClass(el, c) {
  386. el.classList.remove(c);
  387. }
  388. function setStylePx(el, name, value) {
  389. el.style[name] = value + "px";
  390. }
  391. function placeTag(tag, cls, targ, refEl) {
  392. var el = doc.createElement(tag);
  393. if (cls != null)
  394. { addClass(el, cls); }
  395. if (targ != null)
  396. { targ.insertBefore(el, refEl); }
  397. return el;
  398. }
  399. function placeDiv(cls, targ) {
  400. return placeTag("div", cls, targ);
  401. }
  402. function trans(el, xPos, yPos, xMax, yMax) {
  403. el.style.transform = "translate(" + xPos + "px," + yPos + "px)";
  404. if (xPos < 0 || yPos < 0 || xPos > xMax || yPos > yMax)
  405. { addClass(el, OFF); }
  406. else
  407. { remClass(el, OFF); }
  408. }
  409. var evOpts = {passive: true};
  410. function on(ev, el, cb) {
  411. el.addEventListener(ev, cb, evOpts);
  412. }
  413. function off(ev, el, cb) {
  414. el.removeEventListener(ev, cb, evOpts);
  415. }
  416. var months = [
  417. "January",
  418. "February",
  419. "March",
  420. "April",
  421. "May",
  422. "June",
  423. "July",
  424. "August",
  425. "September",
  426. "October",
  427. "November",
  428. "December" ];
  429. var days = [
  430. "Sunday",
  431. "Monday",
  432. "Tuesday",
  433. "Wednesday",
  434. "Thursday",
  435. "Friday",
  436. "Saturday" ];
  437. function slice3(str) {
  438. return str.slice(0, 3);
  439. }
  440. var days3 = days.map(slice3);
  441. var months3 = months.map(slice3);
  442. var engNames = {
  443. MMMM: months,
  444. MMM: months3,
  445. WWWW: days,
  446. WWW: days3,
  447. };
  448. function zeroPad2(int) {
  449. return (int < 10 ? '0' : '') + int;
  450. }
  451. function zeroPad3(int) {
  452. return (int < 10 ? '00' : int < 100 ? '0' : '') + int;
  453. }
  454. /*
  455. function suffix(int) {
  456. let mod10 = int % 10;
  457. return int + (
  458. mod10 == 1 && int != 11 ? "st" :
  459. mod10 == 2 && int != 12 ? "nd" :
  460. mod10 == 3 && int != 13 ? "rd" : "th"
  461. );
  462. }
  463. */
  464. var getFullYear = 'getFullYear';
  465. var getMonth = 'getMonth';
  466. var getDate = 'getDate';
  467. var getDay = 'getDay';
  468. var getHours = 'getHours';
  469. var getMinutes = 'getMinutes';
  470. var getSeconds = 'getSeconds';
  471. var getMilliseconds = 'getMilliseconds';
  472. var subs = {
  473. // 2019
  474. YYYY: d => d[getFullYear](),
  475. // 19
  476. YY: d => (d[getFullYear]()+'').slice(2),
  477. // July
  478. MMMM: (d, names) => names.MMMM[d[getMonth]()],
  479. // Jul
  480. MMM: (d, names) => names.MMM[d[getMonth]()],
  481. // 07
  482. MM: d => zeroPad2(d[getMonth]()+1),
  483. // 7
  484. M: d => d[getMonth]()+1,
  485. // 09
  486. DD: d => zeroPad2(d[getDate]()),
  487. // 9
  488. D: d => d[getDate](),
  489. // Monday
  490. WWWW: (d, names) => names.WWWW[d[getDay]()],
  491. // Mon
  492. WWW: (d, names) => names.WWW[d[getDay]()],
  493. // 03
  494. HH: d => zeroPad2(d[getHours]()),
  495. // 3
  496. H: d => d[getHours](),
  497. // 9 (12hr, unpadded)
  498. h: d => {var h = d[getHours](); return h == 0 ? 12 : h > 12 ? h - 12 : h;},
  499. // AM
  500. AA: d => d[getHours]() >= 12 ? 'PM' : 'AM',
  501. // am
  502. aa: d => d[getHours]() >= 12 ? 'pm' : 'am',
  503. // a
  504. a: d => d[getHours]() >= 12 ? 'p' : 'a',
  505. // 09
  506. mm: d => zeroPad2(d[getMinutes]()),
  507. // 9
  508. m: d => d[getMinutes](),
  509. // 09
  510. ss: d => zeroPad2(d[getSeconds]()),
  511. // 9
  512. s: d => d[getSeconds](),
  513. // 374
  514. fff: d => zeroPad3(d[getMilliseconds]()),
  515. };
  516. function fmtDate(tpl, names) {
  517. names = names || engNames;
  518. var parts = [];
  519. var R = /\{([a-z]+)\}|[^{]+/gi, m;
  520. while (m = R.exec(tpl))
  521. { parts.push(m[0][0] == '{' ? subs[m[1]] : m[0]); }
  522. return d => {
  523. var out = '';
  524. for (var i = 0; i < parts.length; i++)
  525. { out += typeof parts[i] == "string" ? parts[i] : parts[i](d, names); }
  526. return out;
  527. }
  528. }
  529. var localTz = new Intl.DateTimeFormat().resolvedOptions().timeZone;
  530. // https://stackoverflow.com/questions/15141762/how-to-initialize-a-javascript-date-to-a-particular-time-zone/53652131#53652131
  531. function tzDate(date, tz) {
  532. var date2;
  533. // perf optimization
  534. if (tz == 'Etc/UTC')
  535. { date2 = new Date(+date + date.getTimezoneOffset() * 6e4); }
  536. else if (tz == localTz)
  537. { date2 = date; }
  538. else {
  539. date2 = new Date(date.toLocaleString('en-US', {timeZone: tz}));
  540. date2.setMilliseconds(date[getMilliseconds]());
  541. }
  542. return date2;
  543. }
  544. //export const series = [];
  545. // default formatters:
  546. var onlyWhole = v => v % 1 == 0;
  547. var allMults = [1,2,2.5,5];
  548. // ...0.01, 0.02, 0.025, 0.05, 0.1, 0.2, 0.25, 0.5
  549. var decIncrs = genIncrs(10, -16, 0, allMults);
  550. // 1, 2, 2.5, 5, 10, 20, 25, 50...
  551. var oneIncrs = genIncrs(10, 0, 16, allMults);
  552. // 1, 2, 5, 10, 20, 25, 50...
  553. var wholeIncrs = oneIncrs.filter(onlyWhole);
  554. var numIncrs = decIncrs.concat(oneIncrs);
  555. var NL = "\n";
  556. var yyyy = "{YYYY}";
  557. var NLyyyy = NL + yyyy;
  558. var md = "{M}/{D}";
  559. var NLmd = NL + md;
  560. var NLmdyy = NLmd + "/{YY}";
  561. var aa = "{aa}";
  562. var hmm = "{h}:{mm}";
  563. var hmmaa = hmm + aa;
  564. var NLhmmaa = NL + hmmaa;
  565. var ss = ":{ss}";
  566. var _ = null;
  567. function genTimeStuffs(ms) {
  568. var s = ms * 1e3,
  569. m = s * 60,
  570. h = m * 60,
  571. d = h * 24,
  572. mo = d * 30,
  573. y = d * 365;
  574. // min of 1e-3 prevents setting a temporal x ticks too small since Date objects cannot advance ticks smaller than 1ms
  575. var subSecIncrs = ms == 1 ? genIncrs(10, 0, 3, allMults).filter(onlyWhole) : genIncrs(10, -3, 0, allMults);
  576. var timeIncrs = subSecIncrs.concat([
  577. // minute divisors (# of secs)
  578. s,
  579. s * 5,
  580. s * 10,
  581. s * 15,
  582. s * 30,
  583. // hour divisors (# of mins)
  584. m,
  585. m * 5,
  586. m * 10,
  587. m * 15,
  588. m * 30,
  589. // day divisors (# of hrs)
  590. h,
  591. h * 2,
  592. h * 3,
  593. h * 4,
  594. h * 6,
  595. h * 8,
  596. h * 12,
  597. // month divisors TODO: need more?
  598. d,
  599. d * 2,
  600. d * 3,
  601. d * 4,
  602. d * 5,
  603. d * 6,
  604. d * 7,
  605. d * 8,
  606. d * 9,
  607. d * 10,
  608. d * 15,
  609. // year divisors (# months, approx)
  610. mo,
  611. mo * 2,
  612. mo * 3,
  613. mo * 4,
  614. mo * 6,
  615. // century divisors
  616. y,
  617. y * 2,
  618. y * 5,
  619. y * 10,
  620. y * 25,
  621. y * 50,
  622. y * 100 ]);
  623. // [0]: minimum num secs in the tick incr
  624. // [1]: default tick format
  625. // [2-7]: rollover tick formats
  626. // [8]: mode: 0: replace [1] -> [2-7], 1: concat [1] + [2-7]
  627. var _timeAxisStamps = [
  628. // tick incr default year month day hour min sec mode
  629. [y, yyyy, _, _, _, _, _, _, 1],
  630. [d * 28, "{MMM}", NLyyyy, _, _, _, _, _, 1],
  631. [d, md, NLyyyy, _, _, _, _, _, 1],
  632. [h, "{h}" + aa, NLmdyy, _, NLmd, _, _, _, 1],
  633. [m, hmmaa, NLmdyy, _, NLmd, _, _, _, 1],
  634. [s, ss, NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1],
  635. [ms, ss + ".{fff}", NLmdyy + " " + hmmaa, _, NLmd + " " + hmmaa, _, NLhmmaa, _, 1] ];
  636. // the ensures that axis ticks, values & grid are aligned to logical temporal breakpoints and not an arbitrary timestamp
  637. // https://www.timeanddate.com/time/dst/
  638. // https://www.timeanddate.com/time/dst/2019.html
  639. // https://www.epochconverter.com/timezones
  640. function timeAxisSplits(tzDate) {
  641. return (self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace) => {
  642. var splits = [];
  643. var isYr = foundIncr >= y;
  644. var isMo = foundIncr >= mo && foundIncr < y;
  645. // get the timezone-adjusted date
  646. var minDate = tzDate(scaleMin);
  647. var minDateTs = minDate * ms;
  648. // get ts of 12am (this lands us at or before the original scaleMin)
  649. var minMin = mkDate(minDate[getFullYear](), isYr ? 0 : minDate[getMonth](), isMo || isYr ? 1 : minDate[getDate]());
  650. var minMinTs = minMin * ms;
  651. if (isMo || isYr) {
  652. var moIncr = isMo ? foundIncr / mo : 0;
  653. var yrIncr = isYr ? foundIncr / y : 0;
  654. // let tzOffset = scaleMin - minDateTs; // needed?
  655. var split = minDateTs == minMinTs ? minDateTs : mkDate(minMin[getFullYear]() + yrIncr, minMin[getMonth]() + moIncr, 1) * ms;
  656. var splitDate = new Date(split / ms);
  657. var baseYear = splitDate[getFullYear]();
  658. var baseMonth = splitDate[getMonth]();
  659. for (var i = 0; split <= scaleMax; i++) {
  660. var next = mkDate(baseYear + yrIncr * i, baseMonth + moIncr * i, 1);
  661. var offs = next - tzDate(next * ms);
  662. split = (+next + offs) * ms;
  663. if (split <= scaleMax)
  664. { splits.push(split); }
  665. }
  666. }
  667. else {
  668. var incr0 = foundIncr >= d ? d : foundIncr;
  669. var tzOffset = floor(scaleMin) - floor(minDateTs);
  670. var split$1 = minMinTs + tzOffset + incrRoundUp(minDateTs - minMinTs, incr0);
  671. splits.push(split$1);
  672. var date0 = tzDate(split$1);
  673. var prevHour = date0[getHours]() + (date0[getMinutes]() / m) + (date0[getSeconds]() / h);
  674. var incrHours = foundIncr / h;
  675. var minSpace = self.axes[axisIdx]._space;
  676. var pctSpace = foundSpace / minSpace;
  677. while (1) {
  678. split$1 = roundDec(split$1 + foundIncr, ms == 1 ? 0 : 3);
  679. if (split$1 > scaleMax)
  680. { break; }
  681. if (incrHours > 1) {
  682. var expectedHour = floor(roundDec(prevHour + incrHours, 6)) % 24;
  683. var splitDate$1 = tzDate(split$1);
  684. var actualHour = splitDate$1.getHours();
  685. var dstShift = actualHour - expectedHour;
  686. if (dstShift > 1)
  687. { dstShift = -1; }
  688. split$1 -= dstShift * h;
  689. prevHour = (prevHour + incrHours) % 24;
  690. // add a tick only if it's further than 70% of the min allowed label spacing
  691. var prevSplit = splits[splits.length - 1];
  692. var pctIncr = roundDec((split$1 - prevSplit) / foundIncr, 3);
  693. if (pctIncr * pctSpace >= .7)
  694. { splits.push(split$1); }
  695. }
  696. else
  697. { splits.push(split$1); }
  698. }
  699. }
  700. return splits;
  701. }
  702. }
  703. return [
  704. timeIncrs,
  705. _timeAxisStamps,
  706. timeAxisSplits ];
  707. }
  708. var ref = genTimeStuffs(1);
  709. var timeIncrsMs = ref[0];
  710. var _timeAxisStampsMs = ref[1];
  711. var timeAxisSplitsMs = ref[2];
  712. var ref$1 = genTimeStuffs(1e-3);
  713. var timeIncrsS = ref$1[0];
  714. var _timeAxisStampsS = ref$1[1];
  715. var timeAxisSplitsS = ref$1[2];
  716. // base 2
  717. var binIncrs = genIncrs(2, -53, 53, [1]);
  718. /*
  719. console.log({
  720. decIncrs,
  721. oneIncrs,
  722. wholeIncrs,
  723. numIncrs,
  724. timeIncrs,
  725. fixedDec,
  726. });
  727. */
  728. function timeAxisStamps(stampCfg, fmtDate) {
  729. return stampCfg.map(s => s.map((v, i) =>
  730. i == 0 || i == 8 || v == null ? v : fmtDate(i == 1 || s[8] == 0 ? v : s[1] + v)
  731. ));
  732. }
  733. // TODO: will need to accept spaces[] and pull incr into the loop when grid will be non-uniform, eg for log scales.
  734. // currently we ignore this for months since they're *nearly* uniform and the added complexity is not worth it
  735. function timeAxisVals(tzDate, stamps) {
  736. return (self, splits, axisIdx, foundSpace, foundIncr) => {
  737. var s = stamps.find(s => foundIncr >= s[0]) || stamps[stamps.length - 1];
  738. // these track boundaries when a full label is needed again
  739. var prevYear;
  740. var prevMnth;
  741. var prevDate;
  742. var prevHour;
  743. var prevMins;
  744. var prevSecs;
  745. return splits.map(split => {
  746. var date = tzDate(split);
  747. var newYear = date[getFullYear]();
  748. var newMnth = date[getMonth]();
  749. var newDate = date[getDate]();
  750. var newHour = date[getHours]();
  751. var newMins = date[getMinutes]();
  752. var newSecs = date[getSeconds]();
  753. var stamp = (
  754. newYear != prevYear && s[2] ||
  755. newMnth != prevMnth && s[3] ||
  756. newDate != prevDate && s[4] ||
  757. newHour != prevHour && s[5] ||
  758. newMins != prevMins && s[6] ||
  759. newSecs != prevSecs && s[7] ||
  760. s[1]
  761. );
  762. prevYear = newYear;
  763. prevMnth = newMnth;
  764. prevDate = newDate;
  765. prevHour = newHour;
  766. prevMins = newMins;
  767. prevSecs = newSecs;
  768. return stamp(date);
  769. });
  770. }
  771. }
  772. // for when axis.values is defined as a static fmtDate template string
  773. function timeAxisVal(tzDate, dateTpl) {
  774. var stamp = fmtDate(dateTpl);
  775. return (self, splits, axisIdx, foundSpace, foundIncr) => splits.map(split => stamp(tzDate(split)));
  776. }
  777. function mkDate(y, m, d) {
  778. return new Date(y, m, d);
  779. }
  780. function timeSeriesStamp(stampCfg, fmtDate) {
  781. return fmtDate(stampCfg);
  782. }
  783. var _timeSeriesStamp = '{YYYY}-{MM}-{DD} {h}:{mm}{aa}';
  784. function timeSeriesVal(tzDate, stamp) {
  785. return (self, val) => stamp(tzDate(val));
  786. }
  787. var legendWidth = 2;
  788. var legendDash = "solid";
  789. function legendStroke(self, seriesIdx) {
  790. var s = self.series[seriesIdx];
  791. return s.width ? s.stroke(self, seriesIdx) : s.points.width ? s.points.stroke(self, seriesIdx) : null;
  792. }
  793. function legendFill(self, seriesIdx) {
  794. return self.series[seriesIdx].fill(self, seriesIdx);
  795. }
  796. function cursorPointShow(self, si) {
  797. var o = self.cursor.points;
  798. var pt = placeDiv();
  799. var stroke = o.stroke(self, si);
  800. var fill = o.fill(self, si);
  801. pt.style.background = fill || stroke;
  802. var size = o.size(self, si);
  803. var width = o.width(self, si, size);
  804. if (width)
  805. { pt.style.border = width + "px solid " + stroke; }
  806. var mar = size / -2;
  807. setStylePx(pt, WIDTH, size);
  808. setStylePx(pt, HEIGHT, size);
  809. setStylePx(pt, "marginLeft", mar);
  810. setStylePx(pt, "marginTop", mar);
  811. return pt;
  812. }
  813. function cursorPointFill(self, si) {
  814. var s = self.series[si];
  815. return s.stroke(self, si);
  816. }
  817. function cursorPointStroke(self, si) {
  818. var s = self.series[si];
  819. return s.stroke(self, si);
  820. }
  821. function cursorPointSize(self, si) {
  822. var s = self.series[si];
  823. return ptDia(s.width, 1);
  824. }
  825. function dataIdx(self, seriesIdx, cursorIdx) {
  826. return cursorIdx;
  827. }
  828. var moveTuple = [0,0];
  829. function cursorMove(self, mouseLeft1, mouseTop1) {
  830. moveTuple[0] = mouseLeft1;
  831. moveTuple[1] = mouseTop1;
  832. return moveTuple;
  833. }
  834. function filtBtn0(self, targ, handle) {
  835. return e => {
  836. e.button == 0 && handle(e);
  837. };
  838. }
  839. function passThru(self, targ, handle) {
  840. return handle;
  841. }
  842. var cursorOpts = {
  843. show: true,
  844. x: true,
  845. y: true,
  846. lock: false,
  847. move: cursorMove,
  848. points: {
  849. show: cursorPointShow,
  850. size: cursorPointSize,
  851. width: 0,
  852. stroke: cursorPointStroke,
  853. fill: cursorPointFill,
  854. },
  855. bind: {
  856. mousedown: filtBtn0,
  857. mouseup: filtBtn0,
  858. click: filtBtn0,
  859. dblclick: filtBtn0,
  860. mousemove: passThru,
  861. mouseleave: passThru,
  862. mouseenter: passThru,
  863. },
  864. drag: {
  865. setScale: true,
  866. x: true,
  867. y: false,
  868. dist: 0,
  869. uni: null,
  870. _x: false,
  871. _y: false,
  872. },
  873. focus: {
  874. prox: -1,
  875. },
  876. left: -10,
  877. top: -10,
  878. idx: null,
  879. dataIdx: dataIdx,
  880. };
  881. var grid = {
  882. show: true,
  883. stroke: "rgba(0,0,0,0.07)",
  884. width: 2,
  885. // dash: [],
  886. filter: retArg1,
  887. };
  888. var ticks = assign({}, grid, {size: 10});
  889. var font = '12px system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
  890. var labelFont = "bold " + font;
  891. var lineMult = 1.5; // font-size multiplier
  892. var xAxisOpts = {
  893. show: true,
  894. scale: "x",
  895. space: 50,
  896. gap: 5,
  897. size: 50,
  898. labelSize: 30,
  899. labelFont: labelFont,
  900. side: 2,
  901. // class: "x-vals",
  902. // incrs: timeIncrs,
  903. // values: timeVals,
  904. // filter: retArg1,
  905. grid: grid,
  906. ticks: ticks,
  907. font: font,
  908. rotate: 0,
  909. };
  910. var numSeriesLabel = "Value";
  911. var timeSeriesLabel = "Time";
  912. var xSeriesOpts = {
  913. show: true,
  914. scale: "x",
  915. auto: false,
  916. sorted: 1,
  917. // label: "Time",
  918. // value: v => stamp(new Date(v * 1e3)),
  919. // internal caches
  920. min: inf,
  921. max: -inf,
  922. idxs: [],
  923. };
  924. function numAxisVals(self, splits, axisIdx, foundSpace, foundIncr) {
  925. return splits.map(v => v == null ? "" : fmtNum(v));
  926. }
  927. function numAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {
  928. var splits = [];
  929. var numDec = fixedDec.get(foundIncr) || 0;
  930. scaleMin = forceMin ? scaleMin : roundDec(incrRoundUp(scaleMin, foundIncr), numDec);
  931. for (var val = scaleMin; val <= scaleMax; val = roundDec(val + foundIncr, numDec))
  932. { splits.push(Object.is(val, -0) ? 0 : val); } // coalesces -0
  933. return splits;
  934. }
  935. function logAxisSplits(self, axisIdx, scaleMin, scaleMax, foundIncr, foundSpace, forceMin) {
  936. var splits = [];
  937. var logBase = self.scales[self.axes[axisIdx].scale].log;
  938. var logFn = logBase == 10 ? log10 : log2;
  939. var exp = floor(logFn(scaleMin));
  940. foundIncr = pow(logBase, exp);
  941. if (exp < 0)
  942. { foundIncr = roundDec(foundIncr, -exp); }
  943. var split = scaleMin;
  944. do {
  945. splits.push(split);
  946. split = roundDec(split + foundIncr, fixedDec.get(foundIncr));
  947. if (split >= foundIncr * logBase)
  948. { foundIncr = split; }
  949. } while (split <= scaleMax);
  950. return splits;
  951. }
  952. var RE_ALL = /./;
  953. var RE_12357 = /[12357]/;
  954. var RE_125 = /[125]/;
  955. var RE_1 = /1/;
  956. function logAxisValsFilt(self, splits, axisIdx, foundSpace, foundIncr) {
  957. var axis = self.axes[axisIdx];
  958. var scaleKey = axis.scale;
  959. if (self.scales[scaleKey].log == 2)
  960. { return splits; }
  961. var valToPos = self.valToPos;
  962. var minSpace = axis._space;
  963. var _10 = valToPos(10, scaleKey);
  964. var re = (
  965. valToPos(9, scaleKey) - _10 >= minSpace ? RE_ALL :
  966. valToPos(7, scaleKey) - _10 >= minSpace ? RE_12357 :
  967. valToPos(5, scaleKey) - _10 >= minSpace ? RE_125 :
  968. RE_1
  969. );
  970. return splits.map(v => re.test(v) ? v : null);
  971. }
  972. function numSeriesVal(self, val) {
  973. return val == null ? "" : fmtNum(val);
  974. }
  975. var yAxisOpts = {
  976. show: true,
  977. scale: "y",
  978. space: 30,
  979. gap: 5,
  980. size: 50,
  981. labelSize: 30,
  982. labelFont: labelFont,
  983. side: 3,
  984. // class: "y-vals",
  985. // incrs: numIncrs,
  986. // values: (vals, space) => vals,
  987. // filter: retArg1,
  988. grid: grid,
  989. ticks: ticks,
  990. font: font,
  991. rotate: 0,
  992. };
  993. // takes stroke width
  994. function ptDia(width, mult) {
  995. var dia = 3 + (width || 1) * 2;
  996. return roundDec(dia * mult, 3);
  997. }
  998. function seriesPoints(self, si) {
  999. var xsc = self.scales[self.series[0].scale];
  1000. var dim = xsc.ori == 0 ? self.bbox.width : self.bbox.height;
  1001. var s = self.series[si];
  1002. // const dia = ptDia(s.width, pxRatio);
  1003. var maxPts = dim / (s.points.space * pxRatio);
  1004. var idxs = self.series[0].idxs;
  1005. return idxs[1] - idxs[0] <= maxPts;
  1006. }
  1007. function seriesFillTo(self, seriesIdx, dataMin, dataMax) {
  1008. var scale = self.scales[self.series[seriesIdx].scale];
  1009. return scale.distr == 3 ? scale.min : 0;
  1010. }
  1011. var ySeriesOpts = {
  1012. scale: "y",
  1013. auto: true,
  1014. sorted: 0,
  1015. show: true,
  1016. band: false,
  1017. spanGaps: false,
  1018. isGap: (self, seriesIdx, dataIdx) => true,
  1019. alpha: 1,
  1020. points: {
  1021. show: seriesPoints,
  1022. // stroke: "#000",
  1023. // fill: "#fff",
  1024. // width: 1,
  1025. // size: 10,
  1026. },
  1027. // label: "Value",
  1028. // value: v => v,
  1029. values: null,
  1030. // internal caches
  1031. min: inf,
  1032. max: -inf,
  1033. idxs: [],
  1034. path: null,
  1035. clip: null,
  1036. };
  1037. function clampScale(self, val, scaleMin, scaleMax, scaleKey) {
  1038. /*
  1039. if (val < 0) {
  1040. let cssHgt = self.bbox.height / pxRatio;
  1041. let absPos = self.valToPos(abs(val), scaleKey);
  1042. let fromBtm = cssHgt - absPos;
  1043. return self.posToVal(cssHgt + fromBtm, scaleKey);
  1044. }
  1045. */
  1046. return scaleMin / 10;
  1047. }
  1048. var xScaleOpts = {
  1049. time: FEAT_TIME,
  1050. auto: true,
  1051. distr: 1,
  1052. log: 10,
  1053. min: null,
  1054. max: null,
  1055. dir: 1,
  1056. ori: 0,
  1057. };
  1058. var yScaleOpts = assign({}, xScaleOpts, {
  1059. time: false,
  1060. ori: 1,
  1061. });
  1062. var syncs = {};
  1063. function _sync(opts) {
  1064. var clients = [];
  1065. return {
  1066. sub: function sub(client) {
  1067. clients.push(client);
  1068. },
  1069. unsub: function unsub(client) {
  1070. clients = clients.filter(c => c != client);
  1071. },
  1072. pub: function pub(type, self, x, y, w, h, i) {
  1073. if (clients.length > 1) {
  1074. clients.forEach(client => {
  1075. client != self && client.pub(type, self, x, y, w, h, i);
  1076. });
  1077. }
  1078. }
  1079. };
  1080. }
  1081. function orient(u, seriesIdx, cb) {
  1082. var series = u.series[seriesIdx];
  1083. var scales = u.scales;
  1084. var bbox = u.bbox;
  1085. var scaleX = scales[u.series[0].scale];
  1086. var dx = u._data[0],
  1087. dy = u._data[seriesIdx],
  1088. sx = scaleX,
  1089. sy = scales[series.scale],
  1090. l = bbox.left,
  1091. t = bbox.top,
  1092. w = bbox.width,
  1093. h = bbox.height,
  1094. H = u.valToPosH,
  1095. V = u.valToPosV;
  1096. return (sx.ori == 0
  1097. ? cb(
  1098. series,
  1099. dx,
  1100. dy,
  1101. sx,
  1102. sy,
  1103. H,
  1104. V,
  1105. l,
  1106. t,
  1107. w,
  1108. h,
  1109. moveToH,
  1110. lineToH,
  1111. rectH,
  1112. arcH,
  1113. bezierCurveToH
  1114. )
  1115. : cb(
  1116. series,
  1117. dx,
  1118. dy,
  1119. sx,
  1120. sy,
  1121. V,
  1122. H,
  1123. t,
  1124. l,
  1125. h,
  1126. w,
  1127. moveToV,
  1128. lineToV,
  1129. rectV,
  1130. arcV,
  1131. bezierCurveToV
  1132. )
  1133. );
  1134. }
  1135. // creates inverted band clip path (towards from stroke path -> yMax)
  1136. function clipBandLine(self, seriesIdx, idx0, idx1, strokePath) {
  1137. return orient(self, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {
  1138. var dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);
  1139. var lineTo = scaleX.ori == 0 ? lineToH : lineToV;
  1140. var frIdx, toIdx;
  1141. if (dir == 1) {
  1142. frIdx = idx0;
  1143. toIdx = idx1;
  1144. }
  1145. else {
  1146. frIdx = idx1;
  1147. toIdx = idx0;
  1148. }
  1149. // path start
  1150. var x0 = incrRound(valToPosX(dataX[frIdx], scaleX, xDim, xOff), 0.5);
  1151. var y0 = incrRound(valToPosY(dataY[frIdx], scaleY, yDim, yOff), 0.5);
  1152. // path end x
  1153. var x1 = incrRound(valToPosX(dataX[toIdx], scaleX, xDim, xOff), 0.5);
  1154. // upper y limit
  1155. var yLimit = incrRound(valToPosY(scaleY.max, scaleY, yDim, yOff), 0.5);
  1156. var clip = new Path2D(strokePath);
  1157. lineTo(clip, x1, yLimit);
  1158. lineTo(clip, x0, yLimit);
  1159. lineTo(clip, x0, y0);
  1160. return clip;
  1161. });
  1162. }
  1163. function clipGaps(gaps, ori, plotLft, plotTop, plotWid, plotHgt) {
  1164. var clip = null;
  1165. // create clip path (invert gaps and non-gaps)
  1166. if (gaps.length > 0) {
  1167. clip = new Path2D();
  1168. var rect = ori == 0 ? rectH : rectV;
  1169. var prevGapEnd = plotLft;
  1170. for (var i = 0; i < gaps.length; i++) {
  1171. var g = gaps[i];
  1172. rect(clip, prevGapEnd, plotTop, g[0] - prevGapEnd, plotTop + plotHgt);
  1173. prevGapEnd = g[1];
  1174. }
  1175. rect(clip, prevGapEnd, plotTop, plotLft + plotWid - prevGapEnd, plotTop + plotHgt);
  1176. }
  1177. return clip;
  1178. }
  1179. function addGap(gaps, fromX, toX) {
  1180. if (toX > fromX) {
  1181. var prevGap = gaps[gaps.length - 1];
  1182. if (prevGap && prevGap[0] == fromX) // TODO: gaps must be encoded at stroke widths?
  1183. { prevGap[1] = toX; }
  1184. else
  1185. { gaps.push([fromX, toX]); }
  1186. }
  1187. }
  1188. // orientation-inverting canvas functions
  1189. function moveToH(p, x, y) { p.moveTo(x, y); }
  1190. function moveToV(p, y, x) { p.moveTo(x, y); }
  1191. function lineToH(p, x, y) { p.lineTo(x, y); }
  1192. function lineToV(p, y, x) { p.lineTo(x, y); }
  1193. function rectH(p, x, y, w, h) { p.rect(x, y, w, h); }
  1194. function rectV(p, y, x, h, w) { p.rect(x, y, w, h); }
  1195. function arcH(p, x, y, r, startAngle, endAngle) { p.arc(x, y, r, startAngle, endAngle); }
  1196. function arcV(p, y, x, r, startAngle, endAngle) { p.arc(x, y, r, startAngle, endAngle); }
  1197. function bezierCurveToH(p, bp1x, bp1y, bp2x, bp2y, p2x, p2y) { p.bezierCurveTo(bp1x, bp1y, bp2x, bp2y, p2x, p2y); }function bezierCurveToV(p, bp1y, bp1x, bp2y, bp2x, p2y, p2x) { p.bezierCurveTo(bp1x, bp1y, bp2x, bp2y, p2x, p2y); }
  1198. function _drawAcc(lineTo) {
  1199. return (stroke, accX, minY, maxY, outY) => {
  1200. lineTo(stroke, accX, minY);
  1201. lineTo(stroke, accX, maxY);
  1202. lineTo(stroke, accX, outY);
  1203. };
  1204. }
  1205. var drawAccH = _drawAcc(lineToH);
  1206. var drawAccV = _drawAcc(lineToV);
  1207. function linear() {
  1208. return (u, seriesIdx, idx0, idx1) => {
  1209. return orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {
  1210. var lineTo, drawAcc;
  1211. if (scaleX.ori == 0) {
  1212. lineTo = lineToH;
  1213. drawAcc = drawAccH;
  1214. }
  1215. else {
  1216. lineTo = lineToV;
  1217. drawAcc = drawAccV;
  1218. }
  1219. var isGap = series.isGap;
  1220. var dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);
  1221. var _paths = {stroke: new Path2D(), fill: null, clip: null, band: null};
  1222. var stroke = _paths.stroke;
  1223. var minY = inf,
  1224. maxY = -inf,
  1225. outY, outX, drawnAtX;
  1226. var gaps = [];
  1227. var accX = round(valToPosX(dataX[dir == 1 ? idx0 : idx1], scaleX, xDim, xOff));
  1228. var accGaps = false;
  1229. // data edges
  1230. var lftIdx = nonNullIdx(dataY, idx0, idx1, 1 * dir);
  1231. var rgtIdx = nonNullIdx(dataY, idx0, idx1, -1 * dir);
  1232. var lftX = incrRound(valToPosX(dataX[lftIdx], scaleX, xDim, xOff), 0.5);
  1233. var rgtX = incrRound(valToPosX(dataX[rgtIdx], scaleX, xDim, xOff), 0.5);
  1234. if (lftX > xOff)
  1235. { addGap(gaps, xOff, lftX); }
  1236. for (var i = dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += dir) {
  1237. var x = round(valToPosX(dataX[i], scaleX, xDim, xOff));
  1238. if (x == accX) {
  1239. if (dataY[i] != null) {
  1240. outY = round(valToPosY(dataY[i], scaleY, yDim, yOff));
  1241. if (minY == inf)
  1242. { lineTo(stroke, x, outY); }
  1243. minY = min(outY, minY);
  1244. maxY = max(outY, maxY);
  1245. }
  1246. else if (!accGaps && isGap(u, seriesIdx, i))
  1247. { accGaps = true; }
  1248. }
  1249. else {
  1250. var _addGap = false;
  1251. if (minY != inf) {
  1252. drawAcc(stroke, accX, minY, maxY, outY);
  1253. outX = drawnAtX = accX;
  1254. }
  1255. else if (accGaps) {
  1256. _addGap = true;
  1257. accGaps = false;
  1258. }
  1259. if (dataY[i] != null) {
  1260. outY = round(valToPosY(dataY[i], scaleY, yDim, yOff));
  1261. lineTo(stroke, x, outY);
  1262. minY = maxY = outY;
  1263. // prior pixel can have data but still start a gap if ends with null
  1264. if (x - accX > 1 && dataY[i - dir] == null && isGap(u, seriesIdx, i - dir))
  1265. { _addGap = true; }
  1266. }
  1267. else {
  1268. minY = inf;
  1269. maxY = -inf;
  1270. if (!accGaps && isGap(u, seriesIdx, i))
  1271. { accGaps = true; }
  1272. }
  1273. _addGap && addGap(gaps, outX, x);
  1274. accX = x;
  1275. }
  1276. }
  1277. if (minY != inf && minY != maxY && drawnAtX != accX)
  1278. { drawAcc(stroke, accX, minY, maxY, outY); }
  1279. if (rgtX < xOff + xDim)
  1280. { addGap(gaps, rgtX, xOff + xDim); }
  1281. if (series.fill != null) {
  1282. var fill = _paths.fill = new Path2D(stroke);
  1283. var fillTo = round(valToPosY(series.fillTo(u, seriesIdx, series.min, series.max), scaleY, yDim, yOff));
  1284. lineTo(fill, rgtX, fillTo);
  1285. lineTo(fill, lftX, fillTo);
  1286. }
  1287. if (!series.spanGaps)
  1288. { _paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim); }
  1289. if (u.bands.length > 0) {
  1290. // ADDL OPT: only create band clips for series that are band lower edges
  1291. // if (b.series[1] == i && _paths.band == null)
  1292. _paths.band = clipBandLine(u, seriesIdx, idx0, idx1, stroke);
  1293. }
  1294. return _paths;
  1295. });
  1296. };
  1297. }
  1298. function spline(opts) {
  1299. return (u, seriesIdx, idx0, idx1) => {
  1300. return orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {
  1301. var moveTo, bezierCurveTo, lineTo;
  1302. if (scaleX.ori == 0) {
  1303. moveTo = moveToH;
  1304. lineTo = lineToH;
  1305. bezierCurveTo = bezierCurveToH;
  1306. }
  1307. else {
  1308. moveTo = moveToV;
  1309. lineTo = lineToV;
  1310. bezierCurveTo = bezierCurveToV;
  1311. }
  1312. var _dir = 1 * scaleX.dir * (scaleX.ori == 0 ? 1 : -1);
  1313. idx0 = nonNullIdx(dataY, idx0, idx1, 1);
  1314. idx1 = nonNullIdx(dataY, idx0, idx1, -1);
  1315. var gaps = [];
  1316. var inGap = false;
  1317. var firstXPos = round(valToPosX(dataX[_dir == 1 ? idx0 : idx1], scaleX, xDim, xOff));
  1318. var prevXPos = firstXPos;
  1319. var xCoords = [];
  1320. var yCoords = [];
  1321. for (var i = _dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += _dir) {
  1322. var yVal = dataY[i];
  1323. var xVal = dataX[i];
  1324. var xPos = valToPosX(xVal, scaleX, xDim, xOff);
  1325. if (yVal == null) {
  1326. if (series.isGap(u, seriesIdx, i)) {
  1327. addGap(gaps, prevXPos, xPos);
  1328. inGap = true;
  1329. }
  1330. continue;
  1331. }
  1332. else {
  1333. if (inGap) {
  1334. addGap(gaps, prevXPos, xPos);
  1335. inGap = false;
  1336. }
  1337. xCoords.push((prevXPos = xPos));
  1338. yCoords.push(valToPosY(dataY[i], scaleY, yDim, yOff));
  1339. }
  1340. }
  1341. var _paths = {stroke: catmullRomFitting(xCoords, yCoords, 0.5, moveTo, bezierCurveTo), fill: null, clip: null, band: null};
  1342. var stroke = _paths.stroke;
  1343. if (series.fill != null) {
  1344. var fill = _paths.fill = new Path2D(stroke);
  1345. var fillTo = series.fillTo(u, seriesIdx, series.min, series.max);
  1346. var minY = round(valToPosY(fillTo, scaleY, yDim, yOff));
  1347. lineTo(fill, prevXPos, minY);
  1348. lineTo(fill, firstXPos, minY);
  1349. }
  1350. if (!series.spanGaps)
  1351. { _paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim); }
  1352. if (u.bands.length > 0) {
  1353. // ADDL OPT: only create band clips for series that are band lower edges
  1354. // if (b.series[1] == i && _paths.band == null)
  1355. _paths.band = clipBandLine(u, seriesIdx, idx0, idx1, stroke);
  1356. }
  1357. return _paths;
  1358. // if FEAT_PATHS: false in rollup.config.js
  1359. // u.ctx.save();
  1360. // u.ctx.beginPath();
  1361. // u.ctx.rect(u.bbox.left, u.bbox.top, u.bbox.width, u.bbox.height);
  1362. // u.ctx.clip();
  1363. // u.ctx.strokeStyle = u.series[sidx].stroke;
  1364. // u.ctx.stroke(stroke);
  1365. // u.ctx.fillStyle = u.series[sidx].fill;
  1366. // u.ctx.fill(fill);
  1367. // u.ctx.restore();
  1368. // return null;
  1369. });
  1370. };
  1371. }
  1372. // adapted from https://gist.github.com/nicholaswmin/c2661eb11cad5671d816 (MIT)
  1373. function catmullRomFitting(xCoords, yCoords, alpha, moveTo, bezierCurveTo) {
  1374. var path = new Path2D();
  1375. var dataLen = xCoords.length;
  1376. var p0x,
  1377. p0y,
  1378. p1x,
  1379. p1y,
  1380. p2x,
  1381. p2y,
  1382. p3x,
  1383. p3y,
  1384. bp1x,
  1385. bp1y,
  1386. bp2x,
  1387. bp2y,
  1388. d1,
  1389. d2,
  1390. d3,
  1391. A,
  1392. B,
  1393. N,
  1394. M,
  1395. d3powA,
  1396. d2powA,
  1397. d3pow2A,
  1398. d2pow2A,
  1399. d1pow2A,
  1400. d1powA;
  1401. moveTo(path, round(xCoords[0]), round(yCoords[0]));
  1402. for (var i = 0; i < dataLen - 1; i++) {
  1403. var p0i = i == 0 ? 0 : i - 1;
  1404. p0x = xCoords[p0i];
  1405. p0y = yCoords[p0i];
  1406. p1x = xCoords[i];
  1407. p1y = yCoords[i];
  1408. p2x = xCoords[i + 1];
  1409. p2y = yCoords[i + 1];
  1410. if (i + 2 < dataLen) {
  1411. p3x = xCoords[i + 2];
  1412. p3y = yCoords[i + 2];
  1413. } else {
  1414. p3x = p2x;
  1415. p3y = p2y;
  1416. }
  1417. d1 = sqrt(pow(p0x - p1x, 2) + pow(p0y - p1y, 2));
  1418. d2 = sqrt(pow(p1x - p2x, 2) + pow(p1y - p2y, 2));
  1419. d3 = sqrt(pow(p2x - p3x, 2) + pow(p2y - p3y, 2));
  1420. // Catmull-Rom to Cubic Bezier conversion matrix
  1421. // A = 2d1^2a + 3d1^a * d2^a + d3^2a
  1422. // B = 2d3^2a + 3d3^a * d2^a + d2^2a
  1423. // [ 0 1 0 0 ]
  1424. // [ -d2^2a /N A/N d1^2a /N 0 ]
  1425. // [ 0 d3^2a /M B/M -d2^2a /M ]
  1426. // [ 0 0 1 0 ]
  1427. d3powA = pow(d3, alpha);
  1428. d3pow2A = pow(d3, alpha * 2);
  1429. d2powA = pow(d2, alpha);
  1430. d2pow2A = pow(d2, alpha * 2);
  1431. d1powA = pow(d1, alpha);
  1432. d1pow2A = pow(d1, alpha * 2);
  1433. A = 2 * d1pow2A + 3 * d1powA * d2powA + d2pow2A;
  1434. B = 2 * d3pow2A + 3 * d3powA * d2powA + d2pow2A;
  1435. N = 3 * d1powA * (d1powA + d2powA);
  1436. if (N > 0)
  1437. { N = 1 / N; }
  1438. M = 3 * d3powA * (d3powA + d2powA);
  1439. if (M > 0)
  1440. { M = 1 / M; }
  1441. bp1x = (-d2pow2A * p0x + A * p1x + d1pow2A * p2x) * N;
  1442. bp1y = (-d2pow2A * p0y + A * p1y + d1pow2A * p2y) * N;
  1443. bp2x = (d3pow2A * p1x + B * p2x - d2pow2A * p3x) * M;
  1444. bp2y = (d3pow2A * p1y + B * p2y - d2pow2A * p3y) * M;
  1445. if (bp1x == 0 && bp1y == 0) {
  1446. bp1x = p1x;
  1447. bp1y = p1y;
  1448. }
  1449. if (bp2x == 0 && bp2y == 0) {
  1450. bp2x = p2x;
  1451. bp2y = p2y;
  1452. }
  1453. bezierCurveTo(path, bp1x, bp1y, bp2x, bp2y, p2x, p2y);
  1454. }
  1455. return path;
  1456. }
  1457. function stepped(opts) {
  1458. var align = ifNull(opts.align, 1);
  1459. return (u, seriesIdx, idx0, idx1) => {
  1460. return orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {
  1461. var lineTo = scaleX.ori == 0 ? lineToH : lineToV;
  1462. var _paths = {stroke: new Path2D(), fill: null, clip: null, band: null};
  1463. var stroke = _paths.stroke;
  1464. var _dir = 1 * scaleX.dir * (scaleX.ori == 0 ? 1 : -1);
  1465. idx0 = nonNullIdx(dataY, idx0, idx1, 1);
  1466. idx1 = nonNullIdx(dataY, idx0, idx1, -1);
  1467. var gaps = [];
  1468. var inGap = false;
  1469. var prevYPos = round(valToPosY(dataY[_dir == 1 ? idx0 : idx1], scaleY, yDim, yOff));
  1470. var firstXPos = round(valToPosX(dataX[_dir == 1 ? idx0 : idx1], scaleX, xDim, xOff));
  1471. var prevXPos = firstXPos;
  1472. lineTo(stroke, firstXPos, prevYPos);
  1473. for (var i = _dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += _dir) {
  1474. var yVal1 = dataY[i];
  1475. var x1 = round(valToPosX(dataX[i], scaleX, xDim, xOff));
  1476. if (yVal1 == null) {
  1477. if (series.isGap(u, seriesIdx, i)) {
  1478. addGap(gaps, prevXPos, x1);
  1479. inGap = true;
  1480. }
  1481. continue;
  1482. }
  1483. var y1 = round(valToPosY(yVal1, scaleY, yDim, yOff));
  1484. if (inGap) {
  1485. addGap(gaps, prevXPos, x1);
  1486. // don't clip vertical extenders
  1487. if (prevYPos != y1) {
  1488. var halfStroke = (series.width * pxRatio) / 2;
  1489. var lastGap = gaps[gaps.length - 1];
  1490. lastGap[0] += halfStroke;
  1491. lastGap[1] -= halfStroke;
  1492. }
  1493. inGap = false;
  1494. }
  1495. if (align == 1)
  1496. { lineTo(stroke, x1, prevYPos); }
  1497. else
  1498. { lineTo(stroke, prevXPos, y1); }
  1499. lineTo(stroke, x1, y1);
  1500. prevYPos = y1;
  1501. prevXPos = x1;
  1502. }
  1503. if (series.fill != null) {
  1504. var fill = _paths.fill = new Path2D(stroke);
  1505. var fillTo = series.fillTo(u, seriesIdx, series.min, series.max);
  1506. var minY = round(valToPosY(fillTo, scaleY, yDim, yOff));
  1507. lineTo(fill, prevXPos, minY);
  1508. lineTo(fill, firstXPos, minY);
  1509. }
  1510. if (!series.spanGaps)
  1511. { _paths.clip = clipGaps(gaps, scaleX.ori, xOff, yOff, xDim, yDim); }
  1512. if (u.bands.length > 0) {
  1513. // ADDL OPT: only create band clips for series that are band lower edges
  1514. // if (b.series[1] == i && _paths.band == null)
  1515. _paths.band = clipBandLine(u, seriesIdx, idx0, idx1, stroke);
  1516. }
  1517. return _paths;
  1518. });
  1519. };
  1520. }
  1521. function bars(opts) {
  1522. opts = opts || EMPTY_OBJ;
  1523. var size = ifNull(opts.size, [0.6, inf]);
  1524. var align = opts.align || 0;
  1525. var gapFactor = 1 - size[0];
  1526. var maxWidth = ifNull(size[1], inf) * pxRatio;
  1527. return (u, seriesIdx, idx0, idx1) => {
  1528. return orient(u, seriesIdx, (series, dataX, dataY, scaleX, scaleY, valToPosX, valToPosY, xOff, yOff, xDim, yDim) => {
  1529. var rect = scaleX.ori == 0 ? rectH : rectV;
  1530. var colWid = valToPosX(dataX[1], scaleX, xDim, xOff) - valToPosX(dataX[0], scaleX, xDim, xOff);
  1531. var gapWid = colWid * gapFactor;
  1532. var fillToY = series.fillTo(u, seriesIdx, series.min, series.max);
  1533. var y0Pos = valToPosY(fillToY, scaleY, yDim, yOff);
  1534. var strokeWidth = round(series.width * pxRatio);
  1535. var barWid = round(min(maxWidth, colWid - gapWid) - strokeWidth);
  1536. var xShift = align == 1 ? 0 : align == -1 ? barWid : barWid / 2;
  1537. var _paths = {stroke: new Path2D(), fill: null, clip: null, band: null};
  1538. var hasBands = u.bands.length > 0;
  1539. var yLimit;
  1540. if (hasBands) {
  1541. // ADDL OPT: only create band clips for series that are band lower edges
  1542. // if (b.series[1] == i && _paths.band == null)
  1543. _paths.band = new Path2D();
  1544. yLimit = incrRound(valToPosY(scaleY.max, scaleY, yDim, yOff), 0.5);
  1545. }
  1546. var stroke = _paths.stroke;
  1547. var band = _paths.band;
  1548. var _dir = scaleX.dir * (scaleX.ori == 0 ? 1 : -1);
  1549. for (var i = _dir == 1 ? idx0 : idx1; i >= idx0 && i <= idx1; i += _dir) {
  1550. var yVal = dataY[i];
  1551. // interpolate upwards band clips
  1552. if (yVal == null) {
  1553. if (hasBands) {
  1554. // simple, but inefficient bi-directinal linear scans on each iteration
  1555. var prevNonNull = nonNullIdx(dataY, _dir == 1 ? idx0 : idx1, i, -_dir);
  1556. var nextNonNull = nonNullIdx(dataY, i, _dir == 1 ? idx1 : idx0, _dir);
  1557. var prevVal = dataY[prevNonNull];
  1558. var nextVal = dataY[nextNonNull];
  1559. yVal = prevVal + (i - prevNonNull) / (nextNonNull - prevNonNull) * (nextVal - prevVal);
  1560. }
  1561. else
  1562. { continue; }
  1563. }
  1564. var xVal = scaleX.distr == 2 ? i : dataX[i];
  1565. // TODO: all xPos can be pre-computed once for all series in aligned set
  1566. var xPos = valToPosX(xVal, scaleX, xDim, xOff);
  1567. var yPos = valToPosY(yVal, scaleY, yDim, yOff);
  1568. var lft = round(xPos - xShift);
  1569. var btm = round(max(yPos, y0Pos));
  1570. var top = round(min(yPos, y0Pos));
  1571. var barHgt = btm - top;
  1572. dataY[i] != null && rect(stroke, lft, top, barWid, barHgt);
  1573. if (hasBands) {
  1574. btm = top;
  1575. top = yLimit;
  1576. barHgt = btm - top;
  1577. rect(band, lft, top, barWid, barHgt);
  1578. }
  1579. }
  1580. if (series.fill != null)
  1581. { _paths.fill = new Path2D(stroke); }
  1582. return _paths;
  1583. });
  1584. };
  1585. }
  1586. var linearPath = linear() ;
  1587. function setDefaults(d, xo, yo, initY) {
  1588. var d2 = initY ? [d[0], d[1]].concat(d.slice(2)) : [d[0]].concat(d.slice(1));
  1589. return d2.map((o, i) => setDefault(o, i, xo, yo));
  1590. }
  1591. function setDefault(o, i, xo, yo) {
  1592. return assign({}, (i == 0 ? xo : yo), o);
  1593. }
  1594. var nullMinMax = [null, null];
  1595. function snapNumX(self, dataMin, dataMax) {
  1596. return dataMin == null ? nullMinMax : [dataMin, dataMax];
  1597. }
  1598. var snapTimeX = snapNumX;
  1599. // this ensures that non-temporal/numeric y-axes get multiple-snapped padding added above/below
  1600. // TODO: also account for incrs when snapping to ensure top of axis gets a tick & value
  1601. function snapNumY(self, dataMin, dataMax) {
  1602. return dataMin == null ? nullMinMax : rangeNum(dataMin, dataMax, 0.1, true);
  1603. }
  1604. function snapLogY(self, dataMin, dataMax, scale) {
  1605. return dataMin == null ? nullMinMax : rangeLog(dataMin, dataMax, self.scales[scale].log, false);
  1606. }
  1607. var snapLogX = snapLogY;
  1608. // dim is logical (getClientBoundingRect) pixels, not canvas pixels
  1609. function findIncr(min, max, incrs, dim, minSpace) {
  1610. var pxPerUnit = dim / (max - min);
  1611. var minDec = (""+floor(min)).length;
  1612. for (var i = 0; i < incrs.length; i++) {
  1613. var space = incrs[i] * pxPerUnit;
  1614. var incrDec = incrs[i] < 10 ? fixedDec.get(incrs[i]) : 0;
  1615. if (space >= minSpace && minDec + incrDec < 17)
  1616. { return [incrs[i], space]; }
  1617. }
  1618. return [0, 0];
  1619. }
  1620. function pxRatioFont(font) {
  1621. var fontSize;
  1622. font = font.replace(/(\d+)px/, (m, p1) => (fontSize = round(p1 * pxRatio)) + 'px');
  1623. return [font, fontSize];
  1624. }
  1625. function uPlot(opts, data, then) {
  1626. var self = {};
  1627. function getValPct(val, scale) {
  1628. return (
  1629. scale.distr == 3
  1630. ? log10((val > 0 ? val : scale.clamp(self, val, scale.min, scale.max, scale.key)) / scale.min) / log10(scale.max / scale.min)
  1631. : (val - scale.min) / (scale.max - scale.min)
  1632. );
  1633. }
  1634. function getHPos(val, scale, dim, off) {
  1635. var pct = getValPct(val, scale);
  1636. return off + dim * (scale.dir == -1 ? (1 - pct) : pct);
  1637. }
  1638. function getVPos(val, scale, dim, off) {
  1639. var pct = getValPct(val, scale);
  1640. return off + dim * (scale.dir == -1 ? pct : (1 - pct));
  1641. }
  1642. function getPos(val, scale, dim, off) {
  1643. return scale.ori == 0 ? getHPos(val, scale, dim, off) : getVPos(val, scale, dim, off);
  1644. }
  1645. self.valToPosH = getHPos;
  1646. self.valToPosV = getVPos;
  1647. var ready = false;
  1648. self.status = 0;
  1649. var root = self.root = placeDiv(UPLOT);
  1650. if (opts.id != null)
  1651. { root.id = opts.id; }
  1652. addClass(root, opts.class);
  1653. if (opts.title) {
  1654. var title = placeDiv(TITLE, root);
  1655. title.textContent = opts.title;
  1656. }
  1657. var can = placeTag("canvas");
  1658. var ctx = self.ctx = can.getContext("2d");
  1659. var wrap = placeDiv(WRAP, root);
  1660. var under = placeDiv(UNDER, wrap);
  1661. wrap.appendChild(can);
  1662. var over = placeDiv(OVER, wrap);
  1663. opts = copy(opts);
  1664. (opts.plugins || []).forEach(p => {
  1665. if (p.opts)
  1666. { opts = p.opts(self, opts) || opts; }
  1667. });
  1668. var ms = opts.ms || 1e-3;
  1669. var series = self.series = setDefaults(opts.series || [], xSeriesOpts, ySeriesOpts, false);
  1670. var axes = self.axes = setDefaults(opts.axes || [], xAxisOpts, yAxisOpts, true);
  1671. var scales = self.scales = {};
  1672. var bands = self.bands = opts.bands || [];
  1673. bands.forEach(b => {
  1674. b.fill = fnOrSelf(b.fill || null);
  1675. });
  1676. var xScaleKey = series[0].scale;
  1677. var drawOrderMap = {
  1678. axes: drawAxesGrid,
  1679. series: drawSeries,
  1680. };
  1681. var drawOrder = (opts.drawOrder || ["axes", "series"]).map(key => drawOrderMap[key]);
  1682. function initScale(scaleKey) {
  1683. var sc = scales[scaleKey];
  1684. if (sc == null) {
  1685. var scaleOpts = (opts.scales || EMPTY_OBJ)[scaleKey] || EMPTY_OBJ;
  1686. if (scaleOpts.from != null) {
  1687. // ensure parent is initialized
  1688. initScale(scaleOpts.from);
  1689. // dependent scales inherit
  1690. scales[scaleKey] = assign({}, scales[scaleOpts.from], scaleOpts);
  1691. }
  1692. else {
  1693. sc = scales[scaleKey] = assign({}, (scaleKey == xScaleKey ? xScaleOpts : yScaleOpts), scaleOpts);
  1694. sc.key = scaleKey;
  1695. var isTime = sc.time;
  1696. var isLog = sc.distr == 3;
  1697. var rn = sc.range;
  1698. if (scaleKey != xScaleKey && !isArr(rn) && isObj(rn)) {
  1699. var cfg = rn;
  1700. // this is similar to snapNumY
  1701. rn = (self, dataMin, dataMax) => dataMin == null ? nullMinMax : rangeNum(dataMin, dataMax, cfg);
  1702. }
  1703. sc.range = fnOrSelf(rn || (isTime ? snapTimeX : scaleKey == xScaleKey ? (isLog ? snapLogX : snapNumX) : (isLog ? snapLogY : snapNumY)));
  1704. sc.auto = fnOrSelf(sc.auto);
  1705. sc.clamp = fnOrSelf(sc.clamp || clampScale);
  1706. }
  1707. }
  1708. }
  1709. initScale("x");
  1710. initScale("y");
  1711. series.forEach(s => {
  1712. initScale(s.scale);
  1713. });
  1714. axes.forEach(a => {
  1715. initScale(a.scale);
  1716. });
  1717. for (var k in opts.scales)
  1718. { initScale(k); }
  1719. var scaleX = scales[xScaleKey];
  1720. var xScaleDistr = scaleX.distr;
  1721. var valToPosX, valToPosY, moveTo, arc;
  1722. if (scaleX.ori == 0) {
  1723. addClass(root, ORI_HZ);
  1724. valToPosX = getHPos;
  1725. valToPosY = getVPos;
  1726. moveTo = moveToH;
  1727. arc = arcH;
  1728. /*
  1729. updOriDims = () => {
  1730. xDimCan = plotWid;
  1731. xOffCan = plotLft;
  1732. yDimCan = plotHgt;
  1733. yOffCan = plotTop;
  1734. xDimCss = plotWidCss;
  1735. xOffCss = plotLftCss;
  1736. yDimCss = plotHgtCss;
  1737. yOffCss = plotTopCss;
  1738. };
  1739. */
  1740. }
  1741. else {
  1742. addClass(root, ORI_VT);
  1743. valToPosX = getVPos;
  1744. valToPosY = getHPos;
  1745. moveTo = moveToV;
  1746. arc = arcV;
  1747. /*
  1748. updOriDims = () => {
  1749. xDimCan = plotHgt;
  1750. xOffCan = plotTop;
  1751. yDimCan = plotWid;
  1752. yOffCan = plotLft;
  1753. xDimCss = plotHgtCss;
  1754. xOffCss = plotTopCss;
  1755. yDimCss = plotWidCss;
  1756. yOffCss = plotLftCss;
  1757. };
  1758. */
  1759. }
  1760. var pendScales = {};
  1761. // explicitly-set initial scales
  1762. for (var k$1 in scales) {
  1763. var sc = scales[k$1];
  1764. if (sc.min != null || sc.max != null)
  1765. { pendScales[k$1] = {min: sc.min, max: sc.max}; }
  1766. }
  1767. // self.tz = opts.tz || Intl.DateTimeFormat().resolvedOptions().timeZone;
  1768. var _tzDate = (opts.tzDate || (ts => new Date(ts / ms)));
  1769. var _fmtDate = (opts.fmtDate || fmtDate);
  1770. var _timeAxisSplits = (ms == 1 ? timeAxisSplitsMs(_tzDate) : timeAxisSplitsS(_tzDate));
  1771. var _timeAxisVals = timeAxisVals(_tzDate, timeAxisStamps((ms == 1 ? _timeAxisStampsMs : _timeAxisStampsS), _fmtDate));
  1772. var _timeSeriesVal = timeSeriesVal(_tzDate, timeSeriesStamp(_timeSeriesStamp, _fmtDate));
  1773. var legend = assign({show: true, live: true}, opts.legend);
  1774. var showLegend = legend.show;
  1775. {
  1776. legend.width = fnOrSelf(ifNull(legend.width, legendWidth));
  1777. legend.dash = fnOrSelf(legend.dash || legendDash);
  1778. legend.stroke = fnOrSelf(legend.stroke || legendStroke);
  1779. legend.fill = fnOrSelf(legend.fill || legendFill);
  1780. }
  1781. var legendEl;
  1782. var legendRows = [];
  1783. var legendCols;
  1784. var multiValLegend = false;
  1785. if (showLegend) {
  1786. legendEl = placeTag("table", LEGEND, root);
  1787. var getMultiVals = series[1] ? series[1].values : null;
  1788. multiValLegend = getMultiVals != null;
  1789. if (multiValLegend) {
  1790. var head = placeTag("tr", LEGEND_THEAD, legendEl);
  1791. placeTag("th", null, head);
  1792. legendCols = getMultiVals(self, 1, 0);
  1793. for (var key in legendCols)
  1794. { placeTag("th", LEGEND_LABEL, head).textContent = key; }
  1795. }
  1796. else {
  1797. legendCols = {_: 0};
  1798. addClass(legendEl, LEGEND_INLINE);
  1799. legend.live && addClass(legendEl, LEGEND_LIVE);
  1800. }
  1801. }
  1802. function initLegendRow(s, i) {
  1803. if (i == 0 && (multiValLegend || !legend.live))
  1804. { return null; }
  1805. var _row = [];
  1806. var row = placeTag("tr", LEGEND_SERIES, legendEl, legendEl.childNodes[i]);
  1807. addClass(row, s.class);
  1808. if (!s.show)
  1809. { addClass(row, OFF); }
  1810. var label = placeTag("th", null, row);
  1811. var indic = placeDiv(LEGEND_MARKER, label);
  1812. if (i > 0) {
  1813. var width = legend.width(self, i);
  1814. if (width)
  1815. { indic.style.border = width + "px " + legend.dash(self, i) + " " + legend.stroke(self, i); }
  1816. indic.style.background = legend.fill(self, i);
  1817. }
  1818. var text = placeDiv(LEGEND_LABEL, label);
  1819. text.textContent = s.label;
  1820. if (i > 0) {
  1821. onMouse("click", label, e => {
  1822. if ( cursor._lock)
  1823. { return; }
  1824. setSeries(series.indexOf(s), {show: !s.show}, syncOpts.setSeries);
  1825. });
  1826. if (cursorFocus) {
  1827. onMouse(mouseenter, label, e => {
  1828. if (cursor._lock)
  1829. { return; }
  1830. setSeries(series.indexOf(s), FOCUS_TRUE, syncOpts.setSeries);
  1831. });
  1832. }
  1833. }
  1834. for (var key in legendCols) {
  1835. var v = placeTag("td", LEGEND_VALUE, row);
  1836. v.textContent = "--";
  1837. _row.push(v);
  1838. }
  1839. return _row;
  1840. }
  1841. var mouseListeners = new Map();
  1842. function onMouse(ev, targ, fn) {
  1843. var targListeners = mouseListeners.get(targ) || {};
  1844. var listener = cursor.bind[ev](self, targ, fn);
  1845. if (listener) {
  1846. on(ev, targ, targListeners[ev] = listener);
  1847. mouseListeners.set(targ, targListeners);
  1848. }
  1849. }
  1850. function offMouse(ev, targ, fn) {
  1851. var targListeners = mouseListeners.get(targ) || {};
  1852. off(ev, targ, targListeners[ev]);
  1853. targListeners[ev] = null;
  1854. }
  1855. var fullWidCss = 0;
  1856. var fullHgtCss = 0;
  1857. var plotWidCss = 0;
  1858. var plotHgtCss = 0;
  1859. // plot margins to account for axes
  1860. var plotLftCss = 0;
  1861. var plotTopCss = 0;
  1862. var plotLft = 0;
  1863. var plotTop = 0;
  1864. var plotWid = 0;
  1865. var plotHgt = 0;
  1866. self.bbox = {};
  1867. var shouldSetScales = false;
  1868. var shouldSetSize = false;
  1869. var shouldConvergeSize = false;
  1870. var shouldSetCursor = false;
  1871. var shouldSetLegend = false;
  1872. function _setSize(width, height) {
  1873. if (width != self.width || height != self.height)
  1874. { calcSize(width, height); }
  1875. resetYSeries(false);
  1876. shouldConvergeSize = true;
  1877. shouldSetSize = true;
  1878. shouldSetCursor = true;
  1879. shouldSetLegend = true;
  1880. commit();
  1881. }
  1882. function calcSize(width, height) {
  1883. // log("calcSize()", arguments);
  1884. self.width = fullWidCss = plotWidCss = width;
  1885. self.height = fullHgtCss = plotHgtCss = height;
  1886. plotLftCss = plotTopCss = 0;
  1887. calcPlotRect();
  1888. calcAxesRects();
  1889. var bb = self.bbox;
  1890. plotLft = bb.left = incrRound(plotLftCss * pxRatio, 0.5);
  1891. plotTop = bb.top = incrRound(plotTopCss * pxRatio, 0.5);
  1892. plotWid = bb.width = incrRound(plotWidCss * pxRatio, 0.5);
  1893. plotHgt = bb.height = incrRound(plotHgtCss * pxRatio, 0.5);
  1894. // updOriDims();
  1895. }
  1896. function convergeSize() {
  1897. var converged = false;
  1898. var cycleNum = 0;
  1899. while (!converged) {
  1900. cycleNum++;
  1901. var axesConverged = axesCalc(cycleNum);
  1902. var paddingConverged = paddingCalc(cycleNum);
  1903. converged = axesConverged && paddingConverged;
  1904. if (!converged) {
  1905. calcSize(self.width, self.height);
  1906. shouldSetSize = true;
  1907. }
  1908. }
  1909. }
  1910. function setSize(ref) {
  1911. var width = ref.width;
  1912. var height = ref.height;
  1913. _setSize(width, height);
  1914. }
  1915. self.setSize = setSize;
  1916. // accumulate axis offsets, reduce canvas width
  1917. function calcPlotRect() {
  1918. // easements for edge labels
  1919. var hasTopAxis = false;
  1920. var hasBtmAxis = false;
  1921. var hasRgtAxis = false;
  1922. var hasLftAxis = false;
  1923. axes.forEach((axis, i) => {
  1924. if (axis.show && axis._show) {
  1925. var side = axis.side;
  1926. var _size = axis._size;
  1927. var isVt = side % 2;
  1928. var labelSize = axis.labelSize = (axis.label != null ? (axis.labelSize || 30) : 0);
  1929. var fullSize = _size + labelSize;
  1930. if (fullSize > 0) {
  1931. if (isVt) {
  1932. plotWidCss -= fullSize;
  1933. if (side == 3) {
  1934. plotLftCss += fullSize;
  1935. hasLftAxis = true;
  1936. }
  1937. else
  1938. { hasRgtAxis = true; }
  1939. }
  1940. else {
  1941. plotHgtCss -= fullSize;
  1942. if (side == 0) {
  1943. plotTopCss += fullSize;
  1944. hasTopAxis = true;
  1945. }
  1946. else
  1947. { hasBtmAxis = true; }
  1948. }
  1949. }
  1950. }
  1951. });
  1952. sidesWithAxes[0] = hasTopAxis;
  1953. sidesWithAxes[1] = hasRgtAxis;
  1954. sidesWithAxes[2] = hasBtmAxis;
  1955. sidesWithAxes[3] = hasLftAxis;
  1956. // hz padding
  1957. plotWidCss -= _padding[1] + _padding[3];
  1958. plotLftCss += _padding[3];
  1959. // vt padding
  1960. plotHgtCss -= _padding[2] + _padding[0];
  1961. plotTopCss += _padding[0];
  1962. }
  1963. function calcAxesRects() {
  1964. // will accum +
  1965. var off1 = plotLftCss + plotWidCss;
  1966. var off2 = plotTopCss + plotHgtCss;
  1967. // will accum -
  1968. var off3 = plotLftCss;
  1969. var off0 = plotTopCss;
  1970. function incrOffset(side, size) {
  1971. switch (side) {
  1972. case 1: off1 += size; return off1 - size;
  1973. case 2: off2 += size; return off2 - size;
  1974. case 3: off3 -= size; return off3 + size;
  1975. case 0: off0 -= size; return off0 + size;
  1976. }
  1977. }
  1978. axes.forEach((axis, i) => {
  1979. if (axis.show && axis._show) {
  1980. var side = axis.side;
  1981. axis._pos = incrOffset(side, axis._size);
  1982. if (axis.label != null)
  1983. { axis._lpos = incrOffset(side, axis.labelSize); }
  1984. }
  1985. });
  1986. }
  1987. var cursor = (self.cursor = assign({}, cursorOpts, opts.cursor));
  1988. {
  1989. cursor._lock = false;
  1990. var points = cursor.points;
  1991. points.show = fnOrSelf(points.show);
  1992. points.size = fnOrSelf(points.size);
  1993. points.stroke = fnOrSelf(points.stroke);
  1994. points.width = fnOrSelf(points.width);
  1995. points.fill = fnOrSelf(points.fill);
  1996. }
  1997. var focus = self.focus = assign({}, opts.focus || {alpha: 0.3}, cursor.focus);
  1998. var cursorFocus = focus.prox >= 0;
  1999. // series-intersection markers
  2000. var cursorPts = [null];
  2001. function initCursorPt(s, si) {
  2002. if (si > 0) {
  2003. var pt = cursor.points.show(self, si);
  2004. if (pt) {
  2005. addClass(pt, CURSOR_PT);
  2006. addClass(pt, s.class);
  2007. trans(pt, -10, -10, plotWidCss, plotHgtCss);
  2008. over.insertBefore(pt, cursorPts[si]);
  2009. return pt;
  2010. }
  2011. }
  2012. }
  2013. function initSeries(s, i) {
  2014. var isTime = scales[s.scale].time;
  2015. var sv = s.value;
  2016. s.value = isTime ? (isStr(sv) ? timeSeriesVal(_tzDate, timeSeriesStamp(sv, _fmtDate)) : sv || _timeSeriesVal) : sv || numSeriesVal;
  2017. s.label = s.label || (isTime ? timeSeriesLabel : numSeriesLabel);
  2018. if (i > 0) {
  2019. s.width = s.width == null ? 1 : s.width;
  2020. s.paths = s.paths || linearPath || retNull;
  2021. s.fillTo = fnOrSelf(s.fillTo || seriesFillTo);
  2022. s.stroke = fnOrSelf(s.stroke || hexBlack);
  2023. s.fill = fnOrSelf(s.fill || null);
  2024. s._stroke = s._fill = s._paths = null;
  2025. var _ptDia = ptDia(s.width, 1);
  2026. var points = s.points = assign({}, {
  2027. size: _ptDia,
  2028. width: max(1, _ptDia * .2),
  2029. stroke: s.stroke,
  2030. space: _ptDia * 2,
  2031. _stroke: null,
  2032. _fill: null,
  2033. }, s.points);
  2034. points.show = fnOrSelf(points.show);
  2035. points.fill = fnOrSelf(points.fill);
  2036. points.stroke = fnOrSelf(points.stroke);
  2037. }
  2038. if (showLegend)
  2039. { legendRows.splice(i, 0, initLegendRow(s, i)); }
  2040. if ( cursor.show) {
  2041. var pt = initCursorPt(s, i);
  2042. pt && cursorPts.splice(i, 0, pt);
  2043. }
  2044. }
  2045. function addSeries(opts, si) {
  2046. si = si == null ? series.length : si;
  2047. opts = setDefault(opts, si, xSeriesOpts, ySeriesOpts);
  2048. series.splice(si, 0, opts);
  2049. initSeries(series[si], si);
  2050. }
  2051. self.addSeries = addSeries;
  2052. function delSeries(i) {
  2053. series.splice(i, 1);
  2054. showLegend && legendRows.splice(i, 1)[0][0].parentNode.remove();
  2055. cursorPts.length > 1 && cursorPts.splice(i, 1)[0].remove();
  2056. // TODO: de-init no-longer-needed scales?
  2057. }
  2058. self.delSeries = delSeries;
  2059. series.forEach(initSeries);
  2060. var sidesWithAxes = [false, false, false, false];
  2061. function initAxis(axis, i) {
  2062. axis._show = axis.show;
  2063. if (axis.show) {
  2064. var isVt = axis.side % 2;
  2065. var sc = scales[axis.scale];
  2066. // this can occur if all series specify non-default scales
  2067. if (sc == null) {
  2068. axis.scale = isVt ? series[1].scale : xScaleKey;
  2069. sc = scales[axis.scale];
  2070. }
  2071. // also set defaults for incrs & values based on axis distr
  2072. var isTime = sc.time;
  2073. axis.size = fnOrSelf(axis.size);
  2074. axis.space = fnOrSelf(axis.space);
  2075. axis.rotate = fnOrSelf(axis.rotate);
  2076. axis.incrs = fnOrSelf(axis.incrs || ( sc.distr == 2 ? wholeIncrs : (isTime ? (ms == 1 ? timeIncrsMs : timeIncrsS) : numIncrs)));
  2077. axis.splits = fnOrSelf(axis.splits || (isTime && sc.distr == 1 ? _timeAxisSplits : sc.distr == 3 ? logAxisSplits : numAxisSplits));
  2078. var av = axis.values;
  2079. axis.values = (
  2080. isTime ? (
  2081. isArr(av) ?
  2082. timeAxisVals(_tzDate, timeAxisStamps(av, _fmtDate)) :
  2083. isStr(av) ?
  2084. timeAxisVal(_tzDate, av) :
  2085. av || _timeAxisVals
  2086. ) : av || numAxisVals
  2087. );
  2088. axis.filter = fnOrSelf(axis.filter || ( sc.distr == 3 ? logAxisValsFilt : retArg1));
  2089. axis.font = pxRatioFont(axis.font);
  2090. axis.labelFont = pxRatioFont(axis.labelFont);
  2091. axis._size = axis.size(self, null, i, 0);
  2092. axis._space =
  2093. axis._rotate =
  2094. axis._incrs =
  2095. axis._found = // foundIncrSpace
  2096. axis._splits =
  2097. axis._values = null;
  2098. if (axis._size > 0)
  2099. { sidesWithAxes[i] = true; }
  2100. }
  2101. }
  2102. // set axis defaults
  2103. axes.forEach(initAxis);
  2104. function autoPadSide(self, side, sidesWithAxes, cycleNum) {
  2105. var hasTopAxis = sidesWithAxes[0];
  2106. var hasRgtAxis = sidesWithAxes[1];
  2107. var hasBtmAxis = sidesWithAxes[2];
  2108. var hasLftAxis = sidesWithAxes[3];
  2109. var ori = side % 2;
  2110. var size = 0;
  2111. if (ori == 0 && (hasLftAxis || hasRgtAxis))
  2112. { size = (side == 0 && !hasTopAxis || side == 2 && !hasBtmAxis ? round(xAxisOpts.size / 3) : 0); }
  2113. if (ori == 1 && (hasTopAxis || hasBtmAxis))
  2114. { size = (side == 1 && !hasRgtAxis || side == 3 && !hasLftAxis ? round(yAxisOpts.size / 2) : 0); }
  2115. return size;
  2116. }
  2117. var padding = self.padding = (opts.padding || [autoPadSide,autoPadSide,autoPadSide,autoPadSide]).map(p => fnOrSelf(ifNull(p, autoPadSide)));
  2118. var _padding = self._padding = padding.map((p, i) => p(self, i, sidesWithAxes, 0));
  2119. var dataLen;
  2120. // rendered data window
  2121. var i0 = null;
  2122. var i1 = null;
  2123. var idxs = series[0].idxs;
  2124. var data0 = null;
  2125. var viaAutoScaleX = false;
  2126. function setData(_data, _resetScales) {
  2127. if (!isArr(_data) && isObj(_data)) {
  2128. _data.isGap && series.forEach(s => { s.isGap = _data.isGap; });
  2129. _data = _data.data;
  2130. }
  2131. _data = _data || [];
  2132. _data[0] = _data[0] || [];
  2133. self.data = _data;
  2134. data = _data.slice();
  2135. data0 = data[0];
  2136. dataLen = data0.length;
  2137. if (xScaleDistr == 2)
  2138. { data[0] = data0.map((v, i) => i); }
  2139. self._data = data;
  2140. resetYSeries(true);
  2141. fire("setData");
  2142. if (_resetScales !== false) {
  2143. var xsc = scaleX;
  2144. if (xsc.auto(self, viaAutoScaleX))
  2145. { autoScaleX(); }
  2146. else
  2147. { _setScale(xScaleKey, xsc.min, xsc.max); }
  2148. shouldSetCursor = true;
  2149. shouldSetLegend = true;
  2150. commit();
  2151. }
  2152. }
  2153. self.setData = setData;
  2154. function autoScaleX() {
  2155. var assign, assign$1;
  2156. viaAutoScaleX = true;
  2157. var _min, _max;
  2158. if (dataLen > 0) {
  2159. i0 = idxs[0] = 0;
  2160. i1 = idxs[1] = dataLen - 1;
  2161. _min = data[0][i0];
  2162. _max = data[0][i1];
  2163. if (xScaleDistr == 2) {
  2164. _min = i0;
  2165. _max = i1;
  2166. }
  2167. else if (dataLen == 1) {
  2168. if (xScaleDistr == 3)
  2169. { (assign = rangeLog(_min, _min, scaleX.log, false), _min = assign[0], _max = assign[1]); }
  2170. else if (scaleX.time)
  2171. { _max = _min + 86400 / ms; }
  2172. else
  2173. { (assign$1 = rangeNum(_min, _max, 0.1, true), _min = assign$1[0], _max = assign$1[1]); }
  2174. }
  2175. }
  2176. else {
  2177. i0 = idxs[0] = _min = null;
  2178. i1 = idxs[1] = _max = null;
  2179. }
  2180. _setScale(xScaleKey, _min, _max);
  2181. }
  2182. function setCtxStyle(stroke, width, dash, cap, fill) {
  2183. ctx.strokeStyle = stroke || transparent;
  2184. ctx.lineWidth = width;
  2185. ctx.lineJoin = "round";
  2186. ctx.lineCap = cap || "butt"; // (‿|‿)
  2187. ctx.setLineDash(dash || []);
  2188. ctx.fillStyle = fill || transparent;
  2189. }
  2190. function setScales() {
  2191. // log("setScales()", arguments);
  2192. // wip scales
  2193. var wipScales = copy(scales);
  2194. for (var k in wipScales) {
  2195. var wsc = wipScales[k];
  2196. var psc = pendScales[k];
  2197. if (psc != null && psc.min != null) {
  2198. assign(wsc, psc);
  2199. // explicitly setting the x-scale invalidates everything (acts as redraw)
  2200. if (k == xScaleKey)
  2201. { resetYSeries(true); }
  2202. }
  2203. else if (k != xScaleKey) {
  2204. if (dataLen == 0 && wsc.from == null) {
  2205. var minMax = wsc.range(self, null, null, k);
  2206. wsc.min = minMax[0];
  2207. wsc.max = minMax[1];
  2208. }
  2209. else {
  2210. wsc.min = inf;
  2211. wsc.max = -inf;
  2212. }
  2213. }
  2214. }
  2215. if (dataLen > 0) {
  2216. // pre-range y-scales from y series' data values
  2217. series.forEach((s, i) => {
  2218. var k = s.scale;
  2219. var wsc = wipScales[k];
  2220. var psc = pendScales[k];
  2221. if (i == 0) {
  2222. var minMax = wsc.range(self, wsc.min, wsc.max, k);
  2223. wsc.min = minMax[0];
  2224. wsc.max = minMax[1];
  2225. i0 = closestIdx(wsc.min, data[0]);
  2226. i1 = closestIdx(wsc.max, data[0]);
  2227. // closest indices can be outside of view
  2228. if (data[0][i0] < wsc.min)
  2229. { i0++; }
  2230. if (data[0][i1] > wsc.max)
  2231. { i1--; }
  2232. s.min = data0[i0];
  2233. s.max = data0[i1];
  2234. }
  2235. else if (s.show && s.auto && wsc.auto(self, viaAutoScaleX) && (psc == null || psc.min == null)) {
  2236. // only run getMinMax() for invalidated series data, else reuse
  2237. var minMax$1 = s.min == null ? (wsc.distr == 3 ? getMinMaxLog(data[i], i0, i1) : getMinMax(data[i], i0, i1, s.sorted)) : [s.min, s.max];
  2238. // initial min/max
  2239. wsc.min = min(wsc.min, s.min = minMax$1[0]);
  2240. wsc.max = max(wsc.max, s.max = minMax$1[1]);
  2241. }
  2242. s.idxs[0] = i0;
  2243. s.idxs[1] = i1;
  2244. });
  2245. // range independent scales
  2246. for (var k$1 in wipScales) {
  2247. var wsc$1 = wipScales[k$1];
  2248. var psc$1 = pendScales[k$1];
  2249. if (wsc$1.from == null && (psc$1 == null || psc$1.min == null)) {
  2250. var minMax$1 = wsc$1.range(
  2251. self,
  2252. wsc$1.min == inf ? null : wsc$1.min,
  2253. wsc$1.max == -inf ? null : wsc$1.max,
  2254. k$1
  2255. );
  2256. wsc$1.min = minMax$1[0];
  2257. wsc$1.max = minMax$1[1];
  2258. }
  2259. }
  2260. }
  2261. // range dependent scales
  2262. for (var k$2 in wipScales) {
  2263. var wsc$2 = wipScales[k$2];
  2264. if (wsc$2.from != null) {
  2265. var base = wipScales[wsc$2.from];
  2266. var minMax$2 = wsc$2.range(self, base.min, base.max, k$2);
  2267. wsc$2.min = minMax$2[0];
  2268. wsc$2.max = minMax$2[1];
  2269. }
  2270. }
  2271. var changed = {};
  2272. var anyChanged = false;
  2273. for (var k$3 in wipScales) {
  2274. var wsc$3 = wipScales[k$3];
  2275. var sc = scales[k$3];
  2276. if (sc.min != wsc$3.min || sc.max != wsc$3.max) {
  2277. sc.min = wsc$3.min;
  2278. sc.max = wsc$3.max;
  2279. changed[k$3] = anyChanged = true;
  2280. }
  2281. }
  2282. if (anyChanged) {
  2283. // invalidate paths of all series on changed scales
  2284. series.forEach(s => {
  2285. if (changed[s.scale])
  2286. { s._paths = null; }
  2287. });
  2288. for (var k$4 in changed) {
  2289. shouldConvergeSize = true;
  2290. fire("setScale", k$4);
  2291. }
  2292. if ( cursor.show)
  2293. { shouldSetCursor = true; }
  2294. }
  2295. for (var k$5 in pendScales)
  2296. { pendScales[k$5] = null; }
  2297. }
  2298. // TODO: drawWrap(si, drawPoints) (save, restore, translate, clip)
  2299. function drawPoints(si) {
  2300. // log("drawPoints()", arguments);
  2301. var s = series[si];
  2302. var p = s.points;
  2303. var width = roundDec(p.width * pxRatio, 3);
  2304. var offset = (width % 2) / 2;
  2305. var isStroked = p.width > 0;
  2306. var rad = (p.size - p.width) / 2 * pxRatio;
  2307. var dia = roundDec(rad * 2, 3);
  2308. ctx.translate(offset, offset);
  2309. ctx.save();
  2310. ctx.beginPath();
  2311. ctx.rect(
  2312. plotLft - dia,
  2313. plotTop - dia,
  2314. plotWid + dia * 2,
  2315. plotHgt + dia * 2
  2316. );
  2317. ctx.clip();
  2318. ctx.globalAlpha = s.alpha;
  2319. var path = new Path2D();
  2320. var scaleY = scales[s.scale];
  2321. var xDim, xOff, yDim, yOff;
  2322. if (scaleX.ori == 0) {
  2323. xDim = plotWid;
  2324. xOff = plotLft;
  2325. yDim = plotHgt;
  2326. yOff = plotTop;
  2327. }
  2328. else {
  2329. xDim = plotHgt;
  2330. xOff = plotTop;
  2331. yDim = plotWid;
  2332. yOff = plotLft;
  2333. }
  2334. for (var pi = i0; pi <= i1; pi++) {
  2335. if (data[si][pi] != null) {
  2336. var x = round(valToPosX(data[0][pi], scaleX, xDim, xOff));
  2337. var y = round(valToPosY(data[si][pi], scaleY, yDim, yOff));
  2338. moveTo(path, x + rad, y);
  2339. arc(path, x, y, rad, 0, PI * 2);
  2340. }
  2341. }
  2342. var _stroke = p._stroke = p.stroke(self, si);
  2343. var _fill = p._fill = p.fill(self, si);
  2344. setCtxStyle(
  2345. _stroke,
  2346. width,
  2347. p.dash,
  2348. p.cap,
  2349. _fill || (isStroked ? "#fff" : s._stroke)
  2350. );
  2351. ctx.fill(path);
  2352. isStroked && ctx.stroke(path);
  2353. ctx.globalAlpha = 1;
  2354. ctx.restore();
  2355. ctx.translate(-offset, -offset);
  2356. }
  2357. // grabs the nearest indices with y data outside of x-scale limits
  2358. function getOuterIdxs(ydata) {
  2359. var _i0 = clamp(i0 - 1, 0, dataLen - 1);
  2360. var _i1 = clamp(i1 + 1, 0, dataLen - 1);
  2361. while (ydata[_i0] == null && _i0 > 0)
  2362. { _i0--; }
  2363. while (ydata[_i1] == null && _i1 < dataLen - 1)
  2364. { _i1++; }
  2365. return [_i0, _i1];
  2366. }
  2367. function drawSeries() {
  2368. if (dataLen > 0) {
  2369. series.forEach((s, i) => {
  2370. if (i > 0 && s.show && s._paths == null) {
  2371. var _idxs = getOuterIdxs(data[i]);
  2372. s._paths = s.paths(self, i, _idxs[0], _idxs[1]);
  2373. }
  2374. });
  2375. series.forEach((s, i) => {
  2376. if (i > 0 && s.show) {
  2377. if (s._paths)
  2378. { drawPath(i); }
  2379. if (s.points.show(self, i, i0, i1))
  2380. { drawPoints(i); }
  2381. fire("drawSeries", i);
  2382. }
  2383. });
  2384. }
  2385. }
  2386. function drawPath(si) {
  2387. var s = series[si];
  2388. var ref = s._paths;
  2389. var stroke = ref.stroke;
  2390. var fill = ref.fill;
  2391. var clip = ref.clip;
  2392. var width = roundDec(s.width * pxRatio, 3);
  2393. var offset = (width % 2) / 2;
  2394. var _stroke = s._stroke = s.stroke(self, si);
  2395. var _fill = s._fill = s.fill(self, si);
  2396. setCtxStyle(_stroke, width, s.dash, s.cap, _fill);
  2397. ctx.globalAlpha = s.alpha;
  2398. ctx.translate(offset, offset);
  2399. ctx.save();
  2400. var lft = plotLft,
  2401. top = plotTop,
  2402. wid = plotWid,
  2403. hgt = plotHgt;
  2404. var halfWid = width * pxRatio / 2;
  2405. if (s.min == 0)
  2406. { hgt += halfWid; }
  2407. if (s.max == 0) {
  2408. top -= halfWid;
  2409. hgt += halfWid;
  2410. }
  2411. ctx.beginPath();
  2412. ctx.rect(lft, top, wid, hgt);
  2413. ctx.clip();
  2414. if (clip != null)
  2415. { ctx.clip(clip); }
  2416. if (!fillBands(si, _fill) && _fill != null)
  2417. { ctx.fill(fill); }
  2418. width && ctx.stroke(stroke);
  2419. ctx.restore();
  2420. ctx.translate(-offset, -offset);
  2421. ctx.globalAlpha = 1;
  2422. }
  2423. function fillBands(si, seriesFill) {
  2424. var isUpperEdge = false;
  2425. var s = series[si];
  2426. // for all bands where this series is the top edge, create upwards clips using the bottom edges
  2427. // and apply clips + fill with band fill or dfltFill
  2428. bands.forEach((b, bi) => {
  2429. if (b.series[0] == si) {
  2430. isUpperEdge = true;
  2431. var lowerEdge = series[b.series[1]];
  2432. var clip = (lowerEdge._paths || EMPTY_OBJ).band;
  2433. if (lowerEdge.show && clip) {
  2434. ctx.save();
  2435. setCtxStyle(null, null, null, null, b.fill(self, bi) || seriesFill);
  2436. ctx.clip(clip);
  2437. ctx.fill(s._paths.fill);
  2438. ctx.restore();
  2439. }
  2440. }
  2441. });
  2442. return isUpperEdge;
  2443. }
  2444. function getIncrSpace(axisIdx, min, max, fullDim) {
  2445. var axis = axes[axisIdx];
  2446. var incrSpace;
  2447. if (fullDim <= 0)
  2448. { incrSpace = [0, 0]; }
  2449. else {
  2450. var minSpace = axis._space = axis.space(self, axisIdx, min, max, fullDim);
  2451. var incrs = axis._incrs = axis.incrs(self, axisIdx, min, max, fullDim, minSpace);
  2452. incrSpace = axis._found = findIncr(min, max, incrs, fullDim, minSpace);
  2453. }
  2454. return incrSpace;
  2455. }
  2456. function drawOrthoLines(offs, filts, ori, side, pos0, len, width, stroke, dash, cap) {
  2457. var offset = (width % 2) / 2;
  2458. ctx.translate(offset, offset);
  2459. setCtxStyle(stroke, width, dash, cap);
  2460. ctx.beginPath();
  2461. var x0, y0, x1, y1, pos1 = pos0 + (side == 0 || side == 3 ? -len : len);
  2462. if (ori == 0) {
  2463. y0 = pos0;
  2464. y1 = pos1;
  2465. }
  2466. else {
  2467. x0 = pos0;
  2468. x1 = pos1;
  2469. }
  2470. offs.forEach((off, i) => {
  2471. if (filts[i] == null)
  2472. { return; }
  2473. if (ori == 0)
  2474. { x0 = x1 = off; }
  2475. else
  2476. { y0 = y1 = off; }
  2477. ctx.moveTo(x0, y0);
  2478. ctx.lineTo(x1, y1);
  2479. });
  2480. ctx.stroke();
  2481. ctx.translate(-offset, -offset);
  2482. }
  2483. function axesCalc(cycleNum) {
  2484. // log("axesCalc()", arguments);
  2485. var converged = true;
  2486. axes.forEach((axis, i) => {
  2487. if (!axis.show)
  2488. { return; }
  2489. var scale = scales[axis.scale];
  2490. if (scale.min == null) {
  2491. if (axis._show) {
  2492. converged = false;
  2493. axis._show = false;
  2494. resetYSeries(false);
  2495. }
  2496. return;
  2497. }
  2498. else {
  2499. if (!axis._show) {
  2500. converged = false;
  2501. axis._show = true;
  2502. resetYSeries(false);
  2503. }
  2504. }
  2505. var side = axis.side;
  2506. var ori = side % 2;
  2507. var min = scale.min;
  2508. var max = scale.max; // // should this toggle them ._show = false
  2509. var ref = getIncrSpace(i, min, max, ori == 0 ? plotWidCss : plotHgtCss);
  2510. var _incr = ref[0];
  2511. var _space = ref[1];
  2512. if (_space == 0)
  2513. { return; }
  2514. // if we're using index positions, force first tick to match passed index
  2515. var forceMin = scale.distr == 2;
  2516. var _splits = axis._splits = axis.splits(self, i, min, max, _incr, _space, forceMin);
  2517. // tick labels
  2518. // BOO this assumes a specific data/series
  2519. var splits = scale.distr == 2 ? _splits.map(i => data0[i]) : _splits;
  2520. var incr = scale.distr == 2 ? data0[_splits[1]] - data0[_splits[0]] : _incr;
  2521. var values = axis._values = axis.values(self, axis.filter(self, splits, i, _space, incr), i, _space, incr);
  2522. // rotating of labels only supported on bottom x axis
  2523. axis._rotate = side == 2 ? axis.rotate(self, values, i, _space) : 0;
  2524. var oldSize = axis._size;
  2525. axis._size = ceil(axis.size(self, values, i, cycleNum));
  2526. if (oldSize != null && axis._size != oldSize) // ready && ?
  2527. { converged = false; }
  2528. });
  2529. return converged;
  2530. }
  2531. function paddingCalc(cycleNum) {
  2532. var converged = true;
  2533. padding.forEach((p, i) => {
  2534. var _p = p(self, i, sidesWithAxes, cycleNum);
  2535. if (_p != _padding[i])
  2536. { converged = false; }
  2537. _padding[i] = _p;
  2538. });
  2539. return converged;
  2540. }
  2541. function drawAxesGrid() {
  2542. axes.forEach((axis, i) => {
  2543. if (!axis.show || !axis._show)
  2544. { return; }
  2545. var scale = scales[axis.scale];
  2546. var side = axis.side;
  2547. var ori = side % 2;
  2548. var plotDim = ori == 0 ? plotWid : plotHgt;
  2549. var plotOff = ori == 0 ? plotLft : plotTop;
  2550. var axisGap = round(axis.gap * pxRatio);
  2551. var ticks = axis.ticks;
  2552. var tickSize = ticks.show ? round(ticks.size * pxRatio) : 0;
  2553. var ref = axis._found;
  2554. var _incr = ref[0];
  2555. var _space = ref[1];
  2556. var _splits = axis._splits;
  2557. // tick labels
  2558. // BOO this assumes a specific data/series
  2559. var splits = scale.distr == 2 ? _splits.map(i => data0[i]) : _splits;
  2560. var incr = scale.distr == 2 ? data0[_splits[1]] - data0[_splits[0]] : _incr;
  2561. // rotating of labels only supported on bottom x axis
  2562. var angle = axis._rotate * -PI/180;
  2563. var basePos = round(axis._pos * pxRatio);
  2564. var shiftAmt = tickSize + axisGap;
  2565. var shiftDir = ori == 0 && side == 0 || ori == 1 && side == 3 ? -1 : 1;
  2566. var finalPos = basePos + shiftAmt * shiftDir;
  2567. var y = ori == 0 ? finalPos : 0;
  2568. var x = ori == 1 ? finalPos : 0;
  2569. ctx.font = axis.font[0];
  2570. ctx.fillStyle = axis.stroke || hexBlack; // rgba?
  2571. ctx.textAlign = axis.align == 1 ? LEFT :
  2572. axis.align == 2 ? RIGHT :
  2573. angle > 0 ? LEFT :
  2574. angle < 0 ? RIGHT :
  2575. ori == 0 ? "center" : side == 3 ? RIGHT : LEFT;
  2576. ctx.textBaseline = angle ||
  2577. ori == 1 ? "middle" : side == 2 ? TOP : BOTTOM;
  2578. var lineHeight = axis.font[1] * lineMult;
  2579. var canOffs = _splits.map(val => round(getPos(val, scale, plotDim, plotOff)));
  2580. axis._values.forEach((val, i) => {
  2581. if (val == null)
  2582. { return; }
  2583. if (ori == 0)
  2584. { x = canOffs[i]; }
  2585. else
  2586. { y = canOffs[i]; }
  2587. (""+val).split(/\n/gm).forEach((text, j) => {
  2588. if (angle) {
  2589. ctx.save();
  2590. ctx.translate(x, y + j * lineHeight);
  2591. ctx.rotate(angle);
  2592. ctx.fillText(text, 0, 0);
  2593. ctx.restore();
  2594. }
  2595. else
  2596. { ctx.fillText(text, x, y + j * lineHeight); }
  2597. });
  2598. });
  2599. // axis label
  2600. if (axis.label) {
  2601. ctx.save();
  2602. var baseLpos = round(axis._lpos * pxRatio);
  2603. if (ori == 1) {
  2604. x = y = 0;
  2605. ctx.translate(
  2606. baseLpos,
  2607. round(plotTop + plotHgt / 2)
  2608. );
  2609. ctx.rotate((side == 3 ? -PI : PI) / 2);
  2610. }
  2611. else {
  2612. x = round(plotLft + plotWid / 2);
  2613. y = baseLpos;
  2614. }
  2615. ctx.font = axis.labelFont[0];
  2616. // ctx.fillStyle = axis.labelStroke || hexBlack; // rgba?
  2617. ctx.textAlign = "center";
  2618. ctx.textBaseline = side == 2 ? TOP : BOTTOM;
  2619. ctx.fillText(axis.label, x, y);
  2620. ctx.restore();
  2621. }
  2622. // ticks
  2623. if (ticks.show) {
  2624. drawOrthoLines(
  2625. canOffs,
  2626. ticks.filter(self, splits, i, _space, incr),
  2627. ori,
  2628. side,
  2629. basePos,
  2630. tickSize,
  2631. roundDec(ticks.width * pxRatio, 3),
  2632. ticks.stroke,
  2633. ticks.dash,
  2634. ticks.cap
  2635. );
  2636. }
  2637. // grid
  2638. var grid = axis.grid;
  2639. if (grid.show) {
  2640. drawOrthoLines(
  2641. canOffs,
  2642. grid.filter(self, splits, i, _space, incr),
  2643. ori,
  2644. ori == 0 ? 2 : 1,
  2645. ori == 0 ? plotTop : plotLft,
  2646. ori == 0 ? plotHgt : plotWid,
  2647. roundDec(grid.width * pxRatio, 3),
  2648. grid.stroke,
  2649. grid.dash,
  2650. grid.cap
  2651. );
  2652. }
  2653. });
  2654. fire("drawAxes");
  2655. }
  2656. function resetYSeries(minMax) {
  2657. // log("resetYSeries()", arguments);
  2658. series.forEach((s, i) => {
  2659. if (i > 0) {
  2660. s._paths = null;
  2661. if (minMax) {
  2662. s.min = null;
  2663. s.max = null;
  2664. }
  2665. }
  2666. });
  2667. }
  2668. var queuedCommit = false;
  2669. function commit() {
  2670. if (!queuedCommit) {
  2671. microTask(_commit);
  2672. queuedCommit = true;
  2673. }
  2674. }
  2675. function _commit() {
  2676. // log("_commit()", arguments);
  2677. if (shouldSetScales) {
  2678. setScales();
  2679. shouldSetScales = false;
  2680. }
  2681. if (shouldConvergeSize) {
  2682. convergeSize();
  2683. shouldConvergeSize = false;
  2684. }
  2685. if (shouldSetSize) {
  2686. setStylePx(under, LEFT, plotLftCss);
  2687. setStylePx(under, TOP, plotTopCss);
  2688. setStylePx(under, WIDTH, plotWidCss);
  2689. setStylePx(under, HEIGHT, plotHgtCss);
  2690. setStylePx(over, LEFT, plotLftCss);
  2691. setStylePx(over, TOP, plotTopCss);
  2692. setStylePx(over, WIDTH, plotWidCss);
  2693. setStylePx(over, HEIGHT, plotHgtCss);
  2694. setStylePx(wrap, WIDTH, fullWidCss);
  2695. setStylePx(wrap, HEIGHT, fullHgtCss);
  2696. can.width = round(fullWidCss * pxRatio);
  2697. can.height = round(fullHgtCss * pxRatio);
  2698. syncRect();
  2699. fire("setSize");
  2700. shouldSetSize = false;
  2701. }
  2702. // if (shouldSetSelect) {
  2703. // TODO: update .u-select metrics (if visible)
  2704. // setStylePx(selectDiv, TOP, select.top = 0);
  2705. // setStylePx(selectDiv, LEFT, select.left = 0);
  2706. // setStylePx(selectDiv, WIDTH, select.width = 0);
  2707. // setStylePx(selectDiv, HEIGHT, select.height = 0);
  2708. // shouldSetSelect = false;
  2709. // }
  2710. if ( cursor.show && shouldSetCursor) {
  2711. updateCursor();
  2712. shouldSetCursor = false;
  2713. }
  2714. // if (FEAT_LEGEND && legend.show && legend.live && shouldSetLegend) {}
  2715. if (fullWidCss > 0 && fullHgtCss > 0) {
  2716. ctx.clearRect(0, 0, can.width, can.height);
  2717. fire("drawClear");
  2718. drawOrder.forEach(fn => fn());
  2719. fire("draw");
  2720. }
  2721. if (!ready) {
  2722. ready = true;
  2723. self.status = 1;
  2724. fire("ready");
  2725. }
  2726. viaAutoScaleX = false;
  2727. queuedCommit = false;
  2728. }
  2729. self.redraw = rebuildPaths => {
  2730. if (rebuildPaths !== false)
  2731. { _setScale(xScaleKey, scaleX.min, scaleX.max); }
  2732. else
  2733. { commit(); }
  2734. };
  2735. // redraw() => setScale('x', scales.x.min, scales.x.max);
  2736. // explicit, never re-ranged (is this actually true? for x and y)
  2737. function setScale(key, opts) {
  2738. var sc = scales[key];
  2739. if (sc.from == null) {
  2740. if (dataLen == 0) {
  2741. var minMax = sc.range(self, opts.min, opts.max, key);
  2742. opts.min = minMax[0];
  2743. opts.max = minMax[1];
  2744. }
  2745. if (opts.min > opts.max) {
  2746. var _min = opts.min;
  2747. opts.min = opts.max;
  2748. opts.max = _min;
  2749. }
  2750. if (dataLen > 1 && opts.min != null && opts.max != null && opts.max - opts.min < 1e-16)
  2751. { return; }
  2752. if (key == xScaleKey) {
  2753. if (sc.distr == 2 && dataLen > 0) {
  2754. opts.min = closestIdx(opts.min, data[0]);
  2755. opts.max = closestIdx(opts.max, data[0]);
  2756. }
  2757. }
  2758. // log("setScale()", arguments);
  2759. pendScales[key] = opts;
  2760. shouldSetScales = true;
  2761. commit();
  2762. }
  2763. }
  2764. self.setScale = setScale;
  2765. // INTERACTION
  2766. var xCursor;
  2767. var yCursor;
  2768. var vCursor;
  2769. var hCursor;
  2770. // starting position before cursor.move
  2771. var rawMouseLeft0;
  2772. var rawMouseTop0;
  2773. // starting position
  2774. var mouseLeft0;
  2775. var mouseTop0;
  2776. // current position before cursor.move
  2777. var rawMouseLeft1;
  2778. var rawMouseTop1;
  2779. // current position
  2780. var mouseLeft1;
  2781. var mouseTop1;
  2782. var dragging = false;
  2783. var drag = cursor.drag;
  2784. var dragX = drag.x;
  2785. var dragY = drag.y;
  2786. if ( cursor.show) {
  2787. if (cursor.x)
  2788. { xCursor = placeDiv(CURSOR_X, over); }
  2789. if (cursor.y)
  2790. { yCursor = placeDiv(CURSOR_Y, over); }
  2791. if (scaleX.ori == 0) {
  2792. vCursor = xCursor;
  2793. hCursor = yCursor;
  2794. }
  2795. else {
  2796. vCursor = yCursor;
  2797. hCursor = xCursor;
  2798. }
  2799. mouseLeft1 = cursor.left;
  2800. mouseTop1 = cursor.top;
  2801. }
  2802. var select = self.select = assign({
  2803. show: true,
  2804. over: true,
  2805. left: 0,
  2806. width: 0,
  2807. top: 0,
  2808. height: 0,
  2809. }, opts.select);
  2810. var selectDiv = select.show ? placeDiv(SELECT, select.over ? over : under) : null;
  2811. function setSelect(opts, _fire) {
  2812. if (select.show) {
  2813. for (var prop in opts)
  2814. { setStylePx(selectDiv, prop, select[prop] = opts[prop]); }
  2815. _fire !== false && fire("setSelect");
  2816. }
  2817. }
  2818. self.setSelect = setSelect;
  2819. function toggleDOM(i, onOff) {
  2820. var s = series[i];
  2821. var label = showLegend ? legendRows[i][0].parentNode : null;
  2822. if (s.show)
  2823. { label && remClass(label, OFF); }
  2824. else {
  2825. label && addClass(label, OFF);
  2826. cursorPts.length > 1 && trans(cursorPts[i], -10, -10, plotWidCss, plotHgtCss);
  2827. }
  2828. }
  2829. function _setScale(key, min, max) {
  2830. setScale(key, {min: min, max: max});
  2831. }
  2832. function setSeries(i, opts, pub) {
  2833. // log("setSeries()", arguments);
  2834. var s = series[i];
  2835. // will this cause redundant commit() if both show and focus are set?
  2836. if (opts.focus != null)
  2837. { setFocus(i); }
  2838. if (opts.show != null) {
  2839. s.show = opts.show;
  2840. toggleDOM(i, opts.show);
  2841. _setScale(s.scale, null, null);
  2842. commit();
  2843. }
  2844. fire("setSeries", i, opts);
  2845. pub && sync.pub("setSeries", self, i, opts);
  2846. }
  2847. self.setSeries = setSeries;
  2848. function _alpha(i, value) {
  2849. series[i].alpha = value;
  2850. if ( cursor.show && cursorPts[i])
  2851. { cursorPts[i].style.opacity = value; }
  2852. if ( showLegend && legendRows[i])
  2853. { legendRows[i][0].parentNode.style.opacity = value; }
  2854. }
  2855. function _setAlpha(i, value) {
  2856. _alpha(i, value);
  2857. }
  2858. // y-distance
  2859. var closestDist;
  2860. var closestSeries;
  2861. var focusedSeries;
  2862. var FOCUS_TRUE = {focus: true};
  2863. var FOCUS_FALSE = {focus: false};
  2864. function setFocus(i) {
  2865. if (i != focusedSeries) {
  2866. // log("setFocus()", arguments);
  2867. series.forEach((s, i2) => {
  2868. _setAlpha(i2, i == null || i2 == 0 || i2 == i ? 1 : focus.alpha);
  2869. });
  2870. focusedSeries = i;
  2871. commit();
  2872. }
  2873. }
  2874. if (showLegend && cursorFocus) {
  2875. on(mouseleave, legendEl, e => {
  2876. if (cursor._lock)
  2877. { return; }
  2878. setSeries(null, FOCUS_FALSE, syncOpts.setSeries);
  2879. updateCursor();
  2880. });
  2881. }
  2882. function posToVal(pos, scale) {
  2883. var sc = scales[scale];
  2884. var dim = plotWidCss;
  2885. if (sc.ori == 1) {
  2886. dim = plotHgtCss;
  2887. pos = dim - pos;
  2888. }
  2889. if (sc.dir == -1)
  2890. { pos = dim - pos; }
  2891. var _min = sc.min,
  2892. _max = sc.max,
  2893. pct = pos / dim;
  2894. if (sc.distr == 3) {
  2895. _min = log10(_min);
  2896. _max = log10(_max);
  2897. return pow(10, _min + (_max - _min) * pct);
  2898. }
  2899. else
  2900. { return _min + (_max - _min) * pct; }
  2901. }
  2902. function closestIdxFromXpos(pos) {
  2903. var v = posToVal(pos, xScaleKey);
  2904. return closestIdx(v, data[0], i0, i1);
  2905. }
  2906. self.valToIdx = val => closestIdx(val, data[0]);
  2907. self.posToIdx = closestIdxFromXpos;
  2908. self.posToVal = posToVal;
  2909. self.valToPos = (val, scale, can) => (
  2910. scales[scale].ori == 0 ?
  2911. getHPos(val, scales[scale],
  2912. can ? plotWid : plotWidCss,
  2913. can ? plotLft : 0
  2914. ) :
  2915. getVPos(val, scales[scale],
  2916. can ? plotHgt : plotHgtCss,
  2917. can ? plotTop : 0
  2918. )
  2919. );
  2920. // defers calling expensive functions
  2921. function batch(fn) {
  2922. fn(self);
  2923. commit();
  2924. }
  2925. self.batch = batch;
  2926. (self.setCursor = opts => {
  2927. mouseLeft1 = opts.left;
  2928. mouseTop1 = opts.top;
  2929. // assign(cursor, opts);
  2930. updateCursor();
  2931. });
  2932. function setSelH(off, dim) {
  2933. setStylePx(selectDiv, LEFT, select.left = off);
  2934. setStylePx(selectDiv, WIDTH, select.width = dim);
  2935. }
  2936. function setSelV(off, dim) {
  2937. setStylePx(selectDiv, TOP, select.top = off);
  2938. setStylePx(selectDiv, HEIGHT, select.height = dim);
  2939. }
  2940. var setSelX = scaleX.ori == 0 ? setSelH : setSelV;
  2941. var setSelY = scaleX.ori == 1 ? setSelH : setSelV;
  2942. function updateCursor(ts, src) {
  2943. var assign;
  2944. // ts == null && log("updateCursor()", arguments);
  2945. rawMouseLeft1 = mouseLeft1;
  2946. rawMouseTop1 = mouseTop1;
  2947. (assign = cursor.move(self, mouseLeft1, mouseTop1), mouseLeft1 = assign[0], mouseTop1 = assign[1]);
  2948. if (cursor.show) {
  2949. vCursor && trans(vCursor, round(mouseLeft1), 0, plotWidCss, plotHgtCss);
  2950. hCursor && trans(hCursor, 0, round(mouseTop1), plotWidCss, plotHgtCss);
  2951. }
  2952. var idx;
  2953. // when zooming to an x scale range between datapoints the binary search
  2954. // for nearest min/max indices results in this condition. cheap hack :D
  2955. var noDataInRange = i0 > i1;
  2956. closestDist = inf;
  2957. // TODO: extract
  2958. var xDim = scaleX.ori == 0 ? plotWidCss : plotHgtCss;
  2959. var yDim = scaleX.ori == 1 ? plotWidCss : plotHgtCss;
  2960. // if cursor hidden, hide points & clear legend vals
  2961. if (mouseLeft1 < 0 || dataLen == 0 || noDataInRange) {
  2962. idx = null;
  2963. for (var i = 0; i < series.length; i++) {
  2964. if (i > 0) {
  2965. cursorPts.length > 1 && trans(cursorPts[i], -10, -10, plotWidCss, plotHgtCss);
  2966. }
  2967. if (showLegend && legend.live) {
  2968. if (i == 0 && multiValLegend)
  2969. { continue; }
  2970. for (var j = 0; j < legendRows[i].length; j++)
  2971. { legendRows[i][j].firstChild.nodeValue = '--'; }
  2972. }
  2973. }
  2974. if (cursorFocus)
  2975. { setSeries(null, FOCUS_TRUE, syncOpts.setSeries); }
  2976. }
  2977. else {
  2978. // let pctY = 1 - (y / rect.height);
  2979. var mouseXPos = scaleX.ori == 0 ? mouseLeft1 : mouseTop1;
  2980. var valAtPosX = posToVal(mouseXPos, xScaleKey);
  2981. idx = closestIdx(valAtPosX, data[0], i0, i1);
  2982. var xPos = incrRoundUp(valToPosX(data[0][idx], scaleX, xDim, 0), 0.5);
  2983. for (var i$1 = 0; i$1 < series.length; i$1++) {
  2984. var s = series[i$1];
  2985. var idx2 = cursor.dataIdx(self, i$1, idx, valAtPosX);
  2986. var xPos2 = idx2 == idx ? xPos : incrRoundUp(valToPosX(data[0][idx2], scaleX, xDim, 0), 0.5);
  2987. if (i$1 > 0 && s.show) {
  2988. var valAtIdx = data[i$1][idx2];
  2989. var yPos = valAtIdx == null ? -10 : incrRoundUp(valToPosY(valAtIdx, scales[s.scale], yDim, 0), 0.5);
  2990. if (yPos > 0) {
  2991. var dist = abs(yPos - mouseTop1);
  2992. if (dist <= closestDist) {
  2993. closestDist = dist;
  2994. closestSeries = i$1;
  2995. }
  2996. }
  2997. var hPos = (void 0), vPos = (void 0);
  2998. if (scaleX.ori == 0) {
  2999. hPos = xPos2;
  3000. vPos = yPos;
  3001. }
  3002. else {
  3003. hPos = yPos;
  3004. vPos = xPos2;
  3005. }
  3006. cursorPts.length > 1 && trans(cursorPts[i$1], hPos, vPos, plotWidCss, plotHgtCss);
  3007. }
  3008. if (showLegend && legend.live) {
  3009. if ((idx2 == cursor.idx && !shouldSetLegend) || i$1 == 0 && multiValLegend)
  3010. { continue; }
  3011. var src$1 = i$1 == 0 && xScaleDistr == 2 ? data0 : data[i$1];
  3012. var vals = multiValLegend ? s.values(self, i$1, idx2) : {_: s.value(self, src$1[idx2], i$1, idx2)};
  3013. var j$1 = 0;
  3014. for (var k in vals)
  3015. { legendRows[i$1][j$1++].firstChild.nodeValue = vals[k]; }
  3016. }
  3017. }
  3018. shouldSetLegend = false;
  3019. }
  3020. // nit: cursor.drag.setSelect is assumed always true
  3021. if (select.show && dragging) {
  3022. if (src != null) {
  3023. var ref = syncOpts.scales;
  3024. var xKey = ref[0];
  3025. var yKey = ref[1];
  3026. // match the dragX/dragY implicitness/explicitness of src
  3027. var sdrag = src.cursor.drag;
  3028. dragX = sdrag._x;
  3029. dragY = sdrag._y;
  3030. var ref$1 = src.select;
  3031. var left = ref$1.left;
  3032. var top = ref$1.top;
  3033. var width = ref$1.width;
  3034. var height = ref$1.height;
  3035. var sori = src.scales[xKey].ori;
  3036. var sPosToVal = src.posToVal;
  3037. var sOff, sDim, sc, a, b;
  3038. if (xKey) {
  3039. if (sori == 0) {
  3040. sOff = left;
  3041. sDim = width;
  3042. }
  3043. else {
  3044. sOff = top;
  3045. sDim = height;
  3046. }
  3047. sc = scales[xKey];
  3048. a = valToPosX(sPosToVal(sOff, xKey), sc, xDim, 0);
  3049. b = valToPosX(sPosToVal(sOff + sDim, xKey), sc, xDim, 0);
  3050. setSelX(min(a,b), abs(b-a));
  3051. if (!yKey)
  3052. { setSelY(0, yDim); }
  3053. }
  3054. if (yKey) {
  3055. if (sori == 1) {
  3056. sOff = left;
  3057. sDim = width;
  3058. }
  3059. else {
  3060. sOff = top;
  3061. sDim = height;
  3062. }
  3063. sc = scales[yKey];
  3064. a = valToPosY(sPosToVal(sOff, yKey), sc, yDim, 0);
  3065. b = valToPosY(sPosToVal(sOff + sDim, yKey), sc, yDim, 0);
  3066. setSelY(min(a,b), abs(b-a));
  3067. if (!xKey)
  3068. { setSelX(0, xDim); }
  3069. }
  3070. }
  3071. else {
  3072. var rawDX = abs(rawMouseLeft1 - rawMouseLeft0);
  3073. var rawDY = abs(rawMouseTop1 - rawMouseTop0);
  3074. if (scaleX.ori == 1) {
  3075. var _rawDX = rawDX;
  3076. rawDX = rawDY;
  3077. rawDY = _rawDX;
  3078. }
  3079. dragX = drag.x && rawDX >= drag.dist;
  3080. dragY = drag.y && rawDY >= drag.dist;
  3081. var uni = drag.uni;
  3082. if (uni != null) {
  3083. // only calc drag status if they pass the dist thresh
  3084. if (dragX && dragY) {
  3085. dragX = rawDX >= uni;
  3086. dragY = rawDY >= uni;
  3087. // force unidirectionality when both are under uni limit
  3088. if (!dragX && !dragY) {
  3089. if (rawDY > rawDX)
  3090. { dragY = true; }
  3091. else
  3092. { dragX = true; }
  3093. }
  3094. }
  3095. }
  3096. else if (drag.x && drag.y && (dragX || dragY))
  3097. // if omni with no uni then both dragX / dragY should be true if either is true
  3098. { dragX = dragY = true; }
  3099. var p0, p1;
  3100. if (dragX) {
  3101. if (scaleX.ori == 0) {
  3102. p0 = mouseLeft0;
  3103. p1 = mouseLeft1;
  3104. }
  3105. else {
  3106. p0 = mouseTop0;
  3107. p1 = mouseTop1;
  3108. }
  3109. setSelX(min(p0, p1), abs(p1 - p0));
  3110. if (!dragY)
  3111. { setSelY(0, yDim); }
  3112. }
  3113. if (dragY) {
  3114. if (scaleX.ori == 1) {
  3115. p0 = mouseLeft0;
  3116. p1 = mouseLeft1;
  3117. }
  3118. else {
  3119. p0 = mouseTop0;
  3120. p1 = mouseTop1;
  3121. }
  3122. setSelY(min(p0, p1), abs(p1 - p0));
  3123. if (!dragX)
  3124. { setSelX(0, xDim); }
  3125. }
  3126. // the drag didn't pass the dist requirement
  3127. if (!dragX && !dragY) {
  3128. setSelX(0, 0);
  3129. setSelY(0, 0);
  3130. }
  3131. }
  3132. }
  3133. cursor.idx = idx;
  3134. cursor.left = mouseLeft1;
  3135. cursor.top = mouseTop1;
  3136. drag._x = dragX;
  3137. drag._y = dragY;
  3138. // if ts is present, means we're implicitly syncing own cursor
  3139. if (ts != null) {
  3140. // this is not technically a "mousemove" event, since it's debounced, rename to setCursor?
  3141. // since this is internal, we can tweak it later
  3142. sync.pub(mousemove, self, mouseLeft1, mouseTop1, xDim, yDim, idx);
  3143. if (cursorFocus) {
  3144. var o = syncOpts.setSeries;
  3145. var p = focus.prox;
  3146. if (focusedSeries == null) {
  3147. if (closestDist <= p)
  3148. { setSeries(closestSeries, FOCUS_TRUE, o); }
  3149. }
  3150. else {
  3151. if (closestDist > p)
  3152. { setSeries(null, FOCUS_TRUE, o); }
  3153. else if (closestSeries != focusedSeries)
  3154. { setSeries(closestSeries, FOCUS_TRUE, o); }
  3155. }
  3156. }
  3157. }
  3158. ready && fire("setCursor");
  3159. }
  3160. var rect = null;
  3161. function syncRect() {
  3162. rect = over.getBoundingClientRect();
  3163. }
  3164. function mouseMove(e, src, _l, _t, _w, _h, _i) {
  3165. if (cursor._lock)
  3166. { return; }
  3167. cacheMouse(e, src, _l, _t, _w, _h, _i, false, e != null);
  3168. if (e != null)
  3169. { updateCursor(1); }
  3170. else
  3171. { updateCursor(null, src); }
  3172. }
  3173. function cacheMouse(e, src, _l, _t, _w, _h, _i, initial, snap) {
  3174. var assign;
  3175. if (e != null) {
  3176. _l = e.clientX - rect.left;
  3177. _t = e.clientY - rect.top;
  3178. }
  3179. else {
  3180. if (_l < 0 || _t < 0) {
  3181. mouseLeft1 = -10;
  3182. mouseTop1 = -10;
  3183. return;
  3184. }
  3185. var xDim = plotWidCss,
  3186. yDim = plotHgtCss,
  3187. _xDim = _w,
  3188. _yDim = _h,
  3189. _xPos = _l,
  3190. _yPos = _t;
  3191. if (scaleX.ori == 1) {
  3192. xDim = plotHgtCss;
  3193. yDim = plotWidCss;
  3194. }
  3195. var ref = syncOpts.scales;
  3196. var xKey = ref[0];
  3197. var yKey = ref[1];
  3198. if (src.scales[xKey].ori == 1) {
  3199. _xDim = _h;
  3200. _yDim = _w;
  3201. _xPos = _t;
  3202. _yPos = _l;
  3203. }
  3204. if (xKey != null)
  3205. { _l = getPos(src.posToVal(_xPos, xKey), scales[xKey], xDim, 0); }
  3206. else
  3207. { _l = xDim * (_xPos/_xDim); }
  3208. if (yKey != null)
  3209. { _t = getPos(src.posToVal(_yPos, yKey), scales[yKey], yDim, 0); }
  3210. else
  3211. { _t = yDim * (_yPos/_yDim); }
  3212. if (scaleX.ori == 1) {
  3213. var _l$1 = _l;
  3214. _l = _t;
  3215. _t = _l$1;
  3216. }
  3217. }
  3218. if (snap) {
  3219. if (_l <= 1 || _l >= plotWidCss - 1)
  3220. { _l = incrRound(_l, plotWidCss); }
  3221. if (_t <= 1 || _t >= plotHgtCss - 1)
  3222. { _t = incrRound(_t, plotHgtCss); }
  3223. }
  3224. if (initial) {
  3225. rawMouseLeft0 = _l;
  3226. rawMouseTop0 = _t;
  3227. (assign = cursor.move(self, _l, _t), mouseLeft0 = assign[0], mouseTop0 = assign[1]);
  3228. }
  3229. else {
  3230. mouseLeft1 = _l;
  3231. mouseTop1 = _t;
  3232. }
  3233. }
  3234. function hideSelect() {
  3235. setSelect({
  3236. width: 0,
  3237. height: 0,
  3238. }, false);
  3239. }
  3240. function mouseDown(e, src, _l, _t, _w, _h, _i) {
  3241. dragging = true;
  3242. dragX = dragY = drag._x = drag._y = false;
  3243. cacheMouse(e, src, _l, _t, _w, _h, _i, true, false);
  3244. if (e != null) {
  3245. onMouse(mouseup, doc, mouseUp);
  3246. sync.pub(mousedown, self, mouseLeft0, mouseTop0, plotWidCss, plotHgtCss, null);
  3247. }
  3248. }
  3249. function mouseUp(e, src, _l, _t, _w, _h, _i) {
  3250. dragging = drag._x = drag._y = false;
  3251. cacheMouse(e, src, _l, _t, _w, _h, _i, false, true);
  3252. var left = select.left;
  3253. var top = select.top;
  3254. var width = select.width;
  3255. var height = select.height;
  3256. var hasSelect = width > 0 || height > 0;
  3257. hasSelect && setSelect(select);
  3258. if (drag.setScale && hasSelect) {
  3259. // if (syncKey != null) {
  3260. // dragX = drag.x;
  3261. // dragY = drag.y;
  3262. // }
  3263. var xOff = left,
  3264. xDim = width,
  3265. yOff = top,
  3266. yDim = height;
  3267. if (scaleX.ori == 1) {
  3268. xOff = top,
  3269. xDim = height,
  3270. yOff = left,
  3271. yDim = width;
  3272. }
  3273. if (dragX) {
  3274. _setScale(xScaleKey,
  3275. posToVal(xOff, xScaleKey),
  3276. posToVal(xOff + xDim, xScaleKey)
  3277. );
  3278. }
  3279. if (dragY) {
  3280. for (var k in scales) {
  3281. var sc = scales[k];
  3282. if (k != xScaleKey && sc.from == null && sc.min != inf) {
  3283. _setScale(k,
  3284. posToVal(yOff + yDim, k),
  3285. posToVal(yOff, k)
  3286. );
  3287. }
  3288. }
  3289. }
  3290. hideSelect();
  3291. }
  3292. else if (cursor.lock) {
  3293. cursor._lock = !cursor._lock;
  3294. if (!cursor._lock)
  3295. { updateCursor(); }
  3296. }
  3297. if (e != null) {
  3298. offMouse(mouseup, doc);
  3299. sync.pub(mouseup, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, null);
  3300. }
  3301. }
  3302. function mouseLeave(e, src, _l, _t, _w, _h, _i) {
  3303. if (!cursor._lock) {
  3304. var _dragging = dragging;
  3305. if (dragging) {
  3306. // handle case when mousemove aren't fired all the way to edges by browser
  3307. var snapH = true;
  3308. var snapV = true;
  3309. var snapProx = 10;
  3310. var dragH, dragV;
  3311. if (scaleX.ori == 0) {
  3312. dragH = dragX;
  3313. dragV = dragY;
  3314. }
  3315. else {
  3316. dragH = dragY;
  3317. dragV = dragX;
  3318. }
  3319. if (dragH && dragV) {
  3320. // maybe omni corner snap
  3321. snapH = mouseLeft1 <= snapProx || mouseLeft1 >= plotWidCss - snapProx;
  3322. snapV = mouseTop1 <= snapProx || mouseTop1 >= plotHgtCss - snapProx;
  3323. }
  3324. if (dragH && snapH)
  3325. { mouseLeft1 = mouseLeft1 < mouseLeft0 ? 0 : plotWidCss; }
  3326. if (dragV && snapV)
  3327. { mouseTop1 = mouseTop1 < mouseTop0 ? 0 : plotHgtCss; }
  3328. updateCursor(1);
  3329. dragging = false;
  3330. }
  3331. mouseLeft1 = -10;
  3332. mouseTop1 = -10;
  3333. // passing a non-null timestamp to force sync/mousemove event
  3334. updateCursor(1);
  3335. if (_dragging)
  3336. { dragging = _dragging; }
  3337. }
  3338. }
  3339. function dblClick(e, src, _l, _t, _w, _h, _i) {
  3340. autoScaleX();
  3341. hideSelect();
  3342. if (e != null)
  3343. { sync.pub(dblclick, self, mouseLeft1, mouseTop1, plotWidCss, plotHgtCss, null); }
  3344. }
  3345. // internal pub/sub
  3346. var events = {};
  3347. events.mousedown = mouseDown;
  3348. events.mousemove = mouseMove;
  3349. events.mouseup = mouseUp;
  3350. events.dblclick = dblClick;
  3351. events["setSeries"] = (e, src, idx, opts) => {
  3352. setSeries(idx, opts);
  3353. };
  3354. var deb;
  3355. if ( cursor.show) {
  3356. onMouse(mousedown, over, mouseDown);
  3357. onMouse(mousemove, over, mouseMove);
  3358. onMouse(mouseenter, over, syncRect);
  3359. onMouse(mouseleave, over, mouseLeave);
  3360. onMouse(dblclick, over, dblClick);
  3361. deb = debounce(syncRect, 100);
  3362. on(resize, win, deb);
  3363. on(scroll, win, deb);
  3364. self.syncRect = syncRect;
  3365. }
  3366. // external on/off
  3367. var hooks = self.hooks = opts.hooks || {};
  3368. function fire(evName, a1, a2) {
  3369. if (evName in hooks) {
  3370. hooks[evName].forEach(fn => {
  3371. fn.call(null, self, a1, a2);
  3372. });
  3373. }
  3374. }
  3375. (opts.plugins || []).forEach(p => {
  3376. for (var evName in p.hooks)
  3377. { hooks[evName] = (hooks[evName] || []).concat(p.hooks[evName]); }
  3378. });
  3379. var syncOpts = assign({
  3380. key: null,
  3381. setSeries: false,
  3382. scales: [xScaleKey, null]
  3383. }, cursor.sync);
  3384. var syncKey = syncOpts.key;
  3385. var sync = (syncKey != null ? (syncs[syncKey] = syncs[syncKey] || _sync()) : _sync());
  3386. sync.sub(self);
  3387. function pub(type, src, x, y, w, h, i) {
  3388. events[type](null, src, x, y, w, h, i);
  3389. }
  3390. (self.pub = pub);
  3391. function destroy() {
  3392. sync.unsub(self);
  3393. off(resize, win, deb);
  3394. off(scroll, win, deb);
  3395. root.remove();
  3396. fire("destroy");
  3397. }
  3398. self.destroy = destroy;
  3399. function _init() {
  3400. fire("init", opts, data);
  3401. setData(data || opts.data, false);
  3402. if (pendScales[xScaleKey])
  3403. { setScale(xScaleKey, pendScales[xScaleKey]); }
  3404. else
  3405. { autoScaleX(); }
  3406. _setSize(opts.width, opts.height);
  3407. setSelect(select, false);
  3408. }
  3409. if (then) {
  3410. if (then instanceof HTMLElement) {
  3411. then.appendChild(root);
  3412. _init();
  3413. }
  3414. else
  3415. { then(self, _init); }
  3416. }
  3417. else
  3418. { _init(); }
  3419. return self;
  3420. }
  3421. uPlot.assign = assign;
  3422. uPlot.fmtNum = fmtNum;
  3423. uPlot.rangeNum = rangeNum;
  3424. uPlot.rangeLog = rangeLog;
  3425. uPlot.orient = orient;
  3426. {
  3427. uPlot.join = join;
  3428. }
  3429. {
  3430. uPlot.fmtDate = fmtDate;
  3431. uPlot.tzDate = tzDate;
  3432. }
  3433. {
  3434. uPlot.addGap = addGap;
  3435. uPlot.clipGaps = clipGaps;
  3436. var paths = uPlot.paths = {};
  3437. (paths.linear = linear);
  3438. (paths.spline = spline);
  3439. (paths.stepped = stepped);
  3440. (paths.bars = bars);
  3441. }
  3442. return uPlot;
  3443. }());