Skip to content

Commit a198988

Browse files
committed
[jsroot] dev 15/05/2025 without RHist classes
1. Remove all RHist classes 2. Let configure exact axis ticks position via draw option like "xticks:[-3,-1,1,3]" 3. Support dark mode when store images 4. With 'Shift' key pressed whole graph is moved by dragging action 5. Upgrade lil-gui.mjs 0.19.2 -> 0.20.0 6. Many changes with private class members
1 parent b65a5d6 commit a198988

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+3596
-11031
lines changed

js/build/jsroot.js

Lines changed: 1792 additions & 5490 deletions
Large diffs are not rendered by default.

js/changes.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
## Changes in dev
44
1. Use ES6 modules to implement geoworker, enable node.js usage
5-
1. Upgrade three.js r174 -> r176
65
1. Add missing colors 100 - 127
76
1. Let use hex colors in histogram draw options like "fill_00ff00" or "line_77aa1166"
7+
1. Let configure exact axis ticks position via draw option like "xticks:[-3,-1,1,3]"
8+
1. Support dark mode when store images
9+
1. With 'Shift' key pressed whole graph is moved by dragging action
10+
1. Upgrade three.js r174 -> r176
11+
1. Upgrade lil-gui.mjs 0.19.2 -> 0.20.0
812
1. Fix - colz handling on `THStack`, avoid multiple palette drawings
913
1. Fix - bug in pad.Divide context menu command
1014
1. Fix - palette not adjusted when 'same' draw option used for histogram

