Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 13 additions & 6 deletions demo/node/hpainter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
// in batch display one just able to create images


import { version, HierarchyPainter, draw } from 'jsroot';

import { version, HierarchyPainter, draw, addDrawFunc } from 'jsroot';
// import { writeFileSync } from 'fs';

console.log(`JSROOT version ${version}`);

Expand All @@ -14,27 +14,34 @@ const hp = new HierarchyPainter('hpainter');
hp.setDisplay('batch');

// catch draw function calls
hp.setDrawFunc((dom, obj, opt) => {
console.log(`trying to draw ${obj._typename}`);
return draw(dom, obj, opt);
addDrawFunc({
name: '*',
func: (dom, obj, opt) => {
console.log(`Actual draw of ${obj._typename}`);
// if function return true no normal drawing will be performed
// do not try to call `draw` function from here !!!
// return true;
}
});

await hp.openRootFile('https://root.cern/js/files/hsimple.root');

// display of TH2 histogram
console.log('Invoke histogram drawing');
await hp.display('hpxpy');

await hp.expandItem('ntuple');

// invoking TTree::Draw
console.log('Invoke TBranch drawing');
await hp.display('ntuple/pz');


// should be BatchDisplay
const disp = hp.getDisplay();

for (let id = 0; id < disp.numFrames(); ++id) {
const svg = await disp.makeSVG(id);

console.log(`Frame ${id} create svg size ${svg.length}`);

// one can save svg plain file
Expand Down
33 changes: 24 additions & 9 deletions modules/draw.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -130,14 +130,14 @@ const drawFuncs = { lst: [
{ name: 'kind:Command', icon: 'img_execute', execute: true },
{ name: 'TFolder', icon: 'img_folder', icon2: 'img_folderopen', noinspect: true, get_expand: () => import_h().then(h => h.folderHierarchy) },
{ name: 'TTask', icon: 'img_task', get_expand: () => import_h().then(h => h.taskHierarchy), for_derived: true },
{ name: clTTree, icon: 'img_tree', get_expand: () => import('./tree.mjs').then(h => h.treeHierarchy), draw: () => import_tree().then(h => h.drawTree), dflt: 'expand', opt: 'player;testio', shift: kInspect, pm: true },
{ name: clTTree, icon: 'img_tree', get_expand: () => import('./tree.mjs').then(h => h.treeHierarchy), draw: () => import_tree().then(h => h.drawTree), dflt: 'expand', opt: 'player;testio', shift: kInspect, pm: true, transform: true },
{ name: 'TNtuple', sameas: clTTree },
{ name: 'TNtupleD', sameas: clTTree },
{ name: clTBranchFunc, icon: 'img_leaf_method', draw: () => import_tree().then(h => h.drawTree), opt: ';dump', noinspect: true },
{ name: /^TBranch/, icon: 'img_branch', draw: () => import_tree().then(h => h.drawTree), dflt: 'expand', opt: ';dump', ctrl: 'dump', shift: kInspect, ignore_online: true, always_draw: true },
{ name: /^TLeaf/, icon: 'img_leaf', noexpand: true, draw: () => import_tree().then(h => h.drawTree), opt: ';dump', ctrl: 'dump', ignore_online: true, always_draw: true },
{ name: 'ROOT::RNTuple', icon: 'img_tree', get_expand: () => import('./rntuple.mjs').then(h => h.tupleHierarchy), draw: () => import('./draw/RNTuple.mjs').then(h => h.drawRNTuple), dflt: 'expand', pm: true },
{ name: 'ROOT::RNTupleField', icon: 'img_leaf', draw: () => import('./draw/RNTuple.mjs').then(h => h.drawRNTuple), opt: ';dump', ctrl: 'dump', shift: kInspect, ignore_online: true, always_draw: true },
{ name: clTBranchFunc, icon: 'img_leaf_method', draw: () => import_tree().then(h => h.drawTree), opt: ';dump', noinspect: true, transform: true },
{ name: /^TBranch/, icon: 'img_branch', draw: () => import_tree().then(h => h.drawTree), dflt: 'expand', opt: ';dump', ctrl: 'dump', shift: kInspect, ignore_online: true, always_draw: true, transform: true },
{ name: /^TLeaf/, icon: 'img_leaf', noexpand: true, draw: () => import_tree().then(h => h.drawTree), opt: ';dump', ctrl: 'dump', ignore_online: true, always_draw: true, transform: true },
{ name: 'ROOT::RNTuple', icon: 'img_tree', get_expand: () => import('./rntuple.mjs').then(h => h.tupleHierarchy), draw: () => import('./draw/RNTuple.mjs').then(h => h.drawRNTuple), dflt: 'expand', pm: true, transform: true },
{ name: 'ROOT::RNTupleField', icon: 'img_leaf', draw: () => import('./draw/RNTuple.mjs').then(h => h.drawRNTuple), opt: ';dump', ctrl: 'dump', shift: kInspect, ignore_online: true, always_draw: true, transform: true },
{ name: clTList, icon: 'img_list', draw: () => import_h().then(h => h.drawList), get_expand: () => import_h().then(h => h.listHierarchy), dflt: 'expand' },
{ name: clTHashList, sameas: clTList },
{ name: clTObjArray, sameas: clTList },
Expand Down Expand Up @@ -169,19 +169,28 @@ const drawFuncs = { lst: [


/** @summary Register draw function for the class
* @desc List of supported draw options could be provided, separated with ';'
* @param {object} args - arguments
* @param {string|regexp} args.name - class name or regexp pattern
* @param {string|regexp} args.name - class name or regexp pattern or '*'
* @param {function} [args.func] - draw function
* @param {string} [args.sameas] - let behave same as specified class
* @param {function} [args.draw] - async function to load draw function
* @param {function} [args.class] - async function to load painter class with static draw function
* @param {boolean} [args.direct] - if true, function is just Redraw() method of ObjectPainter
* @param {string} [args.opt] - list of supported draw options (separated with semicolon) like 'col;scat;'
* @param {string} [args.icon] - icon name shown for the class in hierarchy browser
* @param {string} [args.draw_field] - draw only data member from object, like fHistogram
* @param {string} [args.noinspect] - disable inspect
* @param {string} [args.noexpand] - disable expand
* @param {string} [args.pm] - always show plus or minus sign even when no child items exists
* @desc List of supported draw options could be provided, separated with ';'
* If args.name parameter is '*', function will be invoked before object drawing.
* If such function does not return value - normal drawing will be continued.
* @protected */
function addDrawFunc(args) {
drawFuncs.lst.push(args);
if (args?.name === '*')
internals._alt_draw = isFunc(args.func) ? args.func : null;
else
drawFuncs.lst.push(args);
return args;
}

Expand Down Expand Up @@ -392,6 +401,12 @@ async function draw(dom, obj, opt) {
if (handle.draw_field && obj[handle.draw_field])
return draw(dom, obj[handle.draw_field], opt || handle.draw_field_opt);

if (internals._alt_draw && !handle.transform) {
const v = internals._alt_draw(dom, obj, opt);
if (v)
return v;
}

if (!canDrawHandle(handle)) {
if (opt && (opt.indexOf('same') >= 0)) {
const main_painter = getElementMainPainter(dom);
Expand Down
6 changes: 6 additions & 0 deletions modules/draw/TTree.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ async function drawTreeDrawResult(dom, obj, opt) {
if (!typ || !isStr(typ))
return Promise.reject(Error('Object without type cannot be draw with TTree'));

if (internals._alt_draw) {
const v = internals._alt_draw(dom, obj, opt);
if (v)
return v;
}

if (typ.indexOf(clTH1) === 0)
return TH1Painter.draw(dom, obj, opt);
if (typ.indexOf(clTH2) === 0)
Expand Down
25 changes: 3 additions & 22 deletions modules/gui/HierarchyPainter.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -825,8 +825,6 @@ class HierarchyPainter extends BasePainter {
#one_by_one; // process drop items one by one
#topname; // top item name
#cached_draw_object; // cached object for first draw
#draw_func; // alternative draw function
#redraw_func; // alternative redraw function

/** @summary Create painter
* @param {string} name - symbolic name
Expand Down Expand Up @@ -857,23 +855,6 @@ class HierarchyPainter extends BasePainter {
this.textcolor = settings.DarkMode ? '#eee' : '#111';
}

/** @summary Set alternative draw/redraw functions
* @desc If only only draw function specified - it also will be used for re-drawing
* @protected */
setDrawFunc(_draw, _redraw) {
if (isFunc(_draw)) {
this.#draw_func = _draw;
this.#redraw_func = isFunc(_redraw) ? _redraw : _draw;
}
}

/** @summary Invoke configured draw or redraw function
* @protected */
async callDrawFunc(dom, obj, opt, doredraw) {
const func = doredraw ? (this.#redraw_func || redraw) : (this.#draw_func || draw);
return func(dom, obj, opt);
}

/** @summary Cleanup hierarchy painter
* @desc clear drawing and browser */
cleanup() {
Expand Down Expand Up @@ -2313,7 +2294,7 @@ class HierarchyPainter extends BasePainter {
drawopt = handle.dflt;

if (dom)
return this.callDrawFunc(dom, obj, drawopt, updating).then(p => complete(p)).catch(err => complete(null, err));
return (updating ? redraw : draw)(dom, obj, drawopt).then(p => complete(p)).catch(err => complete(null, err));

let did_activate = false;
const arr = [];
Expand Down Expand Up @@ -2357,7 +2338,7 @@ class HierarchyPainter extends BasePainter {
cleanup(frame);
mdi.activateFrame(frame);

return this.callDrawFunc(frame, obj, drawopt)
return draw(frame, obj, drawopt)
.then(p => complete(p))
.catch(err => complete(null, err));
});
Expand Down Expand Up @@ -2465,7 +2446,7 @@ class HierarchyPainter extends BasePainter {
if (isFunc(dom?.addPadButtons))
dom.addPadButtons();

return this.callDrawFunc(dom, res.obj, opt).then(p => drop_complete(p, mp === p));
return draw(dom, res.obj, opt).then(p => drop_complete(p, mp === p));
});
}

Expand Down