You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

uPlot.iife.js 138KB

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