import { internals, clTMarker } from '../core.mjs';
import { DrawOptions } from '../base/BasePainter.mjs';
import { ObjectPainter } from '../base/ObjectPainter.mjs';
import { TH1Painter } from '../hist2d/TH1Painter.mjs';
import { draw } from '../draw.mjs';
/**
* @summary Painter for TGraphTime object
*
* @private
*/
class TGraphTimePainter extends ObjectPainter {
#step; // step number
#selfid; // use to identify primitives which should be clean
#wait_animation_frame; // animation flag
#running_timeout; // timeout handle
constructor(dom, gr, opt) {
super(dom, gr, opt);
this.decodeOptions(opt);
this.#selfid = 'grtime_' + internals.id_counter++;
}
/** @summary Redraw object */
redraw() {
if (this.#step === undefined)
this.startDrawing();
}
/** @summary Decode drawing options */
decodeOptions(opt) {
const d = new DrawOptions(opt || 'REPEAT');
this.setOptions({
once: d.check('ONCE'),
repeat: d.check('REPEAT'),
first: d.check('FIRST')
});
this.storeDrawOpt(opt);
}
/** @summary Draw primitives */
async drawPrimitives(indx) {
const lst = this.getObject()?.fSteps.arr[this.#step];
if (!lst || (indx >= lst.arr.length))
return;
const obj = lst.arr[indx],
opt = lst.opt[indx] + (obj._typename === clTMarker ? ';no_interactive' : '');
return draw(this.getPadPainter(), obj, opt).then(p => {
if (p) {
p.$grtimeid = this.#selfid; // indicator that painter created by ourself
p.$grstep = this.#step; // remember step
}
return this.drawPrimitives(indx + 1);
});
}
/** @summary Continue drawing */
continueDrawing() {
const gr = this.getObject(),
o = this.getOptions();
if (o.first) {
// draw only single frame, cancel all others
this.#step = undefined;
return;
}
if (this.#wait_animation_frame) {
this.#wait_animation_frame = undefined;
// clear pad
const pp = this.getPadPainter();
if (!pp) {
// most probably, pad is cleared
this.#step = undefined;
return;
}
// draw primitives again
this.drawPrimitives(0).then(() => {
// clear primitives produced by previous drawing to avoid flicking
pp.cleanPrimitives(p => { return (p.$grtimeid === this.#selfid) && (p.$grstep !== this.#step); });
this.continueDrawing();
});
} else if (this.#running_timeout) {
clearTimeout(this.#running_timeout);
this.#running_timeout = undefined;
this.#wait_animation_frame = true;
// use animation frame to disable update in inactive form
requestAnimationFrame(() => this.continueDrawing());
} else {
let sleeptime = Math.max(gr.fSleepTime, 10);
if (++this.#step > gr.fSteps.arr.length) {
if (o.repeat) {
this.#step = 0; // start again
sleeptime = Math.max(5000, 5*sleeptime); // increase sleep time
} else {
this.#step = undefined; // clear indicator that animation running
return;
}
}
this.#running_timeout = setTimeout(() => this.continueDrawing(), sleeptime);
}
}
/** @summary Start drawing of TGraphTime */
startDrawing() {
this.#step = 0;
return this.drawPrimitives(0).then(() => {
this.continueDrawing();
return this;
});
}
/** @summary Draw TGraphTime object */
static async draw(dom, gr, opt) {
if (!gr.fFrame) {
console.error('Frame histogram not exists');
return null;
}
const painter = new TGraphTimePainter(dom, gr, opt);
if (painter.getMainPainter()) {
console.error('Cannot draw graph time on top of other histograms');
return null;
}
if (!gr.fFrame.fTitle && gr.fTitle) {
const arr = gr.fTitle.split(';');
gr.fFrame.fTitle = arr[0];
if (arr[1]) gr.fFrame.fXaxis.fTitle = arr[1];
if (arr[2]) gr.fFrame.fYaxis.fTitle = arr[2];
}
return TH1Painter.draw(dom, gr.fFrame, '').then(() => {
painter.addToPadPrimitives();
return painter.startDrawing();
});
}
} // class TGraphTimePainter
/** @summary Draw TRooPlot
* @private */
async function drawRooPlot(dom, plot) {
return draw(dom, plot._hist, 'hist').then(async hp => {
const arr = [];
for (let i = 0; i < plot._items.arr.length; ++i)
arr.push(draw(dom, plot._items.arr[i], plot._items.opt[i]));
return Promise.all(arr).then(() => hp);
});
}
export { TGraphTimePainter, drawRooPlot };