// $Id$
const go4Script = document.currentScript;
JSROOT.define(["painter"], jsrp => {
"use strict";
const GO4 = { version: "6.2.99", id_counter: 1, source_dir: "" };
if (go4Script && (typeof go4Script.src == "string")) {
const pos = go4Script.src.indexOf("html/go4.js");
if (pos >= 0) {
GO4.source_dir = go4Script.src.substr(0, pos);
console.log(`Set GO4.source_dir to ${GO4.source_dir}, ${GO4.version}`);
}
}
/** @summary Execute method for selected painter object
* @return {Promise} when done */
GO4.ExecuteMethod = function(painter, method, options) {
let prefix = "";
if (painter.getItemName())
prefix = painter.getItemName() + "/"; // suppress / if item name is empty
let fullcom = prefix + "exe.json?method=" + method + (options || "&"); // send any arguments otherwise ROOT refuse to process it
return JSROOT.httpRequest(fullcom, 'text');
}
// ==================================================================================
GO4.DrawAnalysisRatemeter = function(divid, itemname) {
function CreateHTML() {
let elem = d3.select('#'+divid);
if (elem.size() == 0) return null;
if (elem.select(".event_rate").size() > 0) return elem;
let html = "
";
html += "

";
html += "
";
html += "
Ev/s ";
html += "
Ev/s ";
html += "
s ";
html += "
Events ";
html += "
";
html += "
";
elem.style('overflow','hidden')
.style('padding-left','5px')
.style('display', 'inline-block')
.style('white-space', 'nowrap')
.html(html);
// use height of child element
let brlayout = JSROOT.hpainter ? JSROOT.hpainter.brlayout : null,
sz = elem.node().clientHeight + 12;
if (brlayout)
brlayout.adjustSeparators(null, sz, true);
return elem;
}
let xreq = false, was_running = null;
function UpdateRatemeter() {
if (xreq) return;
let elem = CreateHTML();
if (!elem) return;
xreq = true;
JSROOT.httpRequest(itemname + "/root.json.gz", 'object').then(res => {
elem.select(".event_rate").style('background-color', res.fbRunning ? 'lightgreen' : 'red');
if (was_running != res.fbRunning)
elem.select(".go4_logo").attr("src", res.fbRunning ? 'go4sys/icons/go4logorun4.gif' : 'go4sys/icons/go4logo_t.png');
was_running = res.fbRunning;
elem.select(".event_source").text(res.fxEventSource == "" ? "" : res.fxEventSource);
elem.select(".event_rate").text(res.fdRate.toFixed(1));
elem.select(".aver_rate").text((res.fdTime > 0 ? res.fuCurrentCount / res.fdTime : 0).toFixed(1));
elem.select(".run_time").text(res.fdTime.toFixed(1));
elem.select(".total_events").text(res.fuCurrentCount);
elem.select(".analysis_time").text(res.fxDateString == "" ? "" : res.fxDateString);
}).catch(() => {
elem.select(".event_rate").style('background-color','grey');
}).finally(() => {
xreq = false;
});
}
CreateHTML();
setInterval(UpdateRatemeter, 2000);
}
GO4.MakeMsgListRequest = function(hitem, item) {
let arg = "&max=2000";
if ('last-id' in item) arg+= "&id="+item['last-id'];
return 'exe.json.gz?method=Select' + arg;
}
GO4.AfterMsgListRequest = function(hitem, item, obj) {
if (!item) return;
if (!obj) {
delete item['last-id'];
return;
}
// ignore all other classes
if (obj._typename != 'TList') return;
obj._typename = "TGo4MsgList";
if (obj.arr.length>0) {
let duplicate = (('last-id' in item) && (item['last-id'] == obj.arr[0].fString));
item['last-id'] = obj.arr[0].fString;
// workaround for snapshot, it sends always same messages many times
if (duplicate) obj.arr.length = 1;
// add clear function for item
if (!('clear' in item))
item['clear'] = function() { delete this['last-id']; }
}
}
class MsgListPainter extends JSROOT.BasePainter {
constructor(dom, lst) {
super(dom);
this.lst = lst;
}
redrawObject(obj) {
// if (!obj._typename != 'TList') return false;
this.lst = obj;
this.drawList();
return true;
}
drawList() {
if (!this.lst) return;
let frame = this.selectDom();
let main = frame.select("div");
if (main.empty())
main = frame.append("div")
.style('max-width','100%')
.style('max-height','100%')
.style('overflow','auto');
let old = main.selectAll("pre");
let newsize = old.size() + this.lst.arr.length - 1;
// in the browser keep maximum 2000 entries
if (newsize > 2000)
old.select(function(d,i) { return i < newsize - 2000 ? this : null; }).remove();
for (let i = this.lst.arr.length-1; i > 0; i--)
main.append("pre").style('margin','3px').html(this.lst.arr[i].fString);
}
}
GO4.DrawMsgList = function(dom, lst) {
let painter = new MsgListPainter(dom, lst);
painter.drawList();
painter.setTopPainter();
return Promise.resolve(painter);
}
class AnalysisTerminalPainter extends JSROOT.BasePainter {
constructor(frame, hpainter, itemname, url) {
super(frame);
this.hpainter = hpainter;
this.itemname = itemname;
this.url = url;
this.draw_ready = true;
this.needscroll = false;
}
logReady(p) {
if (p) this.log_painter = p;
if(this.needscroll) {
this.clickScroll(true);
this.needscroll = false;
}
this.draw_ready = true;
}
checkResize() {}
cleanup(arg) {
if (this.log_painter) {
this.log_painter.cleanup();
delete this.log_painter;
}
if (this.interval) {
clearInterval(this.interval);
delete this.interval;
}
super.cleanup(arg);
}
processTimer() {
let subid = "anaterm_output_container";
// detect if drawing disappear
if (d3.select("#" + subid).empty())
return this.cleanup();
if (!this.draw_ready) return;
let msgitem = this.itemname.replace("Control/Terminal", "Status/Log");
this.draw_ready = false;
if (this.log_painter)
this.hpainter.display(msgitem, "update:divid:" + subid).then(() => this.logReady());
else
this.hpainter.display(msgitem, "divid:" + subid).then(p => this.logReady(p));
}
clickCommand(kind) {
let command = this.itemname.replace("Terminal", "CmdExecute");
this.hpainter.executeCommand(command, null, kind). then(() => { this.needscroll = true; });
}
clickClear() {
d3.select("#anaterm_output_container").html("");
}
clickScroll(last) {
// inner frame created by hpainter has the scrollbars, i.e. first child
let nodes = d3.select("#anaterm_output_container").selectAll("pre").nodes();
if (nodes) nodes[last ? nodes.length-1 : 0].scrollIntoView();
}
fillDisplay() {
this.setTopPainter();
this.interval = setInterval(() => this.processTimer(), 2000);
let dom = this.selectDom();
dom.select(".go4_clearterm")
.on("click", () => this.clickClear())
.style('background-image', "url(" + GO4.source_dir + "icons/clear.png)");
dom.select(".go4_startterm")
.on("click", () => this.clickScroll(false))
.style('background-image', "url(" + GO4.source_dir + "icons/shiftup.png)");
dom.select(".go4_endterm")
.on("click", () => this.clickScroll(true))
.style('background-image', "url(" + GO4.source_dir + "icons/shiftdown.png)");
dom.select(".go4_printhistos")
.on("click", () => this.clickCommand("@PrintHistograms()"))
.style('background-image', "url(" + GO4.source_dir + "icons/hislist.png)");
dom.select(".go4_printcond")
.on("click", () => this.clickCommand("@PrintConditions()"))
.style('background-image', "url(" + GO4.source_dir + "icons/condlist.png)");
dom.select(".go4_executescript")
.style('background-image', "url(" + GO4.source_dir + "icons/macro_t.png)");
dom.select(".go4_anaterm_cmd_form").on("submit", event => {
event.preventDefault();
let command = this.itemname.replace("Terminal", "CmdExecute");
let cmdpar = document.getElementById("go4_anaterm_command").value;
console.log("submit command - " + cmdpar);
this.hpainter.executeCommand(command, null, cmdpar).then(() => { this.needscroll = true; });
});
}
}
GO4.drawAnalysisTerminal = function(hpainter, itemname) {
let url = hpainter.getOnlineItemUrl(itemname),
mdi = hpainter.getDisplay(),
frame = mdi ? mdi.findFrame(itemname, true) : null;
if (!url || !frame) return null;
let elem = d3.select(frame),
h = frame.clientHeight,
w = frame.clientWidth;
if ((h < 10) && (w > 10)) elem.style("height", Math.round(w*0.7)+"px");
let player = new AnalysisTerminalPainter(frame, hpainter, itemname, url);
return JSROOT.httpRequest(GO4.source_dir + "html/terminal.htm", "text")
.then(code => {
elem.html(code);
player.fillDisplay();
return player;
});
}
const op_LineColor = 5,
op_LineStyle = 6,
op_LineWidth = 7,
op_FillColor = 8,
op_FillStyle = 9,
op_HisStatsX1 = 19,
op_HisStatsY1 = 20,
op_HisStatsX2 = 21,
op_HisStatsY2 = 22,
op_HisStats = 24,
op_HisTitle = 25,
op_HisStatsOpt = 85,
op_HisStatsFit = 86,
op_Draw = 0x4001,
PictureIndex = -1;
function getOptValue(pic, indx, typ) {
if (!pic || !pic.fxOptIndex) return null;
let srch = indx + 1 + (typ << 16);
for (let k = 0; k < pic.fxOptIndex.length; ++k)
if (pic.fxOptIndex[k] == srch)
return pic.fxOptValue[k];
return null;
}
function getOptDouble(pic, indx, typ) {
let ivalue = getOptValue(pic, indx, typ);
if (ivalue === null) return null;
const buffer = new ArrayBuffer(16),
view = new DataView(buffer),
big = BigInt(ivalue); // to be sure that BigInt is used
view.setUint32(0, Number(big >> 32n));
view.setUint32(4, Number(big % (2n ** 32n)));
return view.getFloat64(0);
}
function drawSpecialObjects(divid, pic, k) {
if (!pic.fxSpecialObjects || (k >= pic.fxSpecialObjects.arr.length))
return Promise.resolve(false);
return JSROOT.draw(divid, pic.fxSpecialObjects.arr[k], pic.fxSpecialObjects.opt[k]).then(() => drawSpecialObjects(divid, pic, k+1));
}
function drawPictureObjects(divid, pic, k) {
if (!divid || !pic.fxNames)
return Promise.resolve(false);
let arr = pic.fxNames ? pic.fxNames.arr : null;
if (!arr || (k >= arr.length))
return drawSpecialObjects(divid, pic, 0);
let n = pic.fxNames.arr[k], itemname = "", isth2 = false;
JSROOT.hpainter.forEachItem(item => {
if (item._name == n.fString) {
itemname = JSROOT.hpainter.itemFullName(item);
if (item._kind && (item._kind.indexOf("ROOT.TH2") == 0)) isth2 = true;
}
});
if (!itemname) {
console.log('not found object with name', n.fString);
return drawPictureObjects(divid, pic, k+1);
}
// console.log('Want to display item', itemname, 'on', divid);
let opt = isth2 ? "col" : "",
iopt = getOptValue(pic, k, op_Draw);
if ((iopt !== null) && pic.fxOptObjects)
opt = pic.fxOptObjects.arr[iopt].fString;
if (k > 0) opt += " same";
return JSROOT.hpainter.display(itemname, opt + "divid:" + divid).then(painter => {
if (!painter) return;
let need_redraw = false;
if (painter.lineatt) {
let lcol = getOptValue(pic, k, op_LineColor),
lwidth = getOptValue(pic, k, op_LineWidth),
lstyle = getOptValue(pic, k, op_LineStyle);
if ((lcol !== null) && (lwidth !== null) && (lstyle !== null)) {
painter.lineatt.change(painter.getColor(lcol), lwidth, lstyle);
need_redraw = true;
}
}
if (painter.fillatt) {
let fcol = getOptValue(pic, k, op_FillColor),
fstyle = getOptValue(pic, k, op_FillStyle);
if ((fcol !== null) && (fstyle !== null)) {
painter.fillatt.change(fcol, fstyle, painter.getCanvSvg());
need_redraw = true;
}
}
if (typeof painter.getHisto == 'function' && painter.createHistDrawAttributes && painter.isMainPainter()) {
const kNoStats = JSROOT.BIT(9),
kNoTitle = JSROOT.BIT(17);
let histo = painter.getHisto(),
stat = painter.findStat(),
sx1 = getOptDouble(pic, PictureIndex, op_HisStatsX1),
sy1 = getOptDouble(pic, PictureIndex, op_HisStatsY1),
sx2 = getOptDouble(pic, PictureIndex, op_HisStatsX2),
sy2 = getOptDouble(pic, PictureIndex, op_HisStatsY2),
has_stats_pos = (sx1 !== null) && (sy1 !== null) && (sx2!==null) && (sy2!==null),
istitle = getOptValue(pic, PictureIndex, op_HisTitle),
isstats = getOptValue(pic, PictureIndex, op_HisStats),
statsopt = getOptValue(pic, PictureIndex, op_HisStatsOpt),
fitopt = getOptValue(pic, PictureIndex, op_HisStatsFit);
if ((istitle !== null) && (!istitle != histo.TestBit(kNoTitle))) {
histo.InvertBit(kNoTitle); need_redraw = true;
}
if ((isstats !== null) && (!isstats != histo.TestBit(kNoStats))) {
histo.InvertBit(kNoStats); need_redraw = true;
}
if (stat && ((statsopt !== null) || (fitopt !== null) || has_stats_pos)) {
if (statsopt !== null) stat.fOptStat = statsopt;
if (fitopt !== null) stat.fOptFit = fitopt;
let pp = painter.getPadPainter(),
statpainter = pp ? pp.findPainterFor(stat) : null;
if (has_stats_pos) {
stat.fX1NDC = sx1;
stat.fY1NDC = sy1;
stat.fX2NDC = sx2;
stat.fY2NDC = sy2;
}
if (statpainter) statpainter.redraw();
}
}
if (need_redraw) return painter.redraw();
}).then(() => drawPictureObjects(divid, pic, k+1));
}
function drawSubPictures(pad_painter, pic, nsub) {
let arr = pic && pic.fxSubPictures ? pic.fxSubPictures.arr : null;
if (!arr || nsub >= arr.length)
return Promise.resolve(pad_painter);
let subpic = pic.fxSubPictures.arr[nsub];
let subpad_painter = pad_painter.getSubPadPainter(1 + subpic.fiPosY*pic.fiNDivX + subpic.fiPosX);
return drawPicture(subpad_painter, subpic).then(() => drawSubPictures(pad_painter, pic, nsub+1));
}
function drawPicture(pad_painter, pic) {
if (!pad_painter)
return Promise.resolve(false);
let need_divide = pic.fiNDivX * pic.fiNDivY > 1;
if (need_divide && !pad_painter.divide) {
console.log('JSROOT version without TPadPainter.divide');
return Promise.resolve(false);
}
let prev_name = pad_painter.selectCurrentPad(pad_painter.this_pad_name);
if (need_divide)
return pad_painter.divide(pic.fiNDivX, pic.fiNDivY).then(() => drawSubPictures(pad_painter, pic, 0)).then(() => {
pad_painter.selectCurrentPad(prev_name);
return pad_painter;
});
let divid = pad_painter.selectDom().attr('id');
if (!divid) {
divid = "go4picture_div_" + GO4.id_counter++;
pad_painter.selectDom().attr('id', divid);
console.error('Drawing must be done on element with id, force ', divid);
}
return drawPictureObjects(divid, pic, 0).then(() => {
pad_painter.selectCurrentPad(prev_name);
return pad_painter;
});
}
GO4.drawGo4Picture = function(dom, pic) {
if (!JSROOT.hpainter) return null;
let painter = new JSROOT.ObjectPainter(dom, pic);
return JSROOT.require('gpad').then(() => jsrp.ensureTCanvas(painter, false)).then(() => {
let pad_painter = painter.getPadPainter();
painter.removeFromPadPrimitives();
return drawPicture(pad_painter, pic);
}).then(() => painter); // return dummy painter
}
// ==============================================================================
let canvsrc = GO4.source_dir + 'html/go4canvas.js;';
jsrp.addDrawFunc({ name: "TGo4WinCond", script: canvsrc, func: 'GO4.drawGo4Cond', opt: ";editor" });
jsrp.addDrawFunc({ name: "TGo4PolyCond", script: canvsrc, func: 'GO4.drawGo4Cond', opt: ";editor" });
jsrp.addDrawFunc({ name: "TGo4ShapedCond", script: canvsrc, func: 'GO4.drawGo4Cond', opt: ";editor" });
jsrp.addDrawFunc({ name: "TGo4CondArray", script: canvsrc, func: 'GO4.drawCondArray', opt: ";editor" });
jsrp.addDrawFunc({ name: "TGo4Marker", script: canvsrc, func: 'GO4.drawGo4Marker' });
jsrp.addDrawFunc({ name: "TGo4AnalysisWebStatus", script: GO4.source_dir + 'html/analysiseditor.js', func: 'GO4.drawGo4AnalysisStatus', opt: "editor" });
jsrp.addDrawFunc({ name: "TGo4MsgList", func: GO4.DrawMsgList });
jsrp.addDrawFunc({ name: "TGo4Picture", func: GO4.drawGo4Picture, icon: GO4.source_dir + "icons/picture.png" });
jsrp.addDrawFunc({ name: "TGo4MbsEvent", noinspect: true });
jsrp.addDrawFunc({ name: "TGo4EventElement", noinspect: true });
globalThis.GO4 = GO4;
return GO4;
});