GSI Object Oriented Online Offline (Go4)  GO4-6.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
go4.js
Go to the documentation of this file.
1 // $Id: go4.js 3527 2022-01-27 10:44:20Z linev $
2 
3 const go4Script = document.currentScript;
4 
5 JSROOT.define(["painter"], jsrp => {
6 
7  "use strict";
8 
9  const GO4 = { version: "6.2.0", id_counter: 1, source_dir: "" };
10 
11  if (go4Script && (typeof go4Script.src == "string")) {
12  const pos = go4Script.src.indexOf("html/go4.js");
13  if (pos >= 0) {
14  GO4.source_dir = go4Script.src.substr(0, pos);
15  console.log(`Set GO4.source_dir to ${GO4.source_dir}, ${GO4.version}`);
16  }
17  }
18 
21  GO4.ExecuteMethod = function(painter, method, options) {
22  let prefix = "";
23  if (painter.getItemName())
24  prefix = painter.getItemName() + "/"; // suppress / if item name is empty
25 
26  let fullcom = prefix + "exe.json?method=" + method + (options || "&"); // send any arguments otherwise ROOT refuse to process it
27 
28  return JSROOT.httpRequest(fullcom, 'text');
29  }
30 
31  // ==================================================================================
32 
33  GO4.DrawAnalysisRatemeter = function(divid, itemname) {
34 
35  function CreateHTML() {
36  let elem = d3.select('#'+divid);
37 
38  if (elem.size() == 0) return null;
39  if (elem.select(".event_rate").size() > 0) return elem;
40 
41  let html = "<div style='padding-top:2px'>";
42  html += "<img class='go4_logo' style='vertical-align:middle;margin-left:5px;margin-right:5px;' src='go4sys/icons/go4logorun4.gif' alt='logo'></img>";
43  html += "<label class='event_source' style='border: 1px solid gray; font-size:large; vertical-align:middle; padding-left:3px; padding-right:3px;'>file.lmd</label> ";
44  html += "<label class='event_rate' style='border: 1px solid gray; font-size:large; vertical-align:middle; background-color: grey'; padding-left:3px; padding-right:3px;>---</label> Ev/s ";
45  html += "<label class='aver_rate' style='border: 1px solid gray; font-size:large; vertical-align:middle; padding-left:3px; padding-right:3px;'>---</label> Ev/s ";
46  html += "<label class='run_time' style='border: 1px solid gray; font-size:large; vertical-align:middle; padding-left:3px; padding-right:3px;'>---</label> s ";
47  html += "<label class='total_events' style='border: 1px solid gray; font-size:large; vertical-align:middle; padding-left:3px; padding-right:3px;'>---</label> Events ";
48  html += "<label class='analysis_time' style='border: 1px solid gray; font-size:large; vertical-align:middle; padding-left:3px; padding-right:3px;'>time</label>";
49  html += "</div>";
50 
51  elem.style('overflow','hidden')
52  .style('padding-left','5px')
53  .style('display', 'inline-block')
54  .style('white-space', 'nowrap')
55  .html(html);
56 
57  // use height of child element
58  let brlayout = JSROOT.hpainter ? JSROOT.hpainter.brlayout : null,
59  sz = elem.node().clientHeight + 12;
60 
61  if (brlayout)
62  brlayout.adjustSeparators(null, sz, true);
63  return elem;
64  }
65 
66  let xreq = false, was_running = null;
67 
68  function UpdateRatemeter() {
69  if (xreq) return;
70 
71  let elem = CreateHTML();
72  if (!elem) return;
73 
74  xreq = true;
75  JSROOT.httpRequest(itemname + "/root.json.gz", 'object').then(res => {
76  elem.select(".event_rate").style('background-color', res.fbRunning ? 'lightgreen' : 'red');
77  if (was_running != res.fbRunning)
78  elem.select(".go4_logo").attr("src", res.fbRunning ? 'go4sys/icons/go4logorun4.gif' : 'go4sys/icons/go4logo_t.png');
79 
80  was_running = res.fbRunning;
81 
82  elem.select(".event_source").text(res.fxEventSource == "" ? "<source>" : res.fxEventSource);
83  elem.select(".event_rate").text(res.fdRate.toFixed(1));
84  elem.select(".aver_rate").text((res.fdTime > 0 ? res.fuCurrentCount / res.fdTime : 0).toFixed(1));
85  elem.select(".run_time").text(res.fdTime.toFixed(1));
86  elem.select(".total_events").text(res.fuCurrentCount);
87  elem.select(".analysis_time").text(res.fxDateString == "" ? "<datime>" : res.fxDateString);
88  }).catch(() => {
89  elem.select(".event_rate").style('background-color','grey');
90  }).finally(() => {
91  xreq = false;
92  });
93  }
94 
95  CreateHTML();
96 
97  setInterval(UpdateRatemeter, 2000);
98  }
99 
100 
101  GO4.MakeMsgListRequest = function(hitem, item) {
102  let arg = "&max=2000";
103  if ('last-id' in item) arg+= "&id="+item['last-id'];
104  return 'exe.json.gz?method=Select' + arg;
105  }
106 
107  GO4.AfterMsgListRequest = function(hitem, item, obj) {
108  if (!item) return;
109 
110  if (!obj) {
111  delete item['last-id'];
112  return;
113  }
114  // ignore all other classes
115  if (obj._typename != 'TList') return;
116 
117  obj._typename = "TGo4MsgList";
118 
119  if (obj.arr.length>0) {
120  let duplicate = (('last-id' in item) && (item['last-id'] == obj.arr[0].fString));
121 
122  item['last-id'] = obj.arr[0].fString;
123 
124  // workaround for snapshot, it sends always same messages many times
125  if (duplicate) obj.arr.length = 1;
126 
127  // add clear function for item
128  if (!('clear' in item))
129  item['clear'] = function() { delete this['last-id']; }
130  }
131  }
132 
133  class MsgListPainter extends JSROOT.BasePainter {
134 
135  constructor(dom, lst) {
136  super(dom);
137  this.lst = lst;
138  }
139 
140  redrawObject(obj) {
141  // if (!obj._typename != 'TList') return false;
142  this.lst = obj;
143  this.drawList();
144  return true;
145  }
146 
147  drawList() {
148  if (!this.lst) return;
149 
150  let frame = this.selectDom();
151 
152  let main = frame.select("div");
153  if (main.empty())
154  main = frame.append("div")
155  .style('max-width','100%')
156  .style('max-height','100%')
157  .style('overflow','auto');
158 
159  let old = main.selectAll("pre");
160  let newsize = old.size() + this.lst.arr.length - 1;
161 
162  // in the browser keep maximum 2000 entries
163  if (newsize > 2000)
164  old.select(function(d,i) { return i < newsize - 2000 ? this : null; }).remove();
165 
166  for (let i = this.lst.arr.length-1; i > 0; i--)
167  main.append("pre").style('margin','3px').html(this.lst.arr[i].fString);
168  }
169  }
170 
171  GO4.DrawMsgList = function(dom, lst) {
172 
173  let painter = new MsgListPainter(dom, lst);
174 
175  painter.drawList();
176 
177  painter.setTopPainter();
178  return Promise.resolve(painter);
179  }
180 
181  class AnalysisTerminalPainter extends JSROOT.BasePainter {
182  constructor(frame, hpainter, itemname, url) {
183  super(frame);
184  this.hpainter = hpainter;
185  this.itemname = itemname;
186  this.url = url;
187  this.draw_ready = true;
188  this.needscroll = false;
189  }
190 
191  logReady(p) {
192  if (p) this.log_painter = p;
193  if(this.needscroll) {
194  this.clickScroll(true);
195  this.needscroll = false;
196  }
197  this.draw_ready = true;
198  }
199 
200  checkResize() {}
201 
202  cleanup(arg) {
203  if (this.log_painter) {
204  this.log_painter.cleanup();
205  delete this.log_painter;
206  }
207  if (this.interval) {
208  clearInterval(this.interval);
209  delete this.interval;
210  }
211  super.cleanup(arg);
212  }
213 
214  processTimer() {
215  let subid = "anaterm_output_container";
216  // detect if drawing disappear
217  if (d3.select("#" + subid).empty())
218  return this.cleanup();
219 
220  if (!this.draw_ready) return;
221 
222  let msgitem = this.itemname.replace("Control/Terminal", "Status/Log");
223 
224  this.draw_ready = false;
225 
226  if (this.log_painter)
227  this.hpainter.display(msgitem, "update:divid:" + subid).then(() => this.logReady());
228  else
229  this.hpainter.display(msgitem, "divid:" + subid).then(p => this.logReady(p));
230  }
231 
232  clickCommand(kind) {
233  let command = this.itemname.replace("Terminal", "CmdExecute");
234  this.hpainter.executeCommand(command, null, kind). then(() => { this.needscroll = true; });
235  }
236 
237  clickClear() {
238  d3.select("#anaterm_output_container").html("");
239  }
240 
241  clickScroll(last) {
242  // inner frame created by hpainter has the scrollbars, i.e. first child
243  let nodes = d3.select("#anaterm_output_container").selectAll("pre").nodes();
244  if (nodes) nodes[last ? nodes.length-1 : 0].scrollIntoView();
245  }
246 
247  fillDisplay() {
248  this.setTopPainter();
249  this.interval = setInterval(() => this.processTimer(), 2000);
250  let dom = this.selectDom();
251 
252  dom.select(".go4_clearterm")
253  .on("click", () => this.clickClear())
254  .style('background-image', "url(" + GO4.source_dir + "icons/clear.png)");
255 
256  dom.select(".go4_startterm")
257  .on("click", () => this.clickScroll(false))
258  .style('background-image', "url(" + GO4.source_dir + "icons/shiftup.png)");
259 
260  dom.select(".go4_endterm")
261  .on("click", () => this.clickScroll(true))
262  .style('background-image', "url(" + GO4.source_dir + "icons/shiftdown.png)");
263 
264  dom.select(".go4_printhistos")
265  .on("click", () => this.clickCommand("@PrintHistograms()"))
266  .style('background-image', "url(" + GO4.source_dir + "icons/hislist.png)");
267 
268  dom.select(".go4_printcond")
269  .on("click", () => this.clickCommand("@PrintConditions()"))
270  .style('background-image', "url(" + GO4.source_dir + "icons/condlist.png)");
271 
272  dom.select(".go4_executescript")
273  .style('background-image', "url(" + GO4.source_dir + "icons/macro_t.png)");
274 
275  dom.select(".go4_anaterm_cmd_form").on("submit", event => {
276  event.preventDefault();
277  let command = this.itemname.replace("Terminal", "CmdExecute");
278  let cmdpar = document.getElementById("go4_anaterm_command").value;
279  console.log("submit command - " + cmdpar);
280  this.hpainter.executeCommand(command, null, cmdpar).then(() => { this.needscroll = true; });
281  });
282 
283  }
284  }
285 
286  GO4.drawAnalysisTerminal = function(hpainter, itemname) {
287  let url = hpainter.getOnlineItemUrl(itemname),
288  mdi = hpainter.getDisplay(),
289  frame = mdi ? mdi.findFrame(itemname, true) : null;
290 
291  if (!url || !frame) return null;
292 
293  let elem = d3.select(frame),
294  h = frame.clientHeight,
295  w = frame.clientWidth;
296  if ((h < 10) && (w > 10)) elem.style("height", Math.round(w*0.7)+"px");
297 
298  let player = new AnalysisTerminalPainter(frame, hpainter, itemname, url);
299 
300  return JSROOT.httpRequest(GO4.source_dir + "html/terminal.htm", "text")
301  .then(code => {
302  elem.html(code);
303  player.fillDisplay();
304  return player;
305  });
306  }
307 
308  const op_LineColor = 5,
309  op_LineStyle = 6,
310  op_LineWidth = 7,
311  op_FillColor = 8,
312  op_FillStyle = 9,
313  op_HisStatsX1 = 19,
314  op_HisStatsY1 = 20,
315  op_HisStatsX2 = 21,
316  op_HisStatsY2 = 22,
317  op_HisStats = 24,
318  op_HisTitle = 25,
319  op_HisStatsOpt = 85,
320  op_HisStatsFit = 86,
321  op_Draw = 0x4001,
322 
323  PictureIndex = -1;
324 
325  function getOptValue(pic, indx, typ) {
326  if (!pic || !pic.fxOptIndex) return null;
327  let srch = indx + 1 + (typ << 16);
328  for (let k = 0; k < pic.fxOptIndex.length; ++k)
329  if (pic.fxOptIndex[k] == srch)
330  return pic.fxOptValue[k];
331  return null;
332  }
333 
334  function getOptDouble(pic, indx, typ) {
335  let ivalue = getOptValue(pic, indx, typ);
336  if (ivalue === null) return null;
337  const buffer = new ArrayBuffer(16),
338  view = new DataView(buffer),
339  big = BigInt(ivalue); // to be sure that BigInt is used
340  view.setUint32(0, Number(big >> 32n));
341  view.setUint32(4, Number(big % (2n ** 32n)));
342  return view.getFloat64(0);
343  }
344 
345  function drawSpecialObjects(divid, pic, k) {
346  if (!pic.fxSpecialObjects || (k >= pic.fxSpecialObjects.arr.length))
347  return Promise.resolve(false);
348 
349  return JSROOT.draw(divid, pic.fxSpecialObjects.arr[k], pic.fxSpecialObjects.opt[k]).then(() => drawSpecialObjects(divid, pic, k+1));
350  }
351 
352  function drawPictureObjects(divid, pic, k) {
353  if (!divid || !pic.fxNames)
354  return Promise.resolve(false);
355 
356  let arr = pic.fxNames ? pic.fxNames.arr : null;
357  if (!arr || (k >= arr.length))
358  return drawSpecialObjects(divid, pic, 0);
359 
360  let n = pic.fxNames.arr[k], itemname = "", isth2 = false;
361 
362  JSROOT.hpainter.forEachItem(item => {
363  if (item._name == n.fString) {
364  itemname = JSROOT.hpainter.itemFullName(item);
365  if (item._kind && (item._kind.indexOf("ROOT.TH2") == 0)) isth2 = true;
366  }
367  });
368 
369  if (!itemname) {
370  console.log('not found object with name', n.fString);
371  return drawPictureObjects(divid, pic, k+1);
372  }
373 
374  // console.log('Want to display item', itemname, 'on', divid);
375 
376  let opt = isth2 ? "col" : "",
377  iopt = getOptValue(pic, k, op_Draw);
378  if ((iopt !== null) && pic.fxOptObjects)
379  opt = pic.fxOptObjects.arr[iopt].fString;
380  if (k > 0) opt += " same";
381 
382  return JSROOT.hpainter.display(itemname, opt + "divid:" + divid).then(painter => {
383  if (!painter) return;
384  let need_redraw = false;
385 
386  if (painter.lineatt) {
387  let lcol = getOptValue(pic, k, op_LineColor),
388  lwidth = getOptValue(pic, k, op_LineWidth),
389  lstyle = getOptValue(pic, k, op_LineStyle);
390  if ((lcol !== null) && (lwidth !== null) && (lstyle !== null)) {
391  painter.lineatt.change(painter.getColor(lcol), lwidth, lstyle);
392  need_redraw = true;
393  }
394  }
395 
396  if (painter.fillatt) {
397  let fcol = getOptValue(pic, k, op_FillColor),
398  fstyle = getOptValue(pic, k, op_FillStyle);
399 
400  if ((fcol !== null) && (fstyle !== null)) {
401  painter.fillatt.change(fcol, fstyle, painter.getCanvSvg());
402  need_redraw = true;
403  }
404  }
405 
406  if (typeof painter.getHisto == 'function' && painter.createHistDrawAttributes && painter.isMainPainter()) {
407  const kNoStats = JSROOT.BIT(9),
408  kNoTitle = JSROOT.BIT(17);
409 
410  let histo = painter.getHisto(),
411  stat = painter.findStat(),
412  sx1 = getOptDouble(pic, PictureIndex, op_HisStatsX1),
413  sy1 = getOptDouble(pic, PictureIndex, op_HisStatsY1),
414  sx2 = getOptDouble(pic, PictureIndex, op_HisStatsX2),
415  sy2 = getOptDouble(pic, PictureIndex, op_HisStatsY2),
416  has_stats_pos = (sx1 !== null) && (sy1 !== null) && (sx2!==null) && (sy2!==null),
417  istitle = getOptValue(pic, PictureIndex, op_HisTitle),
418  isstats = getOptValue(pic, PictureIndex, op_HisStats),
419  statsopt = getOptValue(pic, PictureIndex, op_HisStatsOpt),
420  fitopt = getOptValue(pic, PictureIndex, op_HisStatsFit);
421 
422  if ((istitle !== null) && (!istitle != histo.TestBit(kNoTitle))) {
423  histo.InvertBit(kNoTitle); need_redraw = true;
424  }
425  if ((isstats !== null) && (!isstats != histo.TestBit(kNoStats))) {
426  histo.InvertBit(kNoStats); need_redraw = true;
427  }
428  if (stat && ((statsopt !== null) || (fitopt !== null) || has_stats_pos)) {
429  if (statsopt !== null) stat.fOptStat = statsopt;
430  if (fitopt !== null) stat.fOptFit = fitopt;
431  let pp = painter.getPadPainter(),
432  statpainter = pp ? pp.findPainterFor(stat) : null;
433  if (has_stats_pos) {
434  stat.fX1NDC = sx1;
435  stat.fY1NDC = sy1;
436  stat.fX2NDC = sx2;
437  stat.fY2NDC = sy2;
438  }
439  if (statpainter) statpainter.redraw();
440  }
441  }
442 
443  if (need_redraw) return painter.redraw();
444 
445  }).then(() => drawPictureObjects(divid, pic, k+1));
446  }
447 
448  function drawSubPictures(pad_painter, pic, nsub) {
449  let arr = pic && pic.fxSubPictures ? pic.fxSubPictures.arr : null;
450  if (!arr || nsub >= arr.length)
451  return Promise.resolve(pad_painter);
452 
453  let subpic = pic.fxSubPictures.arr[nsub];
454 
455  let subpad_painter = pad_painter.getSubPadPainter(1 + subpic.fiPosY*pic.fiNDivX + subpic.fiPosX);
456 
457  return drawPicture(subpad_painter, subpic).then(() => drawSubPictures(pad_painter, pic, nsub+1));
458  }
459 
460  function drawPicture(pad_painter, pic) {
461  if (!pad_painter)
462  return Promise.resolve(false);
463 
464  let need_divide = pic.fiNDivX * pic.fiNDivY > 1;
465 
466  if (need_divide && !pad_painter.divide) {
467  console.log('JSROOT version without TPadPainter.divide');
468  return Promise.resolve(false);
469  }
470 
471  let prev_name = pad_painter.selectCurrentPad(pad_painter.this_pad_name);
472 
473  if (need_divide)
474  return pad_painter.divide(pic.fiNDivX, pic.fiNDivY).then(() => drawSubPictures(pad_painter, pic, 0)).then(() => {
475  pad_painter.selectCurrentPad(prev_name);
476  return pad_painter;
477  });
478 
479  let divid = pad_painter.selectDom().attr('id');
480  if (!divid) {
481  divid = "go4picture_div_" + GO4.id_counter++;
482  pad_painter.selectDom().attr('id', divid);
483  console.error('Drawing must be done on element with id, force ', divid);
484  }
485 
486  return drawPictureObjects(divid, pic, 0).then(() => {
487  pad_painter.selectCurrentPad(prev_name);
488  return pad_painter;
489  });
490  }
491 
492  GO4.drawGo4Picture = function(dom, pic) {
493  if (!JSROOT.hpainter) return null;
494 
495  let painter = new JSROOT.ObjectPainter(dom, pic);
496 
497  return JSROOT.require('gpad').then(() => jsrp.ensureTCanvas(painter, false)).then(() => {
498  let pad_painter = painter.getPadPainter();
499 
500  painter.removeFromPadPrimitives();
501 
502  return drawPicture(pad_painter, pic);
503  }).then(() => painter); // return dummy painter
504  }
505 
506  // ==============================================================================
507 
508  let canvsrc = GO4.source_dir + 'html/go4canvas.js;';
509 
510  jsrp.addDrawFunc({ name: "TGo4WinCond", script: canvsrc, func: 'GO4.drawGo4Cond', opt: ";editor" });
511  jsrp.addDrawFunc({ name: "TGo4PolyCond", script: canvsrc, func: 'GO4.drawGo4Cond', opt: ";editor" });
512  jsrp.addDrawFunc({ name: "TGo4ShapedCond", script: canvsrc, func: 'GO4.drawGo4Cond', opt: ";editor" });
513  jsrp.addDrawFunc({ name: "TGo4CondArray", script: canvsrc, func: 'GO4.drawCondArray', opt: ";editor" });
514  jsrp.addDrawFunc({ name: "TGo4Marker", script: canvsrc, func: 'GO4.drawGo4Marker' });
515 
516  jsrp.addDrawFunc({ name: "TGo4AnalysisWebStatus", script: GO4.source_dir + 'html/analysiseditor.js', func: 'GO4.drawGo4AnalysisStatus', opt: "editor" });
517 
518  jsrp.addDrawFunc({ name: "TGo4MsgList", func: GO4.DrawMsgList });
519  jsrp.addDrawFunc({ name: "TGo4Picture", func: GO4.drawGo4Picture, icon: GO4.source_dir + "icons/picture.png" });
520 
521  jsrp.addDrawFunc({ name: "TGo4MbsEvent", noinspect: true });
522  jsrp.addDrawFunc({ name: "TGo4EventElement", noinspect: true });
523 
524  globalThis.GO4 = GO4;
525 
526  return GO4;
527 });
const go4Script
Definition: go4.js:3
int main(int argc, char **argv)