GSI Object Oriented Online Offline (Go4)  GO4-6.2.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
analysiseditor.js
Go to the documentation of this file.
1 // $Id: analysiseditor.js 3525 2022-01-27 10:28:09Z linev $
2 
3 JSROOT.define(["painter"], jsrp => {
4 
5  if (typeof GO4 != "object") {
6  let e1 = new Error("analysiseditor.js requires GO4 to be already loaded");
7  e1.source = "analysiseditor.js";
8  throw e1;
9  }
10 
11  GO4.EvIOType = {
12  GO4EV_NULL: 0, // no event store/source
13  GO4EV_FILE: 1, // root file with own tree
14  GO4EV_TREE: 2, // branch of singleton tree
15  GO4EV_MBS_FILE: 3, // mbs listmode file (input only)
16  GO4EV_MBS_STREAM: 4, // mbs stream server (input only)
17  GO4EV_MBS_TRANSPORT: 5, // mbs transport server (input only)
18  GO4EV_MBS_EVENTSERVER: 6, // mbs event server (input only)
19  GO4EV_MBS_REVSERV: 7, // remote event server (input only)
20  GO4EV_BACK: 8, // backstore in memory (pseudo-ringbuffer?)
21  GO4EV_USER: 9, // user defined source class
22  GO4EV_MBS_RANDOM: 10, // random generated mbs event
23  GO4EV_HDF5: 11 // HDF5 file format
24  };
25 
26  function createJSMenu(event, painter) {
27  return jsrp.createMenu(event,painter).then(menu => {
28  if (!menu.confirm)
29  menu.confirm = function(head, msg) {
30  let res = window.confirm(`${head}\n${msg}`);
31  return Promise.resolve(res);
32  }
33  return menu;
34  });
35  }
36 
37  class AnalysisStatusEditor extends JSROOT.BasePainter {
38  constructor(dom, stat) {
39  super(dom);
40  this.stat = stat;
41  this.changes = [["dummy0", "init0"],["dummy1","init1"]]; // changes array stepwise, index 0 = no step, index = stepindex+1
42  this.clearChanges();
43  }
44 
45  markChanged(key, step) {
46  // first avoid duplicate keys:
47  for (let index = 0; index < this.changes[step].length; index++) {
48  if (this.changes[step][index]== key) return;
49  }
50  this.changes[step].push(key);
51  console.log("Mark changed :%s at step %d", key, step);
52 
53  this.selectDom().select(".buttonAnaChangeLabel").style('display', null); // show warning sign
54  }
55 
56  // clear changed elements' list, make warning sign invisible
57  clearChanges() {
58  let numsteps = this.changes.length;
59  for (let step = 0; step < numsteps ; step++)
60  this.changes[step] = [];
61  this.selectDom().select(".buttonAnaChangeLabel").style('display', 'none'); // hide warning sign
62  }
63 
65  evaluateChanges(optionstring) {
66  let editor = this;
67  let numsteps = this.changes.length;
68  for (let step = 0; step < numsteps ; step++) {
69  let theElement = editor.stat.fxStepArray.arr[step],
70  stepoptions = "",
71  len = this.changes[step].length;
72 
73  for (let index = 0; index < len ; index++) {
74 
75  let key = this.changes[step][index],
76  preifx = `&${key}=`,
77  step_prefix = `&${key}_${step}=`;
78 
79  // here mapping of key to editor field:
80  if (key == "stepenabled") {
81  stepoptions += step_prefix + theElement.fbProcessEnabled;
82  } else if (key == "sourceenabled") {
83  stepoptions += step_prefix + theElement.fbSourceEnabled;
84  } else if (key == "storeenabled") {
85  stepoptions += step_prefix + theElement.fbStoreEnabled;
86  } else if (key == "sourcesel") {
87  stepoptions += step_prefix + theElement.fxSourceType.fiID;
88  } else if (key == "sourcename") {
89  stepoptions += step_prefix + theElement.fxSourceType.fName;
90  } else if (key == "sourcetag") {
91  stepoptions += step_prefix + theElement.fxSourceType.fxTagFile;
92  } else if (key == "sourceport") {
93  stepoptions += step_prefix + theElement.fxSourceType.fiPort;
94  } else if (key == "sourcetmout") {
95  stepoptions += step_prefix + theElement.fxSourceType.fiTimeout;
96  } else if (key == "sourceretry") {
97  stepoptions += step_prefix + theElement.fxSourceType.fiRetryCnt;
98  } else if (key == "sourcefirst") {
99  stepoptions += step_prefix + theElement.fxSourceType.fuStartEvent;
100  } else if (key == "sourcelast") {
101  stepoptions += step_prefix + theElement.fxSourceType.fuStopEvent;
102  } else if (key == "sourceskip") {
103  stepoptions += step_prefix + theElement.fxSourceType.fuEventInterval;
104  } else if (key == "storesel") {
105  stepoptions += step_prefix + theElement.fxStoreType.fiID;
106  } else if (key == "storename") {
107  stepoptions += step_prefix + theElement.fxStoreType.fName;
108  } else if (key == "storesplit") {
109  stepoptions += step_prefix + theElement.fxStoreType.fiSplit;
110  } else if (key == "storebuf") {
111  stepoptions += step_prefix + theElement.fxStoreType.fiBufsize;
112  } else if (key == "storecomp") {
113  stepoptions += step_prefix + theElement.fxStoreType.fiCompression;
114  } else if (key == "storeasf") {
115  stepoptions += step_prefix + theElement.fxStoreType.fiAutosavesize;
116  } else if (key == "storeover") {
117  stepoptions += step_prefix + theElement.fxStoreType.fbOverwrite;
118  }
119  // non step specific options are in step 0 options too:
120  else if (key == "asfname") {
121  stepoptions += preifx + editor.stat.fxAutoFileName;
122  } else if (key == "asfenabled") {
123  stepoptions += preifx + editor.stat.fbAutoSaveOn;
124  } else if (key == "asftime") {
125  stepoptions += preifx + editor.stat.fiAutoSaveInterval;
126  } else if (key == "asfcomp") {
127  stepoptions += preifx + editor.stat.fiAutoSaveCompression;
128  } else if (key == "asfoverwrite") {
129  stepoptions += preifx + editor.stat.fbAutoSaveOverwrite;
130  } else if (key == "anaprefsname") {
131  stepoptions += preifx + editor.stat.fxConfigFileName;
132  } else {
133  console.log(`Warning: evaluateChanges found unknown key: ${key}`);
134  }
135 
136  }// for index
137 
138  optionstring += stepoptions;
139  } // for step
140  console.log("Resulting option string:%s", optionstring);
141  return optionstring;
142  }
143 
144  showStepEditor(tab, theElement, theIndex) {
145 
146  let sourcebox = tab.select(".step_box_source_enab"),
147  storebox = tab.select(".step_box_store_enab"),
148  step_source = tab.select(".step_source"),
149  step_store = tab.select(".step_store"),
150  sourcemore = tab.select(".step_source_expand");
151 
152  // here step control checkboxes and source/store visibility:
153  if (theElement.fbProcessEnabled) {
154  sourcebox.attr('disabled', null);
155  storebox.attr('disabled', null);
156  step_source.attr('disabled', theElement.fbSourceEnabled ? null : "true");
157  step_store.style('display', theElement.fbStoreEnabled ? null : "none");
158  } else {
159  sourcebox.attr('disabled', "true");
160  storebox.attr('disabled', "true");
161  step_source.attr('disabled', "true");
162  step_store.style('display', "none");
163  }
164 
165  let show_tag = false, show_ports = false, show_args = false, show_more = sourcemore.property("checked");
166 
167  switch (theElement.fxSourceType.fiID) {
168  case GO4.EvIOType.GO4EV_MBS_FILE:
169  show_tag = show_args = show_more; break;
170  case GO4.EvIOType.GO4EV_MBS_STREAM:
171  case GO4.EvIOType.GO4EV_MBS_TRANSPORT:
172  case GO4.EvIOType.GO4EV_MBS_EVENTSERVER:
173  case GO4.EvIOType.GO4EV_MBS_REVSERV:
174  show_ports = show_args = show_more; break;
175  case GO4.EvIOType.GO4EV_USER:
176  show_ports = show_more; break;
177  case GO4.EvIOType.GO4EV_FILE:
178  case GO4.EvIOType.GO4EV_MBS_RANDOM:
179  default:
180  // show no extra parameters
181  break;
182  };
183 
184  tab.select(".step_source_tagfile_args").style('display', show_tag ? null : 'none');
185  tab.select(".step_source_port_args").style('display', show_ports ? null : 'none');
186  tab.select(".step_source_number_args").style('display', show_args ? 'inline' : 'none');
187 
188  let enbale_store_pars = false, enbale_store_name = true;
189  switch (theElement.fxStoreType.fiID) {
190  case GO4.EvIOType.GO4EV_FILE:
191  enbale_store_pars = true;
192  break;
193  case GO4.EvIOType.GO4EV_BACK:
194  enbale_store_pars = true;
195  enbale_store_name = false;
196  break;
197  case GO4.EvIOType.GO4EV_USER:
198  break;
199  default:
200  break;
201  };
202 
203  tab.select(".step_store_pars").selectAll("input").each(function() {
204  d3.select(this).attr("disabled", enbale_store_pars ? null : "true");
205  });
206 
207  tab.select(".step_store_name").attr("disabled", enbale_store_name ? null : "true");
208  }
209 
210  fillEditor() {
211  let dom = this.selectDom(),
212  stat = this.stat;
213 
214  let head_html = "", step_html = "";
215  stat.fxStepArray.arr.forEach((step, indx) => {
216  head_html += `<button for="go4_analysis_step_${indx}">${step.fName}</button>`;
217  step_html += `<div class="go4_analysis_step_${indx}" style="display:none">${this.stepPageHtml}</div>`;
218  });
219 
220  dom.select(".ana_step_tabs_header").html(head_html);
221 
222  dom.select(".ana_step_tabs_body").html(step_html);
223 
224  // assign tabs buttons handlers
225  dom.select('.ana_step_tabs_header').selectAll("button").on("click", function() {
226  let btn = d3.select(this);
227 
228  dom.select('.ana_step_tabs_header').selectAll("button").each(function() {
229  d3.select(this).classed("active_btn", false);
230  });
231 
232  btn.classed("active_btn", true);
233 
234  dom.selectAll('.ana_step_tabs_body>div').each(function() {
235  let tab = d3.select(this);
236  tab.style('display', tab.classed(btn.attr("for")) ? null : "none");
237  });
238  });
239 
240  // activate first step
241  dom.select(".ana_step_tabs_body").select(".go4_analysis_step_0").style('display', null);
242  dom.select('.ana_step_tabs_header').select("button").classed("active_btn", true);
243 
244  stat.fxStepArray.arr.forEach((theElement, theIndex) => {
245  let tab = dom.select(".ana_step_tabs_body").select(`.go4_analysis_step_${theIndex}`);
246 
247  let enablebox = tab.select(".step_box_step_enab"),
248  sourcebox = tab.select(".step_box_source_enab"),
249  storebox = tab.select(".step_box_store_enab"),
250  sourcesel = tab.select(".step_source_select"),
251  sourcemore = tab.select(".step_source_expand"),
252  sourcename = tab.select(".step_source_name"),
253  sourcetag = tab.select(".step_source_tagfile"),
254  sourceport = tab.select(".step_source_port"),
255  sourcetmout = tab.select(".step_source_tmout"),
256  sourceretry = tab.select(".step_source_retry"),
257  sourcefirst = tab.select(".step_source_firstev"),
258  sourcelast = tab.select(".step_source_lastev"),
259  sourceskip = tab.select(".step_source_stepev"),
260  storesel = tab.select(".step_store_select"),
261  storename = tab.select(".step_store_name"),
262  storesplit = tab.select(".step_store_split"),
263  storebuf = tab.select(".step_store_buf"),
264  storecomp = tab.select(".step_store_comp"),
265  storetreeasf = tab.select(".step_store_asf"),
266  storeover = tab.select(" .step_store_overwrite");
267 
268  enablebox.property('checked', theElement.fbProcessEnabled)
269  .on("click", () => {
270  this.markChanged("stepenabled", theIndex);
271  theElement.fbProcessEnabled = enablebox.property('checked');
272  this.showStepEditor(tab, theElement, theIndex);
273  }); // clickfunction
274 
275  sourcebox.property('checked', theElement.fbSourceEnabled)
276  .on("click", () => {
277  this.markChanged("sourceenabled", theIndex);
278  theElement.fbSourceEnabled = sourcebox.property('checked');
279  this.showStepEditor(tab, theElement, theIndex);
280  }); // clickfunction
281 
282  storebox.property('checked', theElement.fbStoreEnabled)
283  .on("click", () => {
284  this.markChanged("storeenabled", theIndex);
285  theElement.fbStoreEnabled = storebox.property('checked');
286  this.showStepEditor(tab, theElement, theIndex);
287  }); // clickfunction
288 
290  sourcesel.property("value", theElement.fxSourceType.fiID).on("change", () => {
291  this.markChanged("sourcesel", theIndex);
292 
293  theElement.fxSourceType.fiID = parseInt(sourcesel.property("value"));
294 
295  this.showStepEditor(tab, theElement, theIndex);
296  }); // source selectmenu change
297 
298  sourcemore.on("click", () => {
299  this.showStepEditor(tab, theElement, theIndex);
300  });
301 
302  sourcename.property("value", theElement.fxSourceType.fName)
303  .on("change", () => {
304  this.markChanged("sourcename", theIndex);
305  theElement.fxSourceType.fName = sourcename.property("value").trim();
306  });
307 
308  sourcetag.property("value", theElement.fxSourceType.fxTagFile || "")
309  .on("change", () => {
310  this.markChanged("sourcetag", theIndex);
311  theElement.fxSourceType.fxTagFile = sourcetag.property("value").trim();
312  });
313 
314  sourceport.property("value", theElement.fxSourceType.fiPort || 0)
315  .on("change", () => {
316  this.markChanged("sourceport", theIndex);
317  theElement.fxSourceType.fiPort = parseInt(sourceport.property("value"));
318  });
319 
320  sourcetmout.property("value", theElement.fxSourceType.fiTimeout || 100)
321  .on("change", () => {
322  this.markChanged("sourcetmout", theIndex);
323  theElement.fxSourceType.fiTimeout = parseInt(sourcetmout.property("value"));
324  });
325 
326  sourceretry.property("value", theElement.fxSourceType.fiRetryCnt || 0)
327  .on("change", () => {
328  this.markChanged("sourceretry", theIndex);
329  theElement.fxSourceType.fiRetryCnt = parseInt(sourceretry.property("value"));
330  });
331 
332  sourcefirst.property("value", theElement.fxSourceType.fuStartEvent || 0)
333  .on("change", () => {
334  this.markChanged("sourcefirst", theIndex);
335  theElement.fxSourceType.fuStartEvent = parseInt(sourcefirst.property("value"));
336  });
337 
338  sourcelast.property("value", theElement.fxSourceType.fuStopEvent || 0)
339  .on("change", () => {
340  this.markChanged("sourcelast", theIndex);
341  theElement.fxSourceType.fuStopEvent = parseInt(sourcelast.property("value"));
342  });
343 
344  sourceskip.property("value", theElement.fxSourceType.fuEventInterval || 0)
345  .on("change", () => {
346  this.markChanged("sourceskip", theIndex);
347  theElement.fxSourceType.fuEventInterval = parseInt(sourceskip.property("value"));
348  });
349 
350  storesel.property("value", theElement.fxStoreType.fiID).on("change", () => {
351  this.markChanged("storesel", theIndex);
352  theElement.fxStoreType.fiID = parseInt(storesel.property("value"));
353  this.showStepEditor(tab, theElement, theIndex);
354  });
355 
356  storename.property("value", theElement.fxStoreType.fName)
357  .on("change", () => {
358  this.markChanged("storename", theIndex);
359  theElement.fxStoreType.fName = storename.property("value").trim();
360  });
361 
362  storesplit.property("value", theElement.fxStoreType.fiSplit || 1)
363  .on("change", () => {
364  theElement.fxStoreType.fiSplit = parseInt(storesplit.property("value"));
365  this.markChanged("storesplit", theIndex);
366  });
367 
368  storebuf.property("value", Math.round((theElement.fxStoreType.fiBufsize || 16*1024) / 1024))
369  .on("change", () => {
370  theElement.fxStoreType.fiBufsize = parseInt(storebuf.property("value")) * 1024;
371  this.markChanged("storebuf", theIndex);
372  });
373 
374  storecomp.property("value", theElement.fxStoreType.fiCompression || 0)
375  .on("change", () => {
376  theElement.fxStoreType.fiCompression = parseInt(storecomp.property("value"));
377  this.markChanged("storecomp", theIndex);
378  });
379 
380  storetreeasf.property("value", theElement.fxStoreType.fiAutosavesize || 0)
381  .on("change", () => {
382  theElement.fxStoreType.fiAutosavesize = parseInt(storetreeasf.property("value"));
383  this.markChanged("storeasf", theIndex);
384  });
385 
386  storeover.property("checked", theElement.fxStoreType.fbOverwrite || true)
387  .on("click", () => {
388  theElement.fxStoreType.fbOverwrite = storeover.property("checked");
389  this.markChanged("storeover", theIndex);
390  });
391 
392  this.showStepEditor(tab, theElement, theIndex); // handle all visibility issues here, also refresh tabs
393 
394  }); // steps loop
395 
396  dom.select(".buttonGetAnalysis")
397  .style('background-image', "url(" + GO4.source_dir + "icons/right.png)")
398  .on("click", () => {
399  if (JSROOT.hpainter) JSROOT.hpainter.display(this.getItemName());
400  });
401 
402  dom.select(".buttonSetAnalysis")
403  .style('background-image', "url(" + GO4.source_dir + "icons/left.png)")
404  .on("click", () => {
405  let options = this.evaluateChanges(""); // complete option string from all changed elements
406  console.log("submit analysis " + this.getItemName() + ", options=" + options);
407  GO4.ExecuteMethod(this, "UpdateFromUrl", options).then(() => {
408  console.log("setting analyis configuration done.");
409  this.clearChanges();
410  if (JSROOT.hpainter && (typeof JSROOT.hpainter.reload == 'function')) JSROOT.hpainter.reload();
411  });
412  });
413 
414  dom.select(".buttonAnaChangeLabel")
415  .style('background-image', "url(" + GO4.source_dir + "icons/info1.png)")
416  .style('display', 'none'); // do not show at the begin
417 
418  dom.select(".buttonSetStartAnalysis")
419  .style('background-image', "url(" + GO4.source_dir + "icons/restart.png)")
420  .on("click", () => {
421  let options = this.evaluateChanges(""); // complete option string from all changed elements
422  options += "&start";
423  console.log("submit and start analysis " + this.getItemName() + ", options=" + options);
424  GO4.ExecuteMethod(this, "UpdateFromUrl", options).then(() => {
425  console.log("submit and start analyis configuration done. ");
426  this.clearChanges();
427  if (JSROOT.hpainter && (typeof JSROOT.hpainter.reload == 'function')) JSROOT.hpainter.reload();
428  });
429  });
430 
431  dom.select(".buttonCloseAnalysis")
432  .style('background-image', "url(" + GO4.source_dir + "icons/close.png)")
433  .on("click", () => {
434  console.log("close analysis " + this.getItemName());
435  GO4.ExecuteMethod(this, "UpdateFromUrl", "&close").then(() => {
436  console.log("closing down analyis done. ");
437  });
438  });
439 
440  dom.select(".buttonSaveAnaASF")
441  .style('background-image', "url(" + GO4.source_dir + "icons/filesave.png)");
442 
443  dom.select(".anaASF_name").property("value", stat.fxAutoFileName);
444  dom.select(".anaASF_enabled")
445  .property('checked', stat.fbAutoSaveOn)
446  .on("click", () => {
447  this.markChanged("asfenabled",0);
448  this.stat.fbAutoSaveOn = dom.select(".anaASF_enabled").property('checked');
449  });
450 
451  dom.select(".anaASF_time")
452  .property("value", stat.fiAutoSaveInterval)
453  .on("change", () => {
454  this.markChanged("asftime", 0);
455  this.stat.fiAutoSaveInterval = dom.select(".anaASF_time").property("value");
456  });
457 
458  dom.select(".anaASF_compression")
459  .property("value", stat.fiAutoSaveCompression)
460  .on("change", () => {
461  this.markChanged("asfcomp", 0);
462  this.stat.fiAutoSaveCompression = dom.select(".anaASF_compression").property("value");
463  });
464 
465  dom.select(".anaASF_overwrite")
466  .property('checked', stat.fbAutoSaveOverwrite)
467  .on("click", () => {
468  this.markChanged("asfoverwrite",0);
469  this.stat.fbAutoSaveOverwrite = dom.select(".anaASF_overwrite").property('checked');
470  });
471 
473  dom.select(".anaprefs_name").property("value", stat.fxConfigFileName);
474 
475  dom.select(".anaASF_form").on("submit", event => {
476  event.preventDefault(); // do not send automatic request to server!
477  let content = dom.select(".anaASF_name").property("value");
478  content = content.trim();
479  // before we write immediately, mark name as changed in setup:
480  this.markChanged("asfname", 0);
481  this.stat.fxAutoFileName = content;
482 
483  createJSMenu(event, this)
484  .then(menu => menu.confirm("Save auto save file", content))
485  .then(ok => (ok ? GO4.ExecuteMethod(this, "UpdateFromUrl", "&saveasf=" + content) : null))
486  .then(res => console.log(res ? "Writing autosave file done." : "Ignore or failed"));
487  });
488 
489 
490  dom.select(".buttonSaveAnaConf")
491  .style('background-image', "url(" + GO4.source_dir + "icons/filesave.png)")
492  .on("click", event => {
493  let content = dom.select(".anaprefs_name").property("value").trim(),
494  requestmsg = "Really save analysis preferences: " + content;
495  createJSMenu(event, this)
496  .then(menu => menu.confirm("Saving analysis preferences", requestmsg))
497  .then(ok => {
498  if (!ok) return null;
499  this.markChanged("anaprefsname", 0);
500  this.stat.fxConfigFileName = content;
501  return GO4.ExecuteMethod(this, "UpdateFromUrl", "&saveprefs=" + content);
502  }).then(res => console.log(res !== null ? "Loading Saving preferences done. " : "Saving preferences FAILED."));
503  });
504 
505  dom.select(".buttonLoadAnaConf")
506  .style('background-image', "url(" + GO4.source_dir + "icons/fileopen.png)")
507  .on("click", event => {
508  let content = dom.select(".anaprefs_name").property("value").trim(),
509  requestmsg = "Really load analysis preferences: " + content;
510  createJSMenu(event, this)
511  .then(menu => menu.confirm("Loading analysis preferences", requestmsg))
512  .then(ok => (ok ? GO4.ExecuteMethod(this, "UpdateFromUrl", "&loadprefs=" + content) : null))
513  .then(res => { if ((res!==null) && JSROOT.hpainter) JSROOT.hpainter.display(this.getItemName()); });
514  });
515  }
516 
517  redrawObject(obj /*, opt */) {
518  if (obj._typename != this.stat._typename) return false;
519  this.stat = JSROOT.clone(obj);
520  this.clearChanges();
521  this.fillEditor();
522  return true;
523  }
524  }
525 
526  GO4.drawGo4AnalysisStatus = function(domarg, stat) {
527  let editor = new AnalysisStatusEditor(domarg, stat),
528  dom = editor.selectDom(),
529  h = dom.node().clientHeight,
530  w = dom.node().clientWidth;
531 
532  if ((h < 10) && (w > 10)) dom.style("height", Math.round(w * 0.7)+"px");
533 
534  return JSROOT.httpRequest(GO4.source_dir + "html/analysiseditor.htm", "text").then(code => {
535  dom.html(code);
536 
537  return JSROOT.httpRequest(GO4.source_dir + "html/stepeditor.htm", "text");
538 
539  }).then(step_code => {
540 
541  editor.stepPageHtml = step_code;
542 
543  editor.fillEditor();
544 
545  editor.setTopPainter();
546  return editor;
547  });
548  }
549 
550 });
string msg
Definition: go4init.py:11