@@ -8,11 +8,11 @@ typeof define === 'function' && define.amd ? define(['exports'], factory) :
88var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
99/** @summary version id
1010 * @desc For the JSROOT release the string in format 'major.minor.patch' like '7.0.0' */
11- const version_id = '7.8.x ',
11+ const version_id = '7.8.2 ',
1212
1313/** @summary version date
1414 * @desc Release date in format day/month/year like '14/04/2022' */
15- version_date = '12 /03/2025',
15+ version_date = '26 /03/2025',
1616
1717/** @summary version id and date
1818 * @desc Produced by concatenation of {@link version_id} and {@link version_date}
@@ -106,7 +106,7 @@ if ((typeof document !== 'undefined') && (typeof window !== 'undefined') && (typ
106106 browser.isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0;
107107 browser.isChrome = !!window.chrome;
108108 browser.isChromeHeadless = navigator.userAgent.indexOf('HeadlessChrome') >= 0;
109- browser.chromeVersion = (browser.isChrome || browser.isChromeHeadless) ? parseInt(navigator.userAgent.match(/Chrom(?:e|ium)\/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/)[1]) : 0;
109+ browser.chromeVersion = (browser.isChrome || browser.isChromeHeadless) ? (navigator.userAgent.indexOf('Chrom') > 0 ? parseInt(navigator.userAgent.match(/Chrom(?:e|ium)\/([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/)[1]) : 134 ) : 0;
110110 browser.isWin = navigator.userAgent.indexOf('Windows') >= 0;
111111 }
112112 browser.android = /android/i.test(navigator.userAgent);
@@ -302,7 +302,15 @@ settings = {
302302 * @desc Some http server has limitations for number of bytes ranges therefore let change maximal number via setting
303303 * @default 200 */
304304 MaxRanges: 200,
305- /** @summary Configure xhr.withCredentials = true when submitting http requests from JSROOT */
305+ /** @summary File read timeout in ms
306+ * @desc Configures timeout for each http operation for reading ROOT files
307+ * @default 0 */
308+ FilesTimeout: 0,
309+ /** @summary Default remap object for files loading
310+ * @desc Allows to retry files reading if original URL fails
311+ * @private */
312+ FilesRemap: { 'https://root.cern/': 'https://root-eos.web.cern.ch/' },
313+ /** @summary Configure xhr.withCredentials = true when submitting http requests from JSROOT */
306314 WithCredentials: false,
307315 /** @summary Skip streamer infos from the GUI */
308316 SkipStreamerInfos: false,
@@ -1579,7 +1587,7 @@ function getMethods(typename, obj) {
15791587 };
15801588 }
15811589
1582- if ((typename.indexOf(clTF1) === 0) || (typename === clTF2)) {
1590+ if ((typename.indexOf(clTF1) === 0) || (typename === clTF2) || (typename === clTF3) ) {
15831591 m.addFormula = function(obj) {
15841592 if (!obj) return;
15851593 if (this.formulas === undefined) this.formulas = [];
@@ -100246,6 +100254,7 @@ class TFile {
100246100254 this.fStreamers = 0;
100247100255 this.fStreamerInfos = null;
100248100256 this.fFileName = '';
100257+ this.fTimeout = settings.FilesTimeout ?? 0;
100249100258 this.fStreamers = [];
100250100259 this.fBasicTypes = {}; // custom basic types, in most case enumerations
100251100260
@@ -100271,10 +100280,35 @@ class TFile {
100271100280 this.fAcceptRanges = false;
100272100281 }
100273100282
100283+ if (isNodeJs())
100284+ this.fUseStampPar = false;
100285+
100274100286 const pos = Math.max(this.fURL.lastIndexOf('/'), this.fURL.lastIndexOf('\\'));
100275100287 this.fFileName = pos >= 0 ? this.fURL.slice(pos + 1) : this.fURL;
100276100288 }
100277100289
100290+ /** @summary Set timeout for File instance
100291+ * @desc Timeout used when submitting http requests to the server */
100292+ setTimeout(v) {
100293+ this.fTimeout = v;
100294+ }
100295+
100296+ /** @summary Assign remap for web servers
100297+ * @desc Allows to specify fallback server if main server fails
100298+ * @param {Object} remap - looks like { 'https://original.server/': 'https://fallback.server/' } */
100299+ assignRemap(remap) {
100300+ if (!remap && !isObject(remap))
100301+ return;
100302+
100303+ for (const key in remap) {
100304+ if (this.fURL.indexOf(key) === 0) {
100305+ this.fURL2 = remap[key] + this.fURL.slice(key.length);
100306+ if (!this.fTimeout)
100307+ this.fTimeout = 10000;
100308+ }
100309+ }
100310+ }
100311+
100278100312 /** @summary Assign BufferArray with file contentOpen file
100279100313 * @private */
100280100314 assignFileContent(bufArray) {
@@ -100302,15 +100336,23 @@ class TFile {
100302100336 blobs = [], // array of requested segments
100303100337 promise = new Promise((resolve, reject) => { resolveFunc = resolve; rejectFunc = reject; });
100304100338
100305- let fileurl = file.fURL,
100306- first = 0, last = 0,
100339+ let fileurl, first = 0, last = 0,
100307100340 // eslint-disable-next-line prefer-const
100308100341 read_callback, first_req,
100309100342 first_block_retry = false;
100310100343
100311- if (isStr(filename) && filename) {
100312- const pos = fileurl.lastIndexOf('/');
100313- fileurl = (pos < 0) ? filename : fileurl.slice(0, pos + 1) + filename;
100344+ function setFileUrl(use_second) {
100345+ if (use_second) {
100346+ console.log('Failure - try to repait with URL2', file.fURL2);
100347+ file.fURL = file.fURL2;
100348+ delete file.fURL2;
100349+ }
100350+
100351+ fileurl = file.fURL;
100352+ if (isStr(filename) && filename) {
100353+ const pos = fileurl.lastIndexOf('/');
100354+ fileurl = (pos < 0) ? filename : fileurl.slice(0, pos + 1) + filename;
100355+ }
100314100356 }
100315100357
100316100358 function send_new_request(increment) {
@@ -100342,6 +100384,9 @@ class TFile {
100342100384 xhr.expected_size = Math.max(Math.round(1.1 * totalsz), totalsz + 200); // 200 if offset for the potential gzip
100343100385 }
100344100386
100387+ if (file.fTimeout)
100388+ xhr.timeout = file.fTimeout;
100389+
100345100390 if (isFunc(progress_callback) && isFunc(xhr.addEventListener)) {
100346100391 let sum1 = 0, sum2 = 0, sum_total = 0;
100347100392 for (let n = 1; n < place.length; n += 2) {
@@ -100381,6 +100426,10 @@ class TFile {
100381100426 file.fUseStampPar = false;
100382100427 return send_new_request();
100383100428 }
100429+ if (file.fURL2) {
100430+ setFileUrl(true);
100431+ return send_new_request();
100432+ }
100384100433 if (file.fAcceptRanges) {
100385100434 file.fAcceptRanges = false;
100386100435 first_block_retry = true;
@@ -100415,9 +100464,13 @@ class TFile {
100415100464 }
100416100465
100417100466 if (!res) {
100467+ if (file.fURL2) {
100468+ setFileUrl(true);
100469+ return send_new_request();
100470+ }
100471+
100418100472 if ((first === 0) && (last > 2) && (file.fMaxRanges > 1)) {
100419100473 // server return no response with multi request - try to decrease ranges count or fail
100420-
100421100474 if (last / 2 > 200)
100422100475 file.fMaxRanges = 200;
100423100476 else if (last / 2 > 50)
@@ -100433,7 +100486,7 @@ class TFile {
100433100486 return send_new_request();
100434100487 }
100435100488
100436- return rejectFunc(Error(' Fail to read with several ranges' ));
100489+ return rejectFunc(Error(` Fail to read with ${last/2} ranges` ));
100437100490 }
100438100491
100439100492 // if only single segment requested, return result as is
@@ -100579,6 +100632,8 @@ class TFile {
100579100632 send_new_request(true);
100580100633 };
100581100634
100635+ setFileUrl();
100636+
100582100637 return send_new_request(true).then(() => promise);
100583100638 }
100584100639
@@ -101128,7 +101183,7 @@ function readMapElement(buf) {
101128101183
101129101184 if (this.member_wise) {
101130101185 // when member-wise streaming is used, version is written
101131- const si = buf.fFile.findStreamerInfo(this.pairtype, this.stl_version.val , this.stl_version.checksum);
101186+ const si = buf.fFile.findStreamerInfo(this.pairtype, this.stl_version.val, this.stl_version.checksum);
101132101187
101133101188 if (si && (this.si !== si)) {
101134101189 streamer = getPairStreamer(si, this.pairtype, buf.fFile);
@@ -101406,8 +101461,10 @@ function openFile(arg) {
101406101461 if (!file && isObject(arg) && arg.size && arg.name)
101407101462 file = new TLocalFile(arg);
101408101463
101409- if (!file)
101464+ if (!file) {
101410101465 file = new TFile(arg);
101466+ file.assignRemap(settings.FilesRemap);
101467+ }
101411101468
101412101469 return file._open();
101413101470}
@@ -153158,7 +153215,8 @@ class TScatterPainter extends TGraphPainter$1 {
153158153215 /** @summary Draw axis histogram
153159153216 * @private */
153160153217 async drawAxisHisto() {
153161- const histo = this.createHistogram();
153218+ const need_histo = !this.getHistogram(),
153219+ histo = this.createHistogram(need_histo, need_histo);
153162153220 return TH2Painter$2.draw(this.getDrawDom(), histo, this.options.Axis + ';IGNORE_PALETTE');
153163153221 }
153164153222
0 commit comments