js/modules/base/BasePainter.mjs

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -204,12 +204,32 @@ class DrawOptions {
204204
return true;
205205

206206
let pos2 = pos;
207-
while ((pos2 < this.opt.length) && (this.opt[pos2] !== ' ') && (this.opt[pos2] !== ',') && (this.opt[pos2] !== ';')) pos2++;
207+
const is_array = postpart === 'array';
208+
if (is_array) {
209+
if (this.opt[pos2] !== '[')
210+
return false;
211+
while ((pos2 < this.opt.length) && (this.opt[pos2] !== ']'))
212+
pos2++;
213+
if (++pos2 > this.opt.length)
214+
return false;
215+
} else {
216+
while ((pos2 < this.opt.length) && (this.opt[pos2] !== ' ') && (this.opt[pos2] !== ',') && (this.opt[pos2] !== ';'))
217+
pos2++;
218+
}
208219
if (pos2 > pos) {
209220
this.part = this.opt.slice(pos, pos2);
210221
this.opt = this.opt.slice(0, pos) + this.opt.slice(pos2);
211222
}
212223

224+
if (is_array) {
225+
try {
226+
this.array = JSON.parse(this.part);
227+
} catch {
228+
this.array = undefined;
229+
}
230+
return this.array?.length !== undefined;
231+
}
232+
213233
if (postpart !== 'color')
214234
return true;
215235

@@ -233,7 +253,7 @@ class DrawOptions {
233253
/** @summary Returns remaining part of found option as integer. */
234254
partAsInt(offset, dflt) {
235255
let mult = 1;
236-
const last = this.part ? this.part[this.part.length - 1] : '';
256+
const last = this.part ? this.part.at(-1) : '';
237257
if (last === 'K')
238258
mult = 1e3;
239259
else if (last === 'M')

js/modules/base/ObjectPainter.mjs

Lines changed: 65 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,56 +18,57 @@ import { getRootColors } from './colors.mjs';
1818

1919
class ObjectPainter extends BasePainter {
2020

21+
#pad_name; // pad name where object is drawn
2122
#draw_object; // drawn object
2223
#main_painter; // WeakRef to main painter in the pad
2324
#primary_ref; // reference of primary painter - if any
2425
#secondary_id; // id of this painter in relation to primary painter
2526
#options_store; // stored draw options used to check changes
2627
#user_tooltip_handler; // configured user tooltip handler
2728
#user_tooltip_timeout; // timeout configured with tooltip handler
29+
#user_toottip_handle; // timeout handle processing user tooltip
30+
#user_context_menu; // function for user context menu
2831
#special_draw_area; // current special draw area like projection
32+
#root_colors; // custom colors list
2933

3034
/** @summary constructor
3135
* @param {object|string} dom - dom element or identifier or pad painter
3236
* @param {object} obj - object to draw
3337
* @param {string} [opt] - object draw options */
3438
constructor(dom, obj, opt) {
35-
let pp = null;
36-
if (isFunc(dom?.forEachPainterInPad) && (dom?.this_pad_name !== undefined)) {
37-
pp = dom;
38-
dom = pp.getDom();
39+
let pad_name = '';
40+
if (isFunc(dom?.forEachPainterInPad)) {
41+
pad_name = dom.this_pad_name;
42+
dom = dom.getDom();
3943
}
4044

4145
super(dom);
4246

4347
// this.draw_g = undefined; // container for all drawn objects
44-
this.pad_name = pp?.this_pad_name ?? ''; // name of pad where object is drawn
48+
this.setPadName(pad_name); // name of pad where object is drawn
4549
this.assignObject(obj);
4650
if (isStr(opt))
4751
this.options = { original: opt };
4852
}
4953

5054
/** @summary Assign object to the painter
5155
* @protected */
52-
assignObject(obj) {
53-
this.#draw_object = isObject(obj) ? obj : null;
54-
}
56+
assignObject(obj) { this.#draw_object = isObject(obj) ? obj : null; }
5557

5658
/** @summary Returns drawn object */
5759
getObject() { return this.#draw_object; }
5860

5961
/** @summary Assigns pad name where element will be drawn
6062
* @desc Should happened before first draw of element is performed, only for special use case
6163
* @param {string} [pad_name] - on which sub-pad element should be draw, if not specified - use current
62-
* @protected
63-
* @deprecated to be removed in v8 */
64+
* @protected */
6465
setPadName(pad_name) {
6566
// console.warn('setPadName is deprecated, to be removed in v8');
66-
this.pad_name = isStr(pad_name) ? pad_name : '';
67+
this.#pad_name = isStr(pad_name) ? pad_name : '';
6768
}
6869

6970
/** @summary Returns pad name where object is drawn */
70-
getPadName() { return this.pad_name || ''; }
71+
getPadName() { return this.#pad_name || ''; }
7172

7273
/** @summary Indicates that drawing runs in batch mode
7374
* @private */
@@ -88,12 +89,12 @@ class ObjectPainter extends BasePainter {
8889

8990
if (this.isMainPainter()) {
9091
const pp = this.getPadPainter();
91-
if (!pp || pp._auto_canvas)
92+
if (!pp || pp.isCanvas('auto'))
9293
keep_origin = false;
9394
}
9495

9596
// cleanup all existing references
96-
delete this.pad_name;
97+
this.#pad_name = undefined;
9798
this.#main_painter = null;
9899
this.#draw_object = null;
99100
delete this.snapid;
@@ -105,7 +106,7 @@ class ObjectPainter extends BasePainter {
105106
delete this.fillatt;
106107
delete this.lineatt;
107108
delete this.markeratt;
108-
delete this._root_colors;
109+
this.#root_colors = undefined;
109110
delete this.options;
110111
this.#options_store = undefined;
111112

@@ -249,30 +250,36 @@ class ObjectPainter extends BasePainter {
249250
return this.getObjectName() || this.getClassName() || '';
250251
}
251252

253+
/** @summary Set colors list
254+
* @protected */
255+
setColors(lst) { this.#root_colors = lst; }
256+
257+
/** @summary Return colors list
258+
* @protected */
259+
getColors(force) {
260+
if (!this.#root_colors && force)
261+
this.setColors(this.getCanvPainter()?.getColors() || getRootColors());
262+
return this.#root_colors;
263+
}
264+
252265
/** @summary returns color from current list of colors
253266
* @desc First checks canvas painter and then just access global list of colors
254267
* @param {number} indx - color index
255268
* @return {string} with SVG color name or rgb()
256269
* @protected */
257-
getColor(indx) {
258-
if (!this._root_colors)
259-
this._root_colors = this.getCanvPainter()?._root_colors || getRootColors();
260-
261-
return this._root_colors[indx];
262-
}
270+
getColor(indx) { return this.getColors(true)[indx]; }
263271

264272
/** @summary Add color to list of colors
265273
* @desc Returned color index can be used as color number in all other draw functions
266274
* @return {number} new color index
267275
* @protected */
268276
addColor(color) {
269-
if (!this._root_colors)
270-
this._root_colors = this.getCanvPainter()?._root_colors || getRootColors();
271-
const indx = this._root_colors.indexOf(color);
277+
const lst = this.getColors(true),
278+
indx = lst.indexOf(color);
272279
if (indx >= 0)
273280
return indx;
274-
this._root_colors.push(color);
275-
return this._root_colors.length - 1;
281+
lst.push(color);
282+
return lst.length - 1;
276283
}
277284

278285
/** @summary returns tooltip allowed flag
@@ -386,23 +393,13 @@ class ObjectPainter extends BasePainter {
386393
* @protected */
387394
getPadSvg(pad_name) {
388395
if (pad_name === undefined)
389-
pad_name = this.pad_name;
396+
pad_name = this.getPadName();
390397

391-
let c = this.getCanvSvg();
398+
const c = this.getCanvSvg();
392399
if (!pad_name || c.empty())
393400
return c;
394401

395-
const cp = c.property('pad_painter');
396-
if (cp?.pads_cache && cp.pads_cache[pad_name])
397-
return d3_select(cp.pads_cache[pad_name]);
398-
399-
c = c.select('.primitives_layer .__root_pad_' + pad_name);
400-
if (cp) {
401-
if (!cp.pads_cache)
402-
cp.pads_cache = {};
403-
cp.pads_cache[pad_name] = c.node();
404-
}
405-
return c;
402+
return c.select('.primitives_layer .__root_pad_' + pad_name);
406403
}
407404

408405
/** @summary Assign secondary id
@@ -490,20 +487,20 @@ class ObjectPainter extends BasePainter {
490487
const func = { isndc, nornd },
491488
use_frame = this.draw_g?.property('in_frame');
492489
if (use_frame || (use_frame_coordinates && !isndc))
493-
func.main = this.getFramePainter();
494-
if (func.main?.grx && func.main?.gry) {
495-
func.x0 = (use_frame_coordinates && !isndc) ? func.main.getFrameX() : 0;
496-
func.y0 = (use_frame_coordinates && !isndc) ? func.main.getFrameY() : 0;
490+
func.fp = this.getFramePainter();
491+
if (func.fp?.grx && func.fp?.gry) {
492+
func.x0 = (use_frame_coordinates && !isndc) ? func.fp.getFrameX() : 0;
493+
func.y0 = (use_frame_coordinates && !isndc) ? func.fp.getFrameY() : 0;
497494
if (nornd) {
498-
func.x = function(x) { return this.x0 + this.main.grx(x); };
499-
func.y = function(y) { return this.y0 + this.main.gry(y); };
495+
func.x = function(x) { return this.x0 + this.fp.grx(x); };
496+
func.y = function(y) { return this.y0 + this.fp.gry(y); };
500497
} else {
501-
func.x = function(x) { return this.x0 + Math.round(this.main.grx(x)); };
502-
func.y = function(y) { return this.y0 + Math.round(this.main.gry(y)); };
498+
func.x = function(x) { return this.x0 + Math.round(this.fp.grx(x)); };
499+
func.y = function(y) { return this.y0 + Math.round(this.fp.gry(y)); };
503500
}
504501
} else if (!use_frame) {
505502
const pp = this.getPadPainter();
506-
if (!isndc) func.pad = pp?.getRootPad(true); // need for NDC conversion
503+
func.pad = isndc ? null : pp?.getRootPad(true); // need for NDC conversion
507504
func.padw = pp?.getPadWidth() ?? 10;
508505
func.x = function(value) {
509506
if (this.pad) {
@@ -969,7 +966,7 @@ class ObjectPainter extends BasePainter {
969966
.property('text_factor', 0)
970967
.property('max_text_width', 0) // keep maximal text width, use it later
971968
.property('max_font_size', max_font_size)
972-
.property('_fast_drawing', this.getPadPainter()?._fast_drawing ?? false);
969+
.property('_fast_drawing', this.getPadPainter()?.isFastDrawing() ?? false);
973970

974971
if (draw_g.property('_fast_drawing'))
975972
draw_g.property('_font_too_small', (max_font_size && (max_font_size < 5)) || (font.size < 4));
@@ -1371,17 +1368,14 @@ class ObjectPainter extends BasePainter {
13711368
* Function should return promise with menu when items are filled
13721369
* @param {function} fillmenu_func - function to fill custom context menu for object */
13731370
configureUserContextMenu(fillmenu_func) {
1374-
if (!fillmenu_func || !isFunc(fillmenu_func))
1375-
delete this._userContextMenuFunc;
1376-
else
1377-
this._userContextMenuFunc = fillmenu_func;
1371+
this.#user_context_menu = isFunc(fillmenu_func) ? fillmenu_func : undefined;
13781372
}
13791373

13801374
/** @summary Fill object menu in web canvas
13811375
* @private */
13821376
async fillObjectExecMenu(menu, kind) {
1383-
if (isFunc(this._userContextMenuFunc))
1384-
return this._userContextMenuFunc(menu, kind);
1377+
if (isFunc(this.#user_context_menu))
1378+
return this.#user_context_menu(menu, kind);
13851379

13861380
const canvp = this.getCanvPainter();
13871381

@@ -1421,8 +1415,8 @@ class ObjectPainter extends BasePainter {
14211415
}
14221416

14231417
menu.showMethodArgsDialog(item).then(args => {
1424-
if (!args) return;
1425-
if (execp.executeMenuCommand(item, args)) return;
1418+
if (!args || execp.executeMenuCommand(item, args))
1419+
return;
14261420

14271421
const exec = item.fExec.slice(0, item.fExec.length - 1) + args + ')';
14281422
if (cp?.v7canvas)
@@ -1557,17 +1551,17 @@ class ObjectPainter extends BasePainter {
15571551
if (this.#user_tooltip_timeout <= 0)
15581552
return this.#user_tooltip_handler(data);
15591553

1560-
if (this._user_tooltip_handle) {
1561-
clearTimeout(this._user_tooltip_handle);
1562-
delete this._user_tooltip_handle;
1554+
if (this.#user_toottip_handle) {
1555+
clearTimeout(this.#user_toottip_handle);
1556+
this.#user_toottip_handle = undefined;
15631557
}
15641558

15651559
if (!data)
15661560
return this.#user_tooltip_handler(data);
15671561

15681562
// only after timeout user function will be called
1569-
this._user_tooltip_handle = setTimeout(() => {
1570-
delete this._user_tooltip_handle;
1563+
this.#user_toottip_handle = setTimeout(() => {
1564+
this.#user_toottip_handle = undefined;
15711565
if (this.#user_tooltip_handler)
15721566
this.#user_tooltip_handler(data);
15731567
}, this.#user_tooltip_timeout);
@@ -1673,7 +1667,14 @@ function drawRawText(dom, txt /* , opt */) {
16731667
return painter.drawText();
16741668
}
16751669

1676-
/** @summary Returns canvas painter (if any) for specified HTML element
1670+
/** @summary Returns pad painter (if any) for specified DOM element
1671+
* @param {string|object} dom - id or DOM element
1672+
* @private */
1673+
function getElementPadPainter(dom) {
1674+
return new ObjectPainter(dom).getPadPainter();
1675+
}
1676+
1677+
/** @summary Returns canvas painter (if any) for specified DOM element
16771678
* @param {string|object} dom - id or DOM element
16781679
* @private */
16791680
function getElementCanvPainter(dom) {
@@ -1780,6 +1781,6 @@ const EAxisBits = {
17801781

17811782
Object.assign(internals.jsroot, { ObjectPainter, cleanup, resize });
17821783

1783-
export { getElementCanvPainter, getElementMainPainter, drawingJSON,
1784+
export { getElementPadPainter, getElementCanvPainter, getElementMainPainter, drawingJSON,
17841785
selectActivePad, getActivePad, cleanup, resize, drawRawText,
17851786
ObjectPainter, EAxisBits, kAxisLabels, kAxisNormal, kAxisFunc, kAxisTime };

js/modules/base/RObjectPainter.mjs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const kNormal = 1, /* kLessTraffic = 2, */ kOffline = 3;
99
class RObjectPainter extends ObjectPainter {
1010

1111
#pending_request;
12+
#auto_colors; // handle for auto colors
1213

1314
constructor(dom, obj, opt, csstype) {
1415
super(dom, obj, opt);
@@ -149,16 +150,13 @@ class RObjectPainter extends ObjectPainter {
149150

150151
if (val === 'auto') {
151152
const pp = this.getPadPainter();
152-
if (pp?._auto_color_cnt !== undefined) {
153-
const pal = pp.getHistPalette(),
154-
cnt = pp._auto_color_cnt++;
155-
let num = pp._num_primitives - 1;
156-
if (num < 2) num = 2;
157-
val = pal ? pal.getColorOrdinal((cnt % num) / num) : 'blue';
158-
if (!this._auto_colors) this._auto_colors = {};
159-
this._auto_colors[name] = val;
160-
} else if (this._auto_colors && this._auto_colors[name])
161-
val = this._auto_colors[name];
153+
if (pp) {
154+
val = pp.getAutoColor();
155+
if (!this.#auto_colors)
156+
this.#auto_colors = {};
157+
this.#auto_colors[name] = val;
158+
} else if (this.#auto_colors && this.#auto_colors[name])
159+
val = this.#auto_colors[name];
162160
else {
163161
console.error(`Autocolor ${name} not defined yet - please check code`);
164162
val = '';

0 commit comments

Comments
 (0)