From 1e6a1b4b45285368eed85218c8be02ba44dbc90c Mon Sep 17 00:00:00 2001 From: Sergey Linev Date: Thu, 21 Nov 2024 17:24:24 +0100 Subject: [PATCH] Build with new floatToString --- build/jsroot.js | 242 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 175 insertions(+), 67 deletions(-) diff --git a/build/jsroot.js b/build/jsroot.js index aa13055fa..7d05b3f62 100644 --- a/build/jsroot.js +++ b/build/jsroot.js @@ -12,7 +12,7 @@ const version_id = 'dev', /** @summary version date * @desc Release date in format day/month/year like '14/04/2022' */ -version_date = '19/11/2024', +version_date = '21/11/2024', /** @summary version id and date * @desc Produced by concatenation of {@link version_id} and {@link version_date} @@ -8524,23 +8524,32 @@ function getAbsPosInCanvas(sel, pos) { * @param {boolean} [ret_fmt] - when true returns array with value and actual format like ['0.1','6.4f'] * @return {string|Array} - converted value or array with value and actual format * @private */ -function floatToString(value, fmt, ret_fmt, significance) { +function floatToString(value, fmt, ret_fmt) { if (!fmt) fmt = '6.4g'; else if (fmt === 'g') - fmt = '8.6g'; - else if (fmt === 'c') - fmt = '8.6c'; + fmt = '7.5g'; fmt = fmt.trim(); const len = fmt.length; if (len < 2) return ret_fmt ? [value.toFixed(4), '6.4f'] : value.toFixed(4); - const kind = fmt[len-1].toLowerCase(); - fmt = fmt.slice(0, len-1); + + const kind = fmt[len-1].toLowerCase(), + compact = (len > 1) && (fmt[len-2] === 'c') ? 'c' : ''; + fmt = fmt.slice(0, len - (compact ? 2 : 1)); + + if (kind === 'g') { + const se = floatToString(value, fmt+'ce', true), + sg = floatToString(value, fmt+'cf', true), + res = se[0].length < sg[0].length || ((sg[0] === '0') && value) ? se : sg; + return ret_fmt ? res : res[0]; + } + let isexp, prec = fmt.indexOf('.'); prec = (prec < 0) ? 4 : parseInt(fmt.slice(prec+1)); - if (!Number.isInteger(prec) || (prec <= 0)) prec = 4; + if (!Number.isInteger(prec) || (prec <= 0)) + prec = 4; switch (kind) { case 'e': @@ -8549,46 +8558,37 @@ function floatToString(value, fmt, ret_fmt, significance) { case 'f': isexp = false; break; - case 'c': - case 'g': { - const se = floatToString(value, fmt+'e', true, true); - let sg = floatToString(value, fmt+'f', true, true); - const pnt = sg[0].indexOf('.'); - if ((kind === 'c') && (pnt > 0)) { - let len = sg[0].length; - while ((len > pnt) && (sg[0][len-1] === '0')) - len--; - if (len === pnt) len--; - sg[0] = sg[0].slice(0, len); - } - if (se[0].length < sg[0].length) - sg = se; - return ret_fmt ? sg : sg[0]; - } default: isexp = false; prec = 4; } if (isexp) { - // for exponential representation only one significant digit before point - if (significance) prec--; - if (prec < 0) prec = 0; + let se = value.toExponential(prec); - const se = value.toExponential(prec); - return ret_fmt ? [se, `${prec+2}.${prec}e`] : se; + if (compact) { + const pnt = se.indexOf('.'), + pe = se.toLowerCase().indexOf('e'); + if ((pnt > 0) && (pe > pnt)) { + let p = pe; + while ((p > pnt) && (se[p-1] === '0')) + p--; + if (p === pnt + 1) + p--; + if (p !== pe) + se = se.slice(0, p) + se.slice(pe); + } + } + + return ret_fmt ? [se, `${prec+2}.${prec}${compact}e`] : se; } let sg = value.toFixed(prec); - if (significance) { - // when using fixed representation, one could get 0 - if ((value !== 0) && (Number(sg) === 0) && (prec > 0)) { - prec = 20; sg = value.toFixed(prec); - } - + if (compact) { let l = 0; - while ((l < sg.length) && (sg[l] === '0' || sg[l] === '-' || sg[l] === '.')) l++; + while ((l < sg.length) && (sg[l] === '0' || sg[l] === '-' || sg[l] === '.')) + l++; let diff = sg.length - l - prec; if (sg.indexOf('.') > l) diff--; @@ -8601,9 +8601,22 @@ function floatToString(value, fmt, ret_fmt, significance) { prec = 20; sg = value.toFixed(prec); } + + const pnt = sg.indexOf('.'); + if (pnt > 0) { + let p = sg.length; + while ((p > pnt) && (sg[p-1] === '0')) + p--; + if (p === pnt + 1) + p--; + sg = sg.slice(0, p); + } + + if (sg === '-0') + sg = '0'; } - return ret_fmt ? [sg, `${prec+2}.${prec}f`] : sg; + return ret_fmt ? [sg, `${prec+2}.${prec}${compact}f`] : sg; } @@ -62631,7 +62644,7 @@ const AxisPainterMethods = { return res; } - return floatToString(val, fmt || 'c'); + return floatToString(val, fmt || '8.6g'); }, /** @summary Provide label for exponential form */ @@ -73578,6 +73591,23 @@ class TPavePainter extends ObjectPainter { this.getObject().AddText(txt); } + /** @summary Remade version of THistPainter::GetBestFormat + * @private */ + getBestFormat(tv, e) { + const ie = tv.indexOf('e'), id = tv.indexOf('.'); + + if (ie >= 0) { + if ((tv.indexOf('+') < 0) || (e >= 1)) + return `.${ie-id-1}e`; + else + return '.1f'; + } else if (id < 0) + return '.1f'; + + return `.${tv.length-id-1}f`; + } + + /** @summary Fill function parameters */ fillFunctionStat(f1, dofit, ndim = 1) { this._has_fit = false; @@ -73605,12 +73635,16 @@ class TPavePainter extends ObjectPainter { for (let n = 0; n < f1.GetNumPars(); ++n) { const parname = f1.GetParName(n); let parvalue = f1.GetParValue(n), parerr = f1.GetParError(n); - - parvalue = (parvalue === undefined) ? '' : this.format(Number(parvalue), 'fit'); - if (parerr !== undefined) { - parerr = this.format(parerr, 'last'); - if ((Number(parerr) === 0) && (f1.GetParError(n) !== 0)) - parerr = this.format(f1.GetParError(n), '4.2g'); + if (parvalue === undefined) { + parvalue = ''; + parerr = null; + } else { + parvalue = this.format(Number(parvalue), 'fit'); + if (print_ferrors && (parerr !== undefined)) { + parerr = floatToString(parerr, this.getBestFormat(parvalue, parerr)); + if ((Number(parerr) === 0) && (f1.GetParError(n) !== 0)) + parerr = floatToString(f1.GetParError(n), '4.2g'); + } } if (print_ferrors && parerr) @@ -74691,7 +74725,7 @@ const kUserContour = BIT(10), // user specified contour levels // kCanRebin = BIT(11), // can rebin axis // kLogX = BIT(15), // X-axis in log scale kIsZoomed$1 = BIT(16), // bit set when zooming on Y axis - kNoTitle = BIT(17); // don't draw the histogram title + kNoTitle$1 = BIT(17); // don't draw the histogram title // kIsAverage = BIT(18); // Bin contents are average (used by Add) /** @@ -75197,9 +75231,9 @@ class THistPainter extends ObjectPainter { if (!this.isMainPainter() || !histo) return false; if (arg === 'only-check') - return !histo.TestBit(kNoTitle); - histo.InvertBit(kNoTitle); - this.updateHistTitle().then(() => this.processOnlineChange(`exec:SetBit(TH1::kNoTitle,${histo.TestBit(kNoTitle)?1:0})`)); + return !histo.TestBit(kNoTitle$1); + histo.InvertBit(kNoTitle$1); + this.updateHistTitle().then(() => this.processOnlineChange(`exec:SetBit(TH1::kNoTitle,${histo.TestBit(kNoTitle$1)?1:0})`)); } /** @summary Only redraw histogram title @@ -75215,8 +75249,8 @@ class THistPainter extends ObjectPainter { if (!tpainter || !pt) return this; - const histo = this.getHisto(), st = gStyle, - draw_title = !histo.TestBit(kNoTitle) && (st.fOptTitle > 0); + const histo = this.getHisto(), st = this.getgStyle(), + draw_title = !histo.TestBit(kNoTitle$1) && (st.fOptTitle > 0); pt.Clear(); if (draw_title) pt.AddText(histo.fTitle); @@ -75230,15 +75264,16 @@ class THistPainter extends ObjectPainter { if (!this.isMainPainter() || this.options.Same || (this.options.Axis > 0)) return this; - const histo = this.getHisto(), st = gStyle, - draw_title = !histo.TestBit(kNoTitle) && (st.fOptTitle > 0), + const histo = this.getHisto(), st = this.getgStyle(), + draw_title = !histo.TestBit(kNoTitle$1) && (st.fOptTitle > 0), pp = this.getPadPainter(); let pt = pp.findInPrimitives(kTitle, clTPaveText); if (pt) { pt.Clear(); - if (draw_title) pt.AddText(histo.fTitle); + if (draw_title) + pt.AddText(histo.fTitle); return this; } @@ -75247,7 +75282,7 @@ class THistPainter extends ObjectPainter { fTextFont: st.fTitleFont, fTextSize: st.fTitleFontSize, fTextColor: st.fTitleTextColor, fTextAlign: 22 }); if (draw_title) pt.AddText(histo.fTitle); - return TPavePainter.draw(pp, pt, 'postitle').then(p => p?.setSecondaryId(this, kTitle)); + return TPavePainter.draw(pp, pt, 'postitle').then(p => { p?.setSecondaryId(this, kTitle); return this; }); } /** @summary Live change and update of title drawing @@ -152336,6 +152371,8 @@ __proto__: null, TGraph2DPainter: TGraph2DPainter }); +const kNoTitle = BIT(17); + /** * @summary Painter for TGraphPolargram objects. * @@ -152687,11 +152724,6 @@ class TGraphPolargramPainter extends ObjectPainter { class TGraphPolarPainter extends ObjectPainter { - /** @summary Redraw TGraphPolar */ - redraw() { - this.drawGraphPolar(); - } - /** @summary Decode options for drawing TGraphPolar */ decodeOptions(opt) { const d = new DrawOptions(opt || 'L'); @@ -152704,15 +152736,39 @@ class TGraphPolarPainter extends ObjectPainter { err: d.check('E'), fill: d.check('F'), line: d.check('L'), - curve: d.check('C'), - axis: d.check('A') + curve: d.check('C') }); + if (d.check('A')) + this._draw_axis = true; + this.storeDrawOpt(opt); } + /** @summary Update TGraphPolar with polargram */ + updateObject(obj, opt) { + if (!this.matchObjectType(obj)) + return false; + + if (opt && (opt !== this.options.original)) + this.decodeOptions(opt); + + if (this._draw_axis && obj.fPolargram) + this.getMainPainter().updateObject(obj.fPolargram); + + delete obj.fPolargram; + // copy all properties but not polargram + Object.assign(this.getObject(), obj); + return true; + } + + /** @summary Redraw TGraphPolar */ + redraw() { + return this.drawGraphPolar().then(() => this.updateTitle()); + } + /** @summary Drawing TGraphPolar */ - drawGraphPolar() { + async drawGraphPolar() { const graph = this.getObject(), main = this.getMainPainter(); @@ -152728,7 +152784,7 @@ class TGraphPolarPainter extends ObjectPainter { this.createG(); - if (this.options.axis && !main.isNormalAngles()) { + if (this._draw_axis && !main.isNormalAngles()) { const has_err = graph.fEX?.length; let rwtmin = graph.fX[0], rwtmax = graph.fX[0]; @@ -152881,6 +152937,59 @@ class TGraphPolarPainter extends ObjectPainter { return res; } + /** @summary Only redraw histogram title + * @return {Promise} with painter */ + async updateTitle() { + // case when histogram drawn over other histogram (same option) + if (!this._draw_axis) + return this; + + const tpainter = this.getPadPainter()?.findPainterFor(null, kTitle, clTPaveText), + pt = tpainter?.getObject(); + + if (!tpainter || !pt) + return this; + + const gr = this.getObject(), st = this.getgStyle(), + draw_title = !gr.TestBit(kNoTitle) && (st.fOptTitle > 0); + + pt.Clear(); + if (draw_title) pt.AddText(gr.fTitle); + return tpainter.redraw().then(() => this); + } + + + /** @summary Draw histogram title + * @return {Promise} with painter */ + async drawTitle() { + // case when histogram drawn over other histogram (same option) + if (!this._draw_axis) + return this; + + const gr = this.getObject(), + st = this.getgStyle(), + draw_title = !gr.TestBit(kNoTitle) && (st.fOptTitle > 0), + pp = this.getPadPainter(); + + let pt = pp.findInPrimitives(kTitle, clTPaveText); + + if (pt) { + pt.Clear(); + if (draw_title) + pt.AddText(gr.fTitle); + return this; + } + + pt = create$1(clTPaveText); + Object.assign(pt, { fName: kTitle, fFillColor: st.fTitleColor, fFillStyle: st.fTitleStyle, fBorderSize: st.fTitleBorderSize, + fTextFont: st.fTitleFont, fTextSize: st.fTitleFontSize, fTextColor: st.fTitleTextColor, fTextAlign: 22 }); + + if (draw_title) + pt.AddText(gr.fTitle); + return TPavePainter.draw(pp, pt, 'postitle') + .then(p => { p?.setSecondaryId(this, kTitle); return this; }); + } + /** @summary Show tooltip */ showTooltip(hint) { let ttcircle = this.draw_g?.selectChild('.tooltip_bin'); @@ -152931,16 +153040,15 @@ class TGraphPolarPainter extends ObjectPainter { let pr = Promise.resolve(null); if (!main) { // indicate that axis defined by this graph - painter.options.axis = true; + painter._draw_axis = true; pr = TGraphPolargramPainter.draw(dom, painter.createPolargram(graph)); } return pr.then(gram_painter => { gram_painter?.setSecondaryId(painter, 'polargram'); painter.addToPadPrimitives(); - painter.drawGraphPolar(); - return painter; - }); + return painter.drawGraphPolar(); + }).then(() => painter.drawTitle()); } } // class TGraphPolarPainter