Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
TWebCanvas.cxx
Go to the documentation of this file.
1// Author: Sergey Linev, GSI 7/12/2016
2
3/*************************************************************************
4 * Copyright (C) 1995-2023, Rene Brun and Fons Rademakers. *
5 * All rights reserved. *
6 * *
7 * For the licensing terms see $ROOTSYS/LICENSE. *
8 * For the list of contributors see $ROOTSYS/README/CREDITS. *
9 *************************************************************************/
10
11#include "TWebCanvas.h"
12
13#include "TWebSnapshot.h"
14#include "TWebPadPainter.h"
15#include "TWebPS.h"
16#include "TWebMenuItem.h"
18#include "THttpServer.h"
19
20#include "TSystem.h"
21#include "TStyle.h"
22#include "TCanvas.h"
23#include "TButton.h"
24#include "TFrame.h"
25#include "TPaveText.h"
26#include "TPaveStats.h"
27#include "TText.h"
28#include "TROOT.h"
29#include "TClass.h"
30#include "TColor.h"
31#include "TObjArray.h"
32#include "TArrayI.h"
33#include "TList.h"
34#include "TF1.h"
35#include "TF2.h"
36#include "TH1.h"
37#include "TH2.h"
38#include "TH1K.h"
39#include "THStack.h"
40#include "TMultiGraph.h"
41#include "TEnv.h"
42#include "TError.h"
43#include "TGraph.h"
44#include "TGraph2D.h"
45#include "TGaxis.h"
46#include "TScatter.h"
47#include "TCutG.h"
48#include "TBufferJSON.h"
49#include "TBase64.h"
50#include "TAtt3D.h"
51#include "TView.h"
52#include "TExec.h"
53#include "TVirtualX.h"
54#include "TMath.h"
55#include "TTimer.h"
56#include "TThread.h"
57
58#include <cstdio>
59#include <cstring>
60#include <fstream>
61#include <iostream>
62#include <memory>
63#include <sstream>
64#include <vector>
65
66
67class TWebCanvasTimer : public TTimer {
72public:
74
75 Bool_t IsSlow() const { return fSlow; }
76 void SetSlow(Bool_t slow = kTRUE)
77 {
78 fSlow = slow;
79 fSlowCnt = 0;
80 SetTime(slow ? 1000 : 10);
81 }
82
83 /// used to send control messages to clients
84 void Timeout() override
85 {
86 if (fProcessing || fCanv.fProcessingData) return;
90 if (res) {
91 fSlowCnt = 0;
92 } else if (++fSlowCnt > 10 && !IsSlow()) {
94 }
95 }
96};
97
98
99/** \class TWebCanvas
100\ingroup webgui6
101
102Basic TCanvasImp ABI implementation for Web-based Graphics
103Provides painting of main ROOT classes in web browsers using [JSROOT](https://root.cern/js/)
104
105Following settings parameters can be useful for TWebCanvas:
106
107 WebGui.FullCanvas: 1 read-only mode (0), full-functional canvas (1) (default - 1)
108 WebGui.StyleDelivery: 1 provide gStyle object to JSROOT client (default - 1)
109 WebGui.PaletteDelivery: 1 provide color palette to JSROOT client (default - 1)
110 WebGui.TF1UseSave: 1 used saved values for function drawing: 0 - off, 1 - if client fail to evaluate function, 2 - always (default - 1)
111
112TWebCanvas is used by default in interactive ROOT session. To use web-based canvas in batch mode for image
113generation, one should explicitly specify `--web` option when starting ROOT:
114
115 [shell] root -b --web tutorials/hsimple.root -e 'hpxpy->Draw("colz"); c1->SaveAs("image.png");'
116
117If for any reasons TWebCanvas does not provide required functionality, one always can disable it.
118Either by specifying `root --web=off` when starting ROOT or by setting `Canvas.Name: TRootCanvas` in rootrc file.
119
120*/
121
122using namespace std::string_literals;
123
124static const std::string sid_pad_histogram = "__pad_histogram__";
125
126
127struct WebFont_t {
132 WebFont_t() = default;
133 WebFont_t(Int_t indx, const TString &name, const TString &fmt, const TString &data) : fIndx(indx), fName(name), fFormat(fmt), fData(data) {}
134};
135
136static std::vector<WebFont_t> gWebFonts;
137
138std::string TWebCanvas::gCustomScripts = {};
139std::vector<std::string> TWebCanvas::gCustomClasses = {};
140
143std::vector<std::string> TWebCanvas::gBatchFiles;
144std::vector<std::string> TWebCanvas::gBatchJsons;
145std::vector<int> TWebCanvas::gBatchWidths;
146std::vector<int> TWebCanvas::gBatchHeights;
147
148//////////////////////////////////////////////////////////////////////////////////////////////////
149/// Configure batch image mode for web graphics.
150/// Allows to process many images with single headless browser invocation and increase performance of image production.
151/// When many canvases are stored as image in difference places, they first collected in batch and then processed when at least `n`
152/// images are prepared. Only then headless browser invoked and create all these images at once.
153/// This allows to significantly increase performance of image production in web mode
154
156{
158 if (gBatchImageMode <= gBatchJsons.size())
160}
161
162//////////////////////////////////////////////////////////////////////////////////////////////////
163/// Flush batch images
164
166{
167 bool res = true;
168
169 if (gBatchJsons.size() > 0)
171
172 gBatchFiles.clear();
173 gBatchJsons.clear();
174 gBatchWidths.clear();
175 gBatchHeights.clear();
176
177 return res;
178}
179
180////////////////////////////////////////////////////////////////////////////////
181/// Constructor
182
184 : TCanvasImp(c, name, x, y, width, height)
185{
186 // Workaround for multi-threaded environment
187 // Ensure main thread id picked when canvas implementation is created -
188 // otherwise it may be assigned in other thread and screw-up gPad access.
189 // Workaround may not work if main thread id was wrongly initialized before
190 // This resolves issue https://github.com/root-project/root/issues/15498
192
193 fTimer = new TWebCanvasTimer(*this);
194
195 fReadOnly = readonly;
196 fStyleDelivery = gEnv->GetValue("WebGui.StyleDelivery", 1);
197 fPaletteDelivery = gEnv->GetValue("WebGui.PaletteDelivery", 1);
198 fPrimitivesMerge = gEnv->GetValue("WebGui.PrimitivesMerge", 100);
199 fTF1UseSave = gEnv->GetValue("WebGui.TF1UseSave", (Int_t) 1);
201
202 fWebConn.emplace_back(0); // add special connection which only used to perform updates
203
204 fTimer->TurnOn();
205
206 // fAsyncMode = kTRUE;
207}
208
209
210////////////////////////////////////////////////////////////////////////////////
211/// Destructor
212
214{
215 delete fTimer;
216}
217
218
219//////////////////////////////////////////////////////////////////////////////////////////////////
220/// Add font to static list of fonts supported by the canvas
221/// Name specifies name of the font, second is font file with .ttf or .woff2 extension
222/// Only True Type Fonts (ttf) are supported by PDF
223/// Returns font index which can be used in
224/// auto font_indx = TWebCanvas::AddFont("test", "test.ttf", 2);
225/// gStyle->SetStatFont(font_indx);
226
227Font_t TWebCanvas::AddFont(const char *name, const char *fontfile, Int_t precision)
228{
229 Font_t maxindx = 22;
230 for (auto &entry : gWebFonts) {
231 if (entry.fName == name)
232 return precision > 0 ? entry.fIndx*10 + precision : entry.fIndx;
233 if (entry.fIndx > maxindx)
234 maxindx = entry.fIndx;
235 }
236
237 TString fullname = fontfile, fmt = "ttf";
238 auto pos = fullname.Last('.');
239 if (pos != kNPOS) {
240 fmt = fullname(pos+1, fullname.Length() - pos);
241 fmt.ToLower();
242 if ((fmt != "ttf") && (fmt != "woff2")) {
243 ::Error("TWebCanvas::AddFont", "Unsupported font file extension %s", fmt.Data());
244 return (Font_t) -1;
245 }
246 }
247
248 gSystem->ExpandPathName(fullname);
249
250 if (gSystem->AccessPathName(fullname.Data(), kReadPermission)) {
251 ::Error("TWebCanvas::AddFont", "Not possible to read font file %s", fullname.Data());
252 return (Font_t) -1;
253 }
254
255 std::ifstream is(fullname.Data(), std::ios::in | std::ios::binary);
256 std::string res;
257 if (is) {
258 is.seekg(0, std::ios::end);
259 res.resize(is.tellg());
260 is.seekg(0, std::ios::beg);
261 is.read((char *)res.data(), res.length());
262 if (!is)
263 res.clear();
264 }
265
266 if (res.empty()) {
267 ::Error("TWebCanvas::AddFont", "Fail to read font file %s", fullname.Data());
268 return (Font_t) -1;
269 }
270
271 TString base64 = TBase64::Encode(res.c_str(), res.length());
272
273 maxindx++;
274
275 gWebFonts.emplace_back(maxindx, name, fmt, base64);
276
277 return precision > 0 ? maxindx*10 + precision : maxindx;
278}
279
280////////////////////////////////////////////////////////////////////////////////
281/// Initialize window for the web canvas
282/// At this place canvas is not yet register to the list of canvases - one cannot call RWebWindow::Show()
283
285{
286 return 111222333; // should not be used at all
287}
288
289////////////////////////////////////////////////////////////////////////////////
290/// Creates web-based pad painter
291
293{
294 return new TWebPadPainter();
295}
296
297////////////////////////////////////////////////////////////////////////////////
298/// Returns kTRUE when object is fully supported on JSROOT side
299/// In ROOT7 Paint function will just return appropriate flag that object can be displayed on JSROOT side
300
302{
303 if (!obj)
304 return kTRUE;
305
306 static const struct {
307 const char *name{nullptr};
308 bool with_derived{false};
309 bool reduse_by_many{false};
310 } supported_classes[] = {{"TH1", true},
311 {"TF1", true},
312 {"TGraph", true},
313 {"TScatter"},
314 {"TFrame"},
315 {"THStack"},
316 {"TMultiGraph"},
317 {"TGraphPolargram", true},
318 {"TPave", true},
319 {"TGaxis"},
320 {"TPave", true},
321 {"TArrow"},
322 {"TBox", false, true}, // can be handled via TWebPainter, disable for large number of primitives (like in greyscale.C)
323 {"TWbox"}, // some extra calls which cannot be handled via TWebPainter
324 {"TLine", false, true}, // can be handler via TWebPainter, disable for large number of primitives (like in greyscale.C)
325 {"TEllipse", true, true}, // can be handled via TWebPainter, disable for large number of primitives (like in greyscale.C)
326 {"TText"},
327 {"TLatex"},
328 {"TAnnotation"},
329 {"TMathText"},
330 {"TMarker"},
331 {"TPolyMarker"},
332 {"TPolyLine", true, true}, // can be handled via TWebPainter, simplify colors handling
333 {"TPolyMarker3D"},
334 {"TPolyLine3D"},
335 {"TGraphTime"},
336 {"TGraph2D"},
337 {"TGraph2DErrors"},
338 {"TGraphTime"},
339 {"TASImage"},
340 {"TRatioPlot"},
341 {"TSpline"},
342 {"TSpline3"},
343 {"TSpline5"},
344 {"TGeoManager"},
345 {"TGeoVolume"},
346 {}};
347
348 // fast check of class name
349 for (int i = 0; supported_classes[i].name != nullptr; ++i)
350 if ((!many_primitives || !supported_classes[i].reduse_by_many) && (strcmp(supported_classes[i].name, obj->ClassName()) == 0))
351 return kTRUE;
352
353 // now check inheritance only for configured classes
354 for (int i = 0; supported_classes[i].name != nullptr; ++i)
355 if (supported_classes[i].with_derived && (!many_primitives || !supported_classes[i].reduse_by_many))
356 if (obj->InheritsFrom(supported_classes[i].name))
357 return kTRUE;
358
359 return IsCustomClass(obj->IsA());
360}
361
362//////////////////////////////////////////////////////////////////////////////////////////////////
363/// Configures custom script for canvas.
364/// If started with "modules:" prefix, module(s) will be imported with `loadModules` function of JSROOT.
365/// If custom path was configured in RWebWindowsManager::AddServerLocation, it can be used in module paths.
366/// If started with "load:" prefix, code will be loaded with `loadScript` function of JSROOT (old, deprecated way)
367/// Script also can be a plain JavaScript code which imports JSROOT and provides draw function for custom classes
368/// See tutorials/webgui/custom/custom.mjs demonstrating such example
369
370void TWebCanvas::SetCustomScripts(const std::string &src)
371{
373}
374
375//////////////////////////////////////////////////////////////////////////////////////////////////
376/// Returns configured custom script
377
379{
380 return gCustomScripts;
381}
382
383//////////////////////////////////////////////////////////////////////////////////////////////////
384/// For batch mode special handling of scripts are required
385/// Headless browser not able to load modules from the file system
386/// Therefore custom web-canvas modules and scripts has to be loaded in advance and processed
387
388std::string TWebCanvas::ProcessCustomScripts(bool batch)
389{
390 if (!batch || gCustomScripts.empty() || (gCustomScripts.find("modules:") != 0))
391 return gCustomScripts;
392
394
395 std::string content;
396
397 std::string modules_names = gCustomScripts.substr(8);
398
399 std::map<std::string, bool> mapped_funcs;
400
401 while (!modules_names.empty()) {
402 std::string modname;
403 auto p = modules_names.find(";");
404 if (p == std::string::npos) {
405 modname = modules_names;
406 modules_names.clear();
407 } else {
408 modname = modules_names.substr(0, p);
409 modules_names = modules_names.substr(p+1);
410 }
411
412 p = modname.find("/");
413 if ((p == std::string::npos) || modname.empty())
414 continue;
415
416 std::string pathname = modname.substr(0, p+1);
417 std::string filename = modname.substr(p+1);
418
419 auto fpath = loc[pathname];
420
421 if (fpath.empty())
422 continue;
423
424 auto cont = THttpServer::ReadFileContent(fpath + filename);
425 if (cont.empty())
426 continue;
427
428 // check that special mark is in the script
429 auto pmark = cont.find("$$jsroot_batch_conform$$");
430 if (pmark == std::string::npos)
431 continue;
432
433 // process line like this
434 // import { ObjectPainter, addMoveHandler, addDrawFunc, ensureTCanvas } from 'jsroot';
435
436 static const std::string str1 = "import {";
437 static const std::string str2 = "} from 'jsroot';";
438
439 auto p1 = cont.find(str1);
440 auto p2 = cont.find(str2, p1);
441 if ((p1 == std::string::npos) || (p2 == std::string::npos) || (p2 > pmark))
442 continue;
443
444 TString globs;
445
446 TString funcs = cont.substr(p1 + 8, p2 - p1 - 8).c_str();
447 auto arr = funcs.Tokenize(",");
448
449 TIter next(arr);
450 while (auto obj = next()) {
451 TString name = obj->GetName();
453 if (!mapped_funcs[name.Data()]) {
454 globs.Append(TString::Format("globalThis.%s = JSROOT.%s;\n", name.Data(), name.Data()));
455 mapped_funcs[name.Data()] = true;
456 }
457 }
458 delete arr;
459
460 cont.erase(p1, p2 + str2.length() - p1);
461
462 cont.insert(p1, globs.Data());
463
464 content.append(cont);
465 }
466
467 return content;
468}
469
470
471//////////////////////////////////////////////////////////////////////////////////////////////////
472/// Assign custom class
473
474void TWebCanvas::AddCustomClass(const std::string &clname, bool with_derived)
475{
476 if (with_derived)
477 gCustomClasses.emplace_back("+"s + clname);
478 else
479 gCustomClasses.emplace_back(clname);
480}
481
482//////////////////////////////////////////////////////////////////////////////////////////////////
483/// Checks if class belongs to custom
484
486{
487 for (auto &name : gCustomClasses) {
488 if (name[0] == '+') {
489 if (cl->InheritsFrom(name.substr(1).c_str()))
490 return true;
491 } else if (name.compare(cl->GetName()) == 0) {
492 return true;
493 }
494 }
495 return false;
496}
497
498//////////////////////////////////////////////////////////////////////////////////////////////////
499/// Creates representation of the object for painting in web browser
500
501void TWebCanvas::CreateObjectSnapshot(TPadWebSnapshot &master, TPad *pad, TObject *obj, const char *opt, TWebPS *masterps)
502{
503 if (IsJSSupportedClass(obj, masterps != nullptr)) {
504 master.NewPrimitive(obj, opt).SetSnapshot(TWebSnapshot::kObject, obj);
505 return;
506 }
507
508 // painter is not necessary for batch canvas, but keep configuring it for a while
509 auto *painter = dynamic_cast<TWebPadPainter *>(Canvas()->GetCanvasPainter());
510
511 TView *view = nullptr;
512
514
515 gPad = pad;
516
517 if (obj->InheritsFrom(TAtt3D::Class()) && !pad->GetView()) {
518 pad->GetViewer3D("pad");
519 view = TView::CreateView(1, 0, 0); // Cartesian view by default
520 pad->SetView(view);
521
522 // Set view to perform first auto-range (scaling) pass
523 view->SetAutoRange(kTRUE);
524 }
525
526 TVirtualPS *saveps = gVirtualPS;
527
528 TWebPS ps;
529 gVirtualPS = masterps ? masterps : &ps;
530 if (painter)
531 painter->SetPainting(ps.GetPainting());
532
533 // calling Paint function for the object
534 obj->Paint(opt);
535
536 if (view) {
537 view->SetAutoRange(kFALSE);
538 // call 3D paint once again to make real drawing
539 obj->Paint(opt);
540 pad->SetView(nullptr);
541 }
542
543 if (painter)
544 painter->SetPainting(nullptr);
545
546 gVirtualPS = saveps;
547
548 fPadsStatus[pad]._has_specials = true;
549
550 // if there are master PS, do not create separate entries
551 if (!masterps && !ps.IsEmptyPainting())
553}
554
555//////////////////////////////////////////////////////////////////////////////////////////////////
556/// Calculate hash function for all colors and palette
557
559{
560 UInt_t hash = 0;
561
562 TObjArray *colors = (TObjArray *)gROOT->GetListOfColors();
563
564 if (colors) {
565 for (Int_t n = 0; n <= colors->GetLast(); ++n)
566 if (colors->At(n))
567 hash += TString::Hash(colors->At(n), TColor::Class()->Size());
568 }
569
571
572 hash += TString::Hash(pal.GetArray(), pal.GetSize() * sizeof(Int_t));
573
574 return hash;
575}
576
577
578//////////////////////////////////////////////////////////////////////////////////////////////////
579/// Add special canvas objects with list of colors and color palette
580
582{
583 TObjArray *colors = (TObjArray *)gROOT->GetListOfColors();
584
585 if (!colors)
586 return;
587
588 //Int_t cnt = 0;
589 //for (Int_t n = 0; n <= colors->GetLast(); ++n)
590 // if (colors->At(n))
591 // cnt++;
592 //if (cnt <= 598)
593 // return; // normally there are 598 colors defined
594
596
597 auto listofcols = new TWebPainting;
598 for (Int_t n = 0; n <= colors->GetLast(); ++n)
599 listofcols->AddColor(n, (TColor *)colors->At(n));
600
601 // store palette in the buffer
602 auto *tgt = listofcols->Reserve(pal.GetSize());
603 for (Int_t i = 0; i < pal.GetSize(); i++)
604 tgt[i] = pal[i];
605 listofcols->FixSize();
606
607 master.NewSpecials().SetSnapshot(TWebSnapshot::kColors, listofcols, kTRUE);
608}
609
610//////////////////////////////////////////////////////////////////////////////////////////////////
611/// Add special canvas objects with custom fonts
612
614{
615 for (auto &entry : gWebFonts) {
616 TString code = TString::Format("%d:%s:%s:%s", entry.fIndx, entry.fName.Data(), entry.fFormat.Data(), entry.fData.Data());
617 auto custom_font = new TWebPainting;
618 custom_font->AddOper(code.Data());
619 master.NewSpecials().SetSnapshot(TWebSnapshot::kFont, custom_font, kTRUE);
620 }
621}
622
623//////////////////////////////////////////////////////////////////////////////////////////////////
624/// Create snapshot for pad and all primitives
625/// Callback function is used to create JSON in the middle of data processing -
626/// when all misc objects removed from canvas list of primitives or histogram list of functions
627/// After that objects are moved back to their places
628
630{
631 auto &pad_status = fPadsStatus[pad];
632
633 // send primitives if version 0 or actual pad version grater than already send version
634 bool process_primitives = (version == 0) || (pad_status.fVersion > version);
635
636 if (paddata.IsSetObjectIds()) {
637 paddata.SetActive(pad == gPad);
638 paddata.SetObjectIDAsPtr(pad);
639 }
640 paddata.SetSnapshot(TWebSnapshot::kSubPad, pad); // add ref to the pad
641 paddata.SetWithoutPrimitives(!process_primitives);
642 paddata.SetHasExecs(pad->GetListOfExecs()); // if pad execs are there provide more events from client
643
644 // check style changes every time when creating canvas snapshot
645 if (resfunc && (GetStyleDelivery() > 0)) {
646
648 auto hash = TString::Hash(gStyle, TStyle::Class()->Size());
649 if ((hash != fStyleHash) || (fStyleVersion == 0)) {
650 fStyleHash = hash;
652 }
653 }
654
655 if (fStyleVersion > version)
657 }
658
659 // for the first time add custom fonts to the canvas snapshot
660 if (resfunc && (version == 0))
661 AddCustomFonts(paddata);
662
663 fAllPads.emplace_back(pad);
664
665 TList *primitives = pad->GetListOfPrimitives();
666
667 TWebPS masterps;
668 bool usemaster = primitives ? (primitives->GetSize() > fPrimitivesMerge) : false;
669
670 TIter iter(primitives);
671 TObject *obj = nullptr;
672 TFrame *frame = nullptr;
673 TPaveText *title = nullptr;
674 bool need_frame = false, has_histo = false, need_palette = false;
675 std::string need_title;
676
677 auto checkNeedPalette = [](TH1* hist, const TString &opt) {
678 auto check = [&opt](const TString &arg) {
679 return opt.Contains(arg + "Z") || opt.Contains(arg + "HZ");
680 };
681
682 return ((hist->GetDimension() == 2) && (check("COL") || check("LEGO") || check("LEGO4") || check("SURF2"))) ||
683 ((hist->GetDimension() == 3) && (check("BOX2") || check("BOX3")));
684 };
685
686 while (process_primitives && ((obj = iter()) != nullptr)) {
687 TString opt = iter.GetOption();
688 opt.ToUpper();
689
690 if (obj->InheritsFrom(THStack::Class())) {
691 // workaround for THStack, create extra components before sending to client
692 if (!opt.Contains("PADS") && !opt.Contains("SAME")) {
693 Bool_t do_rebuild_stack = kFALSE;
694
695 auto hs = static_cast<THStack *>(obj);
696
697 if (!opt.Contains("NOSTACK") && !opt.Contains("CANDLE") && !opt.Contains("VIOLIN") && !IsReadOnly() && !fUsedObjs[hs]) {
698 do_rebuild_stack = kTRUE;
699 fUsedObjs[hs] = true;
700 }
701
702 if (strlen(obj->GetTitle()) > 0)
703 need_title = obj->GetTitle();
704 TVirtualPad::TContext ctxt(pad, kFALSE);
705 hs->BuildPrimitives(iter.GetOption(), do_rebuild_stack);
706 has_histo = true;
707 need_frame = true;
708 }
709 } else if (obj->InheritsFrom(TMultiGraph::Class())) {
710 // workaround for TMultiGraph
711 if (opt.Contains("A")) {
712 auto mg = static_cast<TMultiGraph *>(obj);
714 mg->GetHistogram(); // force creation of histogram without any drawings
715 has_histo = true;
716 if (strlen(obj->GetTitle()) > 0)
717 need_title = obj->GetTitle();
718 need_frame = true;
719 }
720 } else if (obj->InheritsFrom(TFrame::Class())) {
721 if (!frame)
722 frame = static_cast<TFrame *>(obj);
723 } else if (obj->InheritsFrom(TH1::Class())) {
724 need_frame = true;
725 has_histo = true;
726 if (!obj->TestBit(TH1::kNoTitle) && !opt.Contains("SAME") && !opt.Contains("AXIS") && !opt.Contains("AXIG") && (strlen(obj->GetTitle()) > 0))
727 need_title = obj->GetTitle();
728 if (checkNeedPalette(static_cast<TH1*>(obj), opt))
729 need_palette = true;
730 } else if (obj->InheritsFrom(TGraph::Class())) {
731 if (opt.Contains("A")) {
732 need_frame = true;
733 if (!has_histo && (strlen(obj->GetTitle()) > 0))
734 need_title = obj->GetTitle();
735 }
736 } else if (obj->InheritsFrom(TGraph2D::Class())) {
737 if (!has_histo && (strlen(obj->GetTitle()) > 0))
738 need_title = obj->GetTitle();
739 } else if (obj->InheritsFrom(TScatter::Class())) {
740 need_frame = need_palette = true;
741 if (strlen(obj->GetTitle()) > 0)
742 need_title = obj->GetTitle();
743 } else if (obj->InheritsFrom(TF1::Class())) {
744 need_frame = !obj->InheritsFrom(TF2::Class());
745 if (!has_histo && (strlen(obj->GetTitle()) > 0))
746 need_title = obj->GetTitle();
747 } else if (obj->InheritsFrom(TPaveText::Class())) {
748 if (strcmp(obj->GetName(), "title") == 0)
749 title = static_cast<TPaveText *>(obj);
750 }
751 }
752
753 if (need_frame && !frame && primitives && CanCreateObject("TFrame")) {
754 if (!IsReadOnly() && need_palette && (pad->GetRightMargin() < 0.12) && (pad->GetRightMargin() == gStyle->GetPadRightMargin()))
755 pad->SetRightMargin(0.12);
756
757 frame = pad->GetFrame();
758 if(frame)
759 primitives->AddFirst(frame);
760 }
761
762 if (!need_title.empty() && gStyle->GetOptTitle()) {
763 if (title) {
764 auto line0 = title->GetLine(0);
765 if (line0 && !IsReadOnly()) line0->SetTitle(need_title.c_str());
766 } else if (primitives && CanCreateObject("TPaveText")) {
767 title = new TPaveText(0, 0, 0, 0, "blNDC");
770 title->SetName("title");
773 title->SetTextFont(gStyle->GetTitleFont(""));
774 if (gStyle->GetTitleFont("") % 10 > 2)
776 title->AddText(need_title.c_str());
777 title->SetBit(kCanDelete);
778 primitives->Add(title);
779 }
780 }
781
782 auto flush_master = [&]() {
783 if (!usemaster || masterps.IsEmptyPainting()) return;
784
786 masterps.CreatePainting(); // create for next operations
787 };
788
789 auto check_cutg_in_options = [&](const TString &opt) {
790 auto p1 = opt.Index("["), p2 = opt.Index("]");
791 if ((p1 != kNPOS) && (p2 != kNPOS) && p2 > p1 + 1) {
792 TString cutname = opt(p1 + 1, p2 - p1 - 1);
793 TObject *cutg = primitives->FindObject(cutname.Data());
794 if (!cutg || (cutg->IsA() != TCutG::Class())) {
795 cutg = gROOT->GetListOfSpecials()->FindObject(cutname.Data());
796 if (cutg && cutg->IsA() == TCutG::Class())
797 paddata.NewPrimitive(cutg, "__ignore_drawing__").SetSnapshot(TWebSnapshot::kObject, cutg);
798 }
799 }
800 };
801
802 auto check_save_tf1 = [&](TObject *fobj, bool ignore_nodraw = false) {
803 if (!paddata.IsBatchMode() && (fTF1UseSave <= 0))
804 return;
805 if (!ignore_nodraw && fobj->TestBit(TF1::kNotDraw))
806 return;
807
808 auto f1 = static_cast<TF1 *>(fobj);
809 // check if TF1 can be used
810 if (!f1->IsValid())
811 return;
812
813 // in default case save buffer used as is
814 if ((fTF1UseSave == 1) && f1->HasSave())
815 return;
816
817 f1->Save(0, 0, 0, 0, 0, 0);
818 };
819
820 auto create_stats = [&]() {
821 TPaveStats *stats = nullptr;
822 if ((gStyle->GetOptStat() > 0) && CanCreateObject("TPaveStats")) {
823 stats = new TPaveStats(
826 gStyle->GetStatX(),
827 gStyle->GetStatY(), "brNDC");
828
829 // do not set optfit and optstat, they calling pad->Update,
830 // values correctly set already in TPaveStats constructor
831 // stats->SetOptFit(gStyle->GetOptFit());
832 // stats->SetOptStat(gStyle->GetOptStat());
836 stats->SetTextFont(gStyle->GetStatFont());
837 if (gStyle->GetStatFont()%10 > 2)
841 stats->SetName("stats");
842
844 stats->SetTextAlign(12);
845 stats->SetBit(kCanDelete);
846 stats->SetBit(kMustCleanup);
847 }
848
849 return stats;
850 };
851
852 auto check_graph_funcs = [&](TGraph *gr, TList *funcs = nullptr) {
853 if (!funcs && gr)
855 if (!funcs)
856 return;
857
858 TIter fiter(funcs);
859 TPaveStats *stats = nullptr;
860 bool has_tf1 = false;
861
862 while (auto fobj = fiter()) {
863 if (fobj->InheritsFrom(TPaveStats::Class()))
864 stats = dynamic_cast<TPaveStats *> (fobj);
865 else if (fobj->InheritsFrom(TF1::Class())) {
866 check_save_tf1(fobj);
867 has_tf1 = true;
868 }
869 }
870
871 if (!stats && has_tf1 && gr && !gr->TestBit(TGraph::kNoStats)) {
872 stats = create_stats();
873 if (stats) {
874 stats->SetParent(funcs);
875 funcs->Add(stats);
876 }
877 }
878 };
879
880 iter.Reset();
881
882 bool first_obj = true;
883
884 if (process_primitives)
885 pad_status._has_specials = false;
886
887 while ((obj = iter()) != nullptr) {
888 if (obj->InheritsFrom(TPad::Class())) {
889 flush_master();
890 CreatePadSnapshot(paddata.NewSubPad(), (TPad *)obj, version, nullptr);
891 } else if (!process_primitives) {
892 continue;
893 } else if (obj->InheritsFrom(TH1K::Class())) {
894 flush_master();
895 TH1K *hist = static_cast<TH1K *>(obj);
896
897 Int_t nbins = hist->GetXaxis()->GetNbins();
898
899 TH1D *h1 = new TH1D("__dummy_name__", hist->GetTitle(), nbins, hist->GetXaxis()->GetXmin(), hist->GetXaxis()->GetXmax());
900 h1->SetDirectory(nullptr);
901 h1->SetName(hist->GetName());
902 hist->TAttLine::Copy(*h1);
903 hist->TAttFill::Copy(*h1);
904 hist->TAttMarker::Copy(*h1);
905 for (Int_t n = 1; n <= nbins; ++n)
906 h1->SetBinContent(n, hist->GetBinContent(n));
907
908 TIter fiter(hist->GetListOfFunctions());
909 while (auto fobj = fiter())
910 h1->GetListOfFunctions()->Add(fobj->Clone());
911
913
914 } else if (obj->InheritsFrom(TH1::Class())) {
915 flush_master();
916
917 TH1 *hist = static_cast<TH1 *>(obj);
918 hist->BufferEmpty();
919
920 TPaveStats *stats = nullptr;
921 TObject *palette = nullptr;
922
923 TIter fiter(hist->GetListOfFunctions());
924 while (auto fobj = fiter()) {
925 if (fobj->InheritsFrom(TPaveStats::Class()))
926 stats = dynamic_cast<TPaveStats *> (fobj);
927 else if (fobj->InheritsFrom("TPaletteAxis"))
928 palette = fobj;
929 else if (fobj->InheritsFrom(TF1::Class()))
930 check_save_tf1(fobj);
931 }
932
933 TString hopt = iter.GetOption();
934 TString o = hopt;
935 o.ToUpper();
936
937 if (!stats && (first_obj || o.Contains("SAMES"))) {
938 stats = create_stats();
939 if (stats) {
940 stats->SetParent(hist);
941 hist->GetListOfFunctions()->Add(stats);
942 }
943 }
944
945 if (!palette && CanCreateObject("TPaletteAxis") && checkNeedPalette(hist, o)) {
946 std::stringstream exec;
947 exec << "new TPaletteAxis(0,0,0,0, (TH1*)" << std::hex << std::showbase << (size_t)hist << ");";
948 palette = (TObject *)gROOT->ProcessLine(exec.str().c_str());
949 if (palette)
950 hist->GetListOfFunctions()->AddFirst(palette);
951 }
952
953 paddata.NewPrimitive(obj, hopt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
954
955 if (hist->GetDimension() == 2)
956 check_cutg_in_options(iter.GetOption());
957
958 first_obj = false;
959 } else if (obj->InheritsFrom(TGraph::Class())) {
960 flush_master();
961
962 TGraph *gr = static_cast<TGraph *>(obj);
963
964 check_graph_funcs(gr);
965
966 TString gropt = iter.GetOption();
967
968 // ensure histogram exists on server to draw it properly on clients side
969 if (!IsReadOnly() && (first_obj || gropt.Index("A", 0, TString::kIgnoreCase) != kNPOS ||
970 (gropt.Index("X+", 0, TString::kIgnoreCase) != kNPOS) || (gropt.Index("X+", 0, TString::kIgnoreCase) != kNPOS)))
971 gr->GetHistogram();
972
973 paddata.NewPrimitive(obj, gropt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
974
975 first_obj = false;
976 } else if (obj->InheritsFrom(TGraph2D::Class())) {
977 flush_master();
978
979 TGraph2D *gr2d = static_cast<TGraph2D *>(obj);
980
981 check_graph_funcs(nullptr, gr2d->GetListOfFunctions());
982
983 // ensure correct range of histogram
984 if (!IsReadOnly() && first_obj) {
985 TString gropt = iter.GetOption();
986 gropt.ToUpper();
987 Bool_t zscale = gropt.Contains("TRI1") || gropt.Contains("TRI2") || gropt.Contains("COL");
988 Bool_t real_draw = gropt.Contains("TRI") || gropt.Contains("LINE") || gropt.Contains("ERR") || gropt.Contains("P0");
989
990 TString hopt = !real_draw ? iter.GetOption() : (zscale ? "lego2z" : "lego2");
991 if (title) hopt.Append(";;use_pad_title");
992
993 // if gr2d not draw - let create histogram with correspondent content
994 auto hist = gr2d->GetHistogram(real_draw ? "empty" : "");
995
996 paddata.NewPrimitive(gr2d, hopt.Data(), "#hist").SetSnapshot(TWebSnapshot::kObject, hist);
997 }
998
999 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1000 first_obj = false;
1001 } else if (obj->InheritsFrom(TMultiGraph::Class())) {
1002 flush_master();
1003
1004 TMultiGraph *mgr = static_cast<TMultiGraph *>(obj);
1005 TIter fiter(mgr->GetListOfFunctions());
1006 while (auto fobj = fiter()) {
1007 if (fobj->InheritsFrom(TF1::Class()))
1008 check_save_tf1(fobj);
1009 }
1010
1011 TIter giter(mgr->GetListOfGraphs());
1012 while (auto gobj = giter())
1013 check_graph_funcs(static_cast<TGraph *>(gobj));
1014
1015 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1016
1017 first_obj = false;
1018 } else if (obj->InheritsFrom(THStack::Class())) {
1019 flush_master();
1020
1021 THStack *hs = static_cast<THStack *>(obj);
1022
1023 TString hopt = iter.GetOption();
1024 hopt.ToLower();
1025 if (!hopt.Contains("nostack") && !hopt.Contains("candle") && !hopt.Contains("violin") && !hopt.Contains("pads")) {
1026 auto arr = hs->GetStack();
1027 arr->SetName(hs->GetName()); // mark list for JS
1028 paddata.NewPrimitive(arr, "__ignore_drawing__").SetSnapshot(TWebSnapshot::kObject, arr);
1029 }
1030
1031 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1032
1033 first_obj = hs->GetNhists() > 0; // real drawing only if there are histograms
1034 } else if (obj->InheritsFrom(TScatter::Class())) {
1035 flush_master();
1036
1037 TScatter *scatter = static_cast<TScatter *>(obj);
1038
1039 TObject *palette = nullptr;
1040
1041 TIter fiter(scatter->GetGraph()->GetListOfFunctions());
1042 while (auto fobj = fiter()) {
1043 if (fobj->InheritsFrom("TPaletteAxis"))
1044 palette = fobj;
1045 }
1046
1047 // ensure histogram exists on server to draw it properly on clients side
1048 if (!IsReadOnly() && first_obj)
1049 scatter->GetHistogram();
1050
1051 if (!palette && CanCreateObject("TPaletteAxis")) {
1052 std::stringstream exec;
1053 exec << "new TPaletteAxis(0,0,0,0,0,0);";
1054 palette = (TObject *)gROOT->ProcessLine(exec.str().c_str());
1055 if (palette)
1056 scatter->GetGraph()->GetListOfFunctions()->AddFirst(palette);
1057 }
1058
1059 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1060
1061 first_obj = false;
1062 } else if (obj->InheritsFrom(TF1::Class())) {
1063 flush_master();
1064 auto f1 = static_cast<TF1 *> (obj);
1065
1066 TString f1opt = iter.GetOption();
1067
1068 check_save_tf1(obj, true);
1069 if (fTF1UseSave > 1)
1070 f1opt.Append(";force_saved");
1071 else if (fTF1UseSave == 1)
1072 f1opt.Append(";prefer_saved");
1073
1074 if (first_obj) {
1075 auto hist = f1->GetHistogram();
1076 paddata.NewPrimitive(hist, "__ignore_drawing__").SetSnapshot(TWebSnapshot::kObject, hist);
1077 f1opt.Append(";webcanv_hist");
1078 }
1079
1080 if (f1->IsA() == TF2::Class())
1081 check_cutg_in_options(iter.GetOption());
1082
1084
1085 first_obj = false;
1086
1087 } else if (obj->InheritsFrom(TGaxis::Class())) {
1088 flush_master();
1089 auto gaxis = static_cast<TGaxis *> (obj);
1090 auto func = gaxis->GetFunction();
1091 if (func)
1092 paddata.NewPrimitive(func, "__ignore_drawing__").SetSnapshot(TWebSnapshot::kObject, func);
1093
1094 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1095 } else if (obj->InheritsFrom(TFrame::Class())) {
1096 flush_master();
1097 if (frame && (obj == frame)) {
1098 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1099 frame = nullptr; // add frame only once
1100 }
1101 } else if (IsJSSupportedClass(obj, usemaster)) {
1102 flush_master();
1103 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
1104 } else {
1105 CreateObjectSnapshot(paddata, pad, obj, iter.GetOption(), usemaster ? &masterps : nullptr);
1106 }
1107 }
1108
1109 flush_master();
1110
1111 bool provide_colors = false;
1112
1113 if ((GetPaletteDelivery() > 2) || ((GetPaletteDelivery() == 2) && resfunc)) {
1114 // provide colors: either for each subpad (> 2) or only for canvas (== 2)
1115 provide_colors = process_primitives;
1116 } else if ((GetPaletteDelivery() == 1) && resfunc) {
1117 // check that colors really changing, using hash
1118
1120 auto hash = CalculateColorsHash();
1121 if ((hash != fColorsHash) || (fColorsVersion == 0)) {
1122 fColorsHash = hash;
1124 }
1125 }
1126
1127 provide_colors = fColorsVersion > version;
1128 }
1129
1130 // add colors after painting is performed - new colors may be generated only during painting
1131 if (provide_colors)
1132 AddColorsPalette(paddata);
1133
1134 if (!resfunc)
1135 return;
1136
1137 // now hide all primitives to perform I/O
1138 std::vector<TList *> all_primitives(fAllPads.size());
1139 for (unsigned n = 0; n < fAllPads.size(); ++n) {
1140 all_primitives[n] = fAllPads[n]->fPrimitives;
1141 fAllPads[n]->fPrimitives = nullptr;
1142 }
1143
1144 // execute function to prevent storing of colors with custom TCanvas streamer
1146
1147 // invoke callback for streaming
1148 resfunc(&paddata);
1149
1150 // and restore back primitives - delete any temporary if necessary
1151 for (unsigned n = 0; n < fAllPads.size(); ++n) {
1152 if (fAllPads[n]->fPrimitives)
1153 delete fAllPads[n]->fPrimitives;
1154 fAllPads[n]->fPrimitives = all_primitives[n];
1155 }
1156 fAllPads.clear();
1157 fUsedObjs.clear();
1158}
1159
1160//////////////////////////////////////////////////////////////////////////////////////////////////
1161/// Add control message for specified connection
1162/// Same control message can be overwritten many time before it really sends to the client
1163/// If connid == 0, message will be add to all connections
1164/// After ctrl message is add to the output, short timer is activated and message send afterwards
1165
1166void TWebCanvas::AddCtrlMsg(unsigned connid, const std::string &key, const std::string &value)
1167{
1168 Bool_t new_ctrl = kFALSE;
1169
1170 for (auto &conn : fWebConn) {
1171 if (conn.match(connid)) {
1172 conn.fCtrl[key] = value;
1173 new_ctrl = kTRUE;
1174 }
1175 }
1176
1177 if (new_ctrl && fTimer->IsSlow())
1179}
1180
1181
1182//////////////////////////////////////////////////////////////////////////////////////////////////
1183/// Add message to send queue for specified connection
1184/// If connid == 0, message will be add to all connections
1185
1186void TWebCanvas::AddSendQueue(unsigned connid, const std::string &msg)
1187{
1188 for (auto &conn : fWebConn) {
1189 if (conn.match(connid))
1190 conn.fSend.emplace(msg);
1191 }
1192}
1193
1194
1195//////////////////////////////////////////////////////////////////////////////////////////////////
1196/// Check if any data should be send to client
1197/// If connid != 0, only selected connection will be checked
1198
1200{
1201 if (!Canvas())
1202 return kFALSE;
1203
1204 bool isMoreData = false, isAnySend = false;
1205
1206 for (auto &conn : fWebConn) {
1207
1208 bool isConnData = !conn.fCtrl.empty() || !conn.fSend.empty() ||
1209 ((conn.fCheckedVersion < fCanvVersion) && (conn.fSendVersion == conn.fDrawVersion));
1210
1211 while ((conn.is_batch() && !connid) || (conn.match(connid) && fWindow && fWindow->CanSend(conn.fConnId, true))) {
1212 // check if any control messages still there to keep timer running
1213
1214 std::string buf;
1215
1216 if (!conn.fCtrl.empty()) {
1218 conn.fCtrl.clear();
1219 } else if (!conn.fSend.empty()) {
1220 std::swap(buf, conn.fSend.front());
1221 conn.fSend.pop();
1222 } else if ((conn.fCheckedVersion < fCanvVersion) && (conn.fSendVersion == conn.fDrawVersion)) {
1223
1224 buf = "SNAP6:"s + std::to_string(fCanvVersion) + ":"s;
1225
1226 TCanvasWebSnapshot holder(IsReadOnly(), true, false); // readonly, set ids, batchmode
1227
1228 holder.SetFixedSize(fFixedSize); // set fixed size flag
1229
1230 // scripts send only when canvas drawn for the first time
1231 if (!conn.fSendVersion)
1232 holder.SetScripts(ProcessCustomScripts(false));
1233
1234 holder.SetHighlightConnect(Canvas()->HasConnection("Highlighted(TVirtualPad*,TObject*,Int_t,Int_t)"));
1235
1236 CreatePadSnapshot(holder, Canvas(), conn.fSendVersion, [&buf, &conn, this](TPadWebSnapshot *snap) {
1237 if (conn.is_batch()) {
1238 // for batch connection only calling of CreatePadSnapshot is important
1239 buf.clear();
1240 return;
1241 }
1242
1243 auto json = TBufferJSON::ToJSON(snap, fJsonComp);
1244 auto hash = json.Hash();
1245 if (conn.fLastSendHash && (conn.fLastSendHash == hash) && conn.fSendVersion) {
1246 // prevent looping when same data send many times
1247 buf.clear();
1248 } else {
1249 buf.append(json.Data());
1250 conn.fLastSendHash = hash;
1251 }
1252 });
1253
1254 conn.fCheckedVersion = fCanvVersion;
1255
1256 conn.fSendVersion = fCanvVersion;
1257
1258 if (buf.empty())
1259 conn.fDrawVersion = fCanvVersion;
1260 } else {
1261 isConnData = false;
1262 break;
1263 }
1264
1265 if (!buf.empty() && !conn.is_batch()) {
1266 fWindow->Send(conn.fConnId, buf);
1267 isAnySend = true;
1268 }
1269 }
1270
1271 if (isConnData)
1272 isMoreData = true;
1273 }
1274
1275 if (fTimer->IsSlow() && isMoreData)
1276 fTimer->SetSlow(kFALSE);
1277
1278 return isAnySend;
1279}
1280
1281//////////////////////////////////////////////////////////////////////////////////////////
1282/// Close web canvas - not implemented
1283
1285{
1286}
1287
1288//////////////////////////////////////////////////////////////////////////////////////////
1289/// Show canvas in specified place.
1290/// If parameter args not specified, default ROOT web display will be used
1291
1293{
1294 if (!fWindow) {
1296
1297 fWindow->SetConnLimit(0); // configure connections limit
1298
1299 fWindow->SetDefaultPage("file:rootui5sys/canv/canvas6.html");
1300
1301 fWindow->SetCallBacks(
1302 // connection
1303 [this](unsigned connid) {
1304 if (fWindow->GetConnectionId(0) == connid)
1305 fWebConn.emplace(fWebConn.begin() + 1, connid);
1306 else
1307 fWebConn.emplace_back(connid);
1308 CheckDataToSend(connid);
1309 },
1310 // data
1311 [this](unsigned connid, const std::string &arg) {
1312 ProcessData(connid, arg);
1314 },
1315 // disconnect
1316 [this](unsigned connid) {
1317 unsigned indx = 0;
1318 for (auto &c : fWebConn) {
1319 if (c.fConnId == connid) {
1320 fWebConn.erase(fWebConn.begin() + indx);
1321 break;
1322 }
1323 indx++;
1324 }
1325 });
1326 }
1327
1328 auto w = Canvas()->GetWindowWidth(), h = Canvas()->GetWindowHeight();
1329 if ((w > 0) && (w < 50000) && (h > 0) && (h < 30000))
1330 fWindow->SetGeometry(w, h);
1331
1336
1337 fWindow->Show(args);
1338}
1339
1340//////////////////////////////////////////////////////////////////////////////////////////
1341/// Show canvas in browser window
1342
1344{
1345 if (gROOT->IsWebDisplayBatch())
1346 return;
1347
1349 args.SetWidgetKind("TCanvas");
1350 args.SetSize(Canvas()->GetWindowWidth(), Canvas()->GetWindowHeight());
1351 args.SetPos(Canvas()->GetWindowTopX(), Canvas()->GetWindowTopY());
1352
1353 ShowWebWindow(args);
1354}
1355
1356//////////////////////////////////////////////////////////////////////////////////////////
1357/// Function used to send command to browser to toggle menu, toolbar, editors, ...
1358
1359void TWebCanvas::ShowCmd(const std::string &arg, Bool_t show)
1360{
1361 AddCtrlMsg(0, arg, show ? "1"s : "0"s);
1362}
1363
1364//////////////////////////////////////////////////////////////////////////////////////////
1365/// Activate object in editor in web browser
1366
1368{
1369 if (!pad || !obj) return;
1370
1371 UInt_t hash = TString::Hash(&obj, sizeof(obj));
1372
1373 AddCtrlMsg(0, "edit"s, std::to_string(hash));
1374}
1375
1376//////////////////////////////////////////////////////////////////////////////////////////
1377/// Returns kTRUE if web canvas has graphical editor
1378
1380{
1381 return (fClientBits & TCanvas::kShowEditor) != 0;
1382}
1383
1384//////////////////////////////////////////////////////////////////////////////////////////
1385/// Returns kTRUE if web canvas has menu bar
1386
1388{
1389 return (fClientBits & TCanvas::kMenuBar) != 0;
1390}
1391
1392//////////////////////////////////////////////////////////////////////////////////////////
1393/// Returns kTRUE if web canvas has status bar
1394
1396{
1397 return (fClientBits & TCanvas::kShowEventStatus) != 0;
1398}
1399
1400//////////////////////////////////////////////////////////////////////////////////////////
1401/// Returns kTRUE if tooltips are activated in web canvas
1402
1404{
1405 return (fClientBits & TCanvas::kShowToolTips) != 0;
1406}
1407
1408//////////////////////////////////////////////////////////////////////////////////////////
1409/// Set window position of web canvas
1410
1412{
1413 AddCtrlMsg(0, "x"s, std::to_string(x));
1414 AddCtrlMsg(0, "y"s, std::to_string(y));
1415}
1416
1417//////////////////////////////////////////////////////////////////////////////////////////
1418/// Set window size of web canvas
1419
1421{
1422 AddCtrlMsg(0, "w"s, std::to_string(w));
1423 AddCtrlMsg(0, "h"s, std::to_string(h));
1424}
1425
1426//////////////////////////////////////////////////////////////////////////////////////////
1427/// Set window title of web canvas
1428
1429void TWebCanvas::SetWindowTitle(const char *newTitle)
1430{
1431 AddCtrlMsg(0, "title"s, newTitle);
1432}
1433
1434//////////////////////////////////////////////////////////////////////////////////////////
1435/// Set canvas size of web canvas
1436
1438{
1439 fFixedSize = kTRUE;
1440 AddCtrlMsg(0, "cw"s, std::to_string(cw));
1441 AddCtrlMsg(0, "ch"s, std::to_string(ch));
1442 if ((cw > 0) && (ch > 0)) {
1443 Canvas()->fCw = cw;
1444 Canvas()->fCh = ch;
1445 } else {
1446 // temporary value, will be reported back from client
1447 Canvas()->fCw = Canvas()->fWindowWidth;
1449 }
1450}
1451
1452//////////////////////////////////////////////////////////////////////////////////////////
1453/// Iconify browser window
1454
1456{
1457 AddCtrlMsg(0, "winstate"s, "iconify"s);
1458}
1459
1460//////////////////////////////////////////////////////////////////////////////////////////
1461/// Raise browser window
1462
1464{
1465 AddCtrlMsg(0, "winstate"s, "raise"s);
1466}
1467
1468//////////////////////////////////////////////////////////////////////////////////////////
1469/// Assign clients bits
1470
1472{
1473 fClientBits = bits;
1478}
1479
1480//////////////////////////////////////////////////////////////////////////////////////////////////
1481/// Decode all pad options, which includes ranges plus objects options
1482
1483Bool_t TWebCanvas::DecodePadOptions(const std::string &msg, bool process_execs)
1484{
1485 if (IsReadOnly() || msg.empty())
1486 return kFALSE;
1487
1488 auto arr = TBufferJSON::FromJSON<std::vector<TWebPadOptions>>(msg);
1489
1490 if (!arr)
1491 return kFALSE;
1492
1493 Bool_t need_update = kFALSE;
1494
1495 TPad *pad_with_execs = nullptr;
1496 TExec *hist_exec = nullptr;
1497
1498 for (unsigned n = 0; n < arr->size(); ++n) {
1499 auto &r = arr->at(n);
1500
1501 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(r.snapid));
1502
1503 if (!pad)
1504 continue;
1505
1506 if (pad == Canvas()) {
1507 AssignStatusBits(r.bits);
1508 Canvas()->fCw = r.cw;
1509 Canvas()->fCh = r.ch;
1510 if (r.w.size() == 4)
1512 }
1513
1514 // only if get OPTIONS message from client allow to change gPad
1515 if (r.active && (pad != gPad) && process_execs)
1516 gPad = pad;
1517
1518 if ((pad->GetTickx() != r.tickx) || (pad->GetTicky() != r.ticky))
1519 pad->SetTicks(r.tickx, r.ticky);
1520 if ((pad->GetGridx() != (r.gridx > 0)) || (pad->GetGridy() != (r.gridy > 0)))
1521 pad->SetGrid(r.gridx, r.gridy);
1522 pad->fLogx = r.logx;
1523 pad->fLogy = r.logy;
1524 pad->fLogz = r.logz;
1525
1526 pad->SetLeftMargin(r.mleft);
1527 pad->SetRightMargin(r.mright);
1528 pad->SetTopMargin(r.mtop);
1529 pad->SetBottomMargin(r.mbottom);
1530
1531 if (r.ranges) {
1532 // avoid call of original methods, set members directly
1533 // pad->Range(r.px1, r.py1, r.px2, r.py2);
1534 // pad->RangeAxis(r.ux1, r.uy1, r.ux2, r.uy2);
1535
1536 pad->fX1 = r.px1;
1537 pad->fX2 = r.px2;
1538 pad->fY1 = r.py1;
1539 pad->fY2 = r.py2;
1540
1541 pad->fUxmin = r.ux1;
1542 pad->fUxmax = r.ux2;
1543 pad->fUymin = r.uy1;
1544 pad->fUymax = r.uy2;
1545 }
1546
1547 // pad->SetPad(r.mleft, r.mbottom, 1-r.mright, 1-r.mtop);
1548
1549 pad->fAbsXlowNDC = r.xlow;
1550 pad->fAbsYlowNDC = r.ylow;
1551 pad->fAbsWNDC = r.xup - r.xlow;
1552 pad->fAbsHNDC = r.yup - r.ylow;
1553
1554 if (pad == Canvas()) {
1555 pad->fXlowNDC = r.xlow;
1556 pad->fYlowNDC = r.ylow;
1557 pad->fXUpNDC = r.xup;
1558 pad->fYUpNDC = r.yup;
1559 pad->fWNDC = r.xup - r.xlow;
1560 pad->fHNDC = r.yup - r.ylow;
1561 } else {
1562 auto mother = pad->GetMother();
1563 if (mother->GetAbsWNDC() > 0. && mother->GetAbsHNDC() > 0.) {
1564 pad->fXlowNDC = (r.xlow - mother->GetAbsXlowNDC()) / mother->GetAbsWNDC();
1565 pad->fYlowNDC = (r.ylow - mother->GetAbsYlowNDC()) / mother->GetAbsHNDC();
1566 pad->fXUpNDC = (r.xup - mother->GetAbsXlowNDC()) / mother->GetAbsWNDC();
1567 pad->fYUpNDC = (r.yup - mother->GetAbsYlowNDC()) / mother->GetAbsHNDC();
1568 pad->fWNDC = (r.xup - r.xlow) / mother->GetAbsWNDC();
1569 pad->fHNDC = (r.yup - r.ylow) / mother->GetAbsHNDC();
1570 }
1571 }
1572
1573 if (r.phi || r.theta) {
1574 pad->fPhi = r.phi;
1575 pad->fTheta = r.theta;
1576 }
1577
1578 // copy of code from TPad::ResizePad()
1579
1580 Double_t pxlow = r.xlow * r.cw;
1581 Double_t pylow = (1-r.ylow) * r.ch;
1582 Double_t pxrange = (r.xup - r.xlow) * r.cw;
1583 Double_t pyrange = -1*(r.yup - r.ylow) * r.ch;
1584
1585 Double_t rounding = 0.00005;
1586 Double_t xrange = r.px2 - r.px1;
1587 Double_t yrange = r.py2 - r.py1;
1588
1589 if ((xrange != 0.) && (pxrange != 0)) {
1590 // Linear X axis
1591 pad->fXtoAbsPixelk = rounding + pxlow - pxrange*r.px1/xrange; //origin at left
1592 pad->fXtoPixelk = rounding + -pxrange*r.px1/xrange;
1593 pad->fXtoPixel = pxrange/xrange;
1594 pad->fAbsPixeltoXk = r.px1 - pxlow*xrange/pxrange;
1595 pad->fPixeltoXk = r.px1;
1596 pad->fPixeltoX = xrange/pxrange;
1597 }
1598
1599 if ((yrange != 0.) && (pyrange != 0.)) {
1600 // Linear Y axis
1601 pad->fYtoAbsPixelk = rounding + pylow - pyrange*r.py1/yrange; //origin at top
1602 pad->fYtoPixelk = rounding + -pyrange - pyrange*r.py1/yrange;
1603 pad->fYtoPixel = pyrange/yrange;
1604 pad->fAbsPixeltoYk = r.py1 - pylow*yrange/pyrange;
1605 pad->fPixeltoYk = r.py1;
1606 pad->fPixeltoY = yrange/pyrange;
1607 }
1608
1610
1611 TObjLink *objlnk = nullptr;
1612
1613 TH1 *hist = static_cast<TH1 *>(FindPrimitive(sid_pad_histogram, 1, pad, &objlnk));
1614
1615 if (hist) {
1616
1617 TObject *hist_holder = objlnk ? objlnk->GetObject() : nullptr;
1618 if (hist_holder == hist)
1619 hist_holder = nullptr;
1620
1621 Bool_t no_entries = hist->GetEntries();
1622 Bool_t is_stack = hist_holder && (hist_holder->IsA() == THStack::Class());
1623
1624 Double_t hmin = 0., hmax = 0.;
1625
1626 if (r.zx1 == r.zx2)
1627 hist->GetXaxis()->SetRange(0, 0);
1628 else
1629 hist->GetXaxis()->SetRangeUser(r.zx1, r.zx2);
1630
1631 if (hist->GetDimension() == 1) {
1632 hmin = r.zy1;
1633 hmax = r.zy2;
1634 if ((hmin == hmax) && !no_entries && !is_stack) {
1635 // if there are no zooming on Y and histogram has no entries, hmin/hmax should be set to full range
1636 hmin = pad->fLogy ? TMath::Power(pad->fLogy < 2 ? 10 : pad->fLogy, r.uy1) : r.uy1;
1637 hmax = pad->fLogy ? TMath::Power(pad->fLogy < 2 ? 10 : pad->fLogy, r.uy2) : r.uy2;
1638 }
1639 } else if (r.zy1 == r.zy2) {
1640 hist->GetYaxis()->SetRange(0, 0);
1641 } else {
1642 hist->GetYaxis()->SetRangeUser(r.zy1, r.zy2);
1643 }
1644
1645 if (hist->GetDimension() == 2) {
1646 hmin = r.zz1;
1647 hmax = r.zz2;
1648 if ((hmin == hmax) && !no_entries) {
1649 // z scale is not transformed
1650 hmin = r.uz1;
1651 hmax = r.uz2;
1652 }
1653 } else if (hist->GetDimension() == 3) {
1654 if (r.zz1 == r.zz2) {
1655 hist->GetZaxis()->SetRange(0, 0);
1656 } else {
1657 hist->GetZaxis()->SetRangeUser(r.zz1, r.zz2);
1658 }
1659 }
1660
1661 if (hmin == hmax)
1662 hmin = hmax = -1111;
1663
1664 if (is_stack) {
1665 hist->SetMinimum(hmin);
1666 hist->SetMaximum(hmax);
1667 hist->SetBit(TH1::kIsZoomed, hmin != hmax);
1668 } else if (!hist_holder || (hist_holder->IsA() == TScatter::Class())) {
1669 hist->SetMinimum(hmin);
1670 hist->SetMaximum(hmax);
1671 } else {
1672 auto SetMember = [hist_holder](const char *name, Double_t value) {
1673 auto offset = hist_holder->IsA()->GetDataMemberOffset(name);
1674 if (offset > 0)
1675 *((Double_t *)((char*) hist_holder + offset)) = value;
1676 else
1677 ::Error("SetMember", "Cannot find %s data member in %s", name, hist_holder->ClassName());
1678 };
1679
1680 // directly set min/max in classes like THStack, TGraph, TMultiGraph
1681 SetMember("fMinimum", hmin);
1682 SetMember("fMaximum", hmax);
1683 }
1684
1685 TIter next(hist->GetListOfFunctions());
1686 while (auto fobj = next())
1687 if (!hist_exec && fobj->InheritsFrom(TExec::Class())) {
1688 hist_exec = (TExec *) fobj;
1689 need_update = kTRUE;
1690 }
1691 }
1692
1693 std::map<std::string, int> idmap;
1694
1695 for (auto &item : r.primitives) {
1696 auto iter = idmap.find(item.snapid);
1697 int idcnt = 1;
1698 if (iter == idmap.end())
1699 idmap[item.snapid] = 1;
1700 else
1701 idcnt = ++iter->second;
1702
1703 ProcessObjectOptions(item, pad, idcnt);
1704 }
1705
1706 // without special objects no need for explicit update of the pad
1707 if (fPadsStatus[pad]._has_specials) {
1708 pad->Modified(kTRUE);
1709 need_update = kTRUE;
1710 }
1711
1712 if (process_execs && (gPad == pad))
1713 pad_with_execs = pad;
1714 }
1715
1716 ProcessExecs(pad_with_execs, hist_exec);
1717
1718 if (fUpdatedSignal) fUpdatedSignal(); // invoke signal
1719
1720 return need_update;
1721}
1722
1723//////////////////////////////////////////////////////////////////////////////////////////////////
1724/// Process TExec objects in the pad
1725
1727{
1728 auto execs = pad ? pad->GetListOfExecs() : nullptr;
1729
1730 if ((!execs || !execs->GetSize()) && !extra)
1731 return;
1732
1733 auto saveps = gVirtualPS;
1734 TWebPS ps;
1735 gVirtualPS = &ps;
1736
1737 auto savex = gVirtualX;
1738 TVirtualX x;
1739 gVirtualX = &x;
1740
1741 TIter next(execs);
1742 while (auto obj = next()) {
1743 auto exec = dynamic_cast<TExec *>(obj);
1744 if (exec)
1745 exec->Exec();
1746 }
1747
1748 if (extra)
1749 extra->Exec();
1750
1751 gVirtualPS = saveps;
1752 gVirtualX = savex;
1753}
1754
1755//////////////////////////////////////////////////////////////////////////////////////////
1756/// Execute one or several methods for selected object
1757/// String can be separated by ";;" to let execute several methods at once
1758void TWebCanvas::ProcessLinesForObject(TObject *obj, const std::string &lines)
1759{
1760 std::string buf = lines;
1761
1762 Int_t indx = 0;
1763
1764 while (obj && !buf.empty()) {
1765 std::string sub = buf;
1766 auto pos = buf.find(";;");
1767 if (pos == std::string::npos) {
1768 sub = buf;
1769 buf.clear();
1770 } else {
1771 sub = buf.substr(0,pos);
1772 buf = buf.substr(pos+2);
1773 }
1774 if (sub.empty()) continue;
1775
1776 std::stringstream exec;
1777 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj << ")->" << sub << ";";
1778 if (indx < 3 || gDebug > 0)
1779 Info("ProcessLinesForObject", "Obj %s Execute %s", obj->GetName(), exec.str().c_str());
1780 gROOT->ProcessLine(exec.str().c_str());
1781 indx++;
1782 }
1783}
1784
1785//////////////////////////////////////////////////////////////////////////////////////////
1786/// Handle data from web browser
1787/// Returns kFALSE if message was not processed
1788
1789Bool_t TWebCanvas::ProcessData(unsigned connid, const std::string &arg)
1790{
1791 if (arg.empty())
1792 return kTRUE;
1793
1794 // try to identify connection for given WS request
1795 unsigned indx = 0; // first connection is batch and excluded
1796 while(++indx < fWebConn.size()) {
1797 if (fWebConn[indx].fConnId == connid)
1798 break;
1799 }
1800 if (indx >= fWebConn.size())
1801 return kTRUE;
1802
1803 Bool_t is_main_connection = indx == 1; // first connection allow to make changes
1804
1805 struct FlagGuard {
1806 Bool_t &flag;
1807 FlagGuard(Bool_t &_flag) : flag(_flag) { flag = true; }
1808 ~FlagGuard() { flag = false; }
1809 };
1810
1811 FlagGuard guard(fProcessingData);
1812
1813 const char *cdata = arg.c_str();
1814
1815 if (arg == "KEEPALIVE") {
1816 // do nothing
1817
1818 } else if (arg == "QUIT") {
1819
1820 // use window manager to correctly terminate http server
1821 fWindow->TerminateROOT();
1822
1823 } else if (arg.compare(0, 7, "READY6:") == 0) {
1824
1825 // this is reply on drawing of ROOT6 snapshot
1826 // it confirms when drawing of specific canvas version is completed
1827
1828 cdata += 7;
1829
1830 const char *separ = strchr(cdata, ':');
1831 if (!separ) {
1832 fWebConn[indx].fDrawVersion = std::stoll(cdata);
1833 } else {
1834 fWebConn[indx].fDrawVersion = std::stoll(std::string(cdata, separ - cdata));
1835 if (is_main_connection && !IsReadOnly())
1836 if (DecodePadOptions(separ+1, false))
1838 }
1839
1840 } else if (arg == "RELOAD") {
1841
1842 // trigger reload of canvas data
1843 fWebConn[indx].reset();
1844
1845 } else if (arg.compare(0, 5, "SAVE:") == 0) {
1846
1847 // save image produced by the client side - like png or svg
1848 const char *img = cdata + 5;
1849
1850 const char *separ = strchr(img, ':');
1851 if (separ) {
1852 TString filename(img, separ - img);
1853 img = separ + 1;
1854
1855 std::ofstream ofs(filename.Data());
1856
1857 int filelen = -1;
1858
1859 if (filename.Index(".svg") != kNPOS) {
1860 // ofs << "<?xml version=\"1.0\" standalone=\"no\"?>";
1861 ofs << img;
1862 filelen = strlen(img);
1863 } else {
1864 TString binary = TBase64::Decode(img);
1865 ofs.write(binary.Data(), binary.Length());
1866 filelen = binary.Length();
1867 }
1868 ofs.close();
1869
1870 Info("ProcessData", "File %s size %d has been created", filename.Data(), filelen);
1871 }
1872
1873 } else if (arg.compare(0, 8, "PRODUCE:") == 0) {
1874
1875 // create ROOT, PDF, ... files using native ROOT functionality
1876 Canvas()->Print(arg.c_str() + 8);
1877
1878 } else if (arg.compare(0, 8, "GETMENU:") == 0) {
1879
1880 TObject *obj = FindPrimitive(arg.substr(8));
1881 if (!obj)
1882 obj = Canvas();
1883
1884 TWebMenuItems items(arg.c_str() + 8);
1885 items.PopulateObjectMenu(obj, obj->IsA());
1886 std::string buf = "MENU:";
1887 buf.append(TBufferJSON::ToJSON(&items, 103).Data());
1888
1889 AddSendQueue(connid, buf);
1890
1891 } else if (arg.compare(0, 11, "STATUSBITS:") == 0) {
1892
1893 if (is_main_connection) {
1894 AssignStatusBits(std::stoul(arg.substr(11)));
1895 if (fUpdatedSignal) fUpdatedSignal(); // invoke signal
1896 }
1897
1898 } else if (arg.compare(0, 10, "HIGHLIGHT:") == 0) {
1899
1900 if (is_main_connection) {
1901 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(10));
1902 if (!arr || (arr->size() != 4)) {
1903 Error("ProcessData", "Wrong arguments count %d in highlight message", (int)(arr ? arr->size() : -1));
1904 } else {
1905 auto pad = dynamic_cast<TVirtualPad *>(FindPrimitive(arr->at(0)));
1906 auto obj = FindPrimitive(arr->at(1));
1907 int argx = std::stoi(arr->at(2));
1908 int argy = std::stoi(arr->at(3));
1909 if (pad && obj) {
1910 Canvas()->Highlighted(pad, obj, argx, argy);
1912 }
1913 }
1914 }
1915
1916 } else if (ROOT::RWebWindow::IsFileDialogMessage(arg)) {
1917
1919
1920 } else if (IsReadOnly() || !is_main_connection) {
1921
1922 ///////////////////////////////////////////////////////////////////////////////////////
1923 // all following messages are not allowed in readonly mode or for secondary connections
1924
1925 return kFALSE;
1926
1927 } else if (arg.compare(0, 9, "OPTIONS6:") == 0) {
1928
1929 if (DecodePadOptions(arg.substr(9), true))
1931
1932 } else if (arg.compare(0, 9, "FITPANEL:") == 0) {
1933
1934 std::string chid = arg.substr(9);
1935
1936 TH1 *hist = nullptr;
1937 TIter iter(Canvas()->GetListOfPrimitives());
1938 while (auto obj = iter()) {
1939 hist = dynamic_cast<TH1 *>(obj);
1940 if (hist) break;
1941 }
1942
1943 TString showcmd;
1944 if (chid == "standalone")
1945 showcmd = "panel->Show()";
1946 else
1947 showcmd = TString::Format("auto wptr = (std::shared_ptr<ROOT::RWebWindow>*)0x%zx;"
1948 "panel->Show({*wptr, %u, %s})",
1949 (size_t) &fWindow, connid, chid.c_str());
1950
1951 auto cmd = TString::Format("auto panel = std::make_shared<ROOT::Experimental::RFitPanel>(\"FitPanel\");"
1952 "panel->AssignCanvas(\"%s\");"
1953 "panel->AssignHistogram((TH1 *)0x%zx);"
1954 "%s;panel->ClearOnClose(panel);",
1955 Canvas()->GetName(), (size_t) hist, showcmd.Data());
1956 gROOT->ProcessLine(cmd.Data());
1957 } else if (arg == "START_BROWSER"s) {
1958
1959 gROOT->ProcessLine("new TBrowser;");
1960
1961 } else if (arg.compare(0, 6, "EVENT:") == 0) {
1962 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(6));
1963 if (!arr || (arr->size() != 5)) {
1964 Error("ProcessData", "Wrong arguments count %d in event message", (int)(arr ? arr->size() : -1));
1965 } else {
1966 auto pad = dynamic_cast<TPad *>(FindPrimitive(arr->at(0)));
1967 std::string kind = arr->at(1);
1968 int event = -1;
1969 if (kind == "move"s) event = kMouseMotion;
1970 int argx = std::stoi(arr->at(2));
1971 int argy = std::stoi(arr->at(3));
1972 auto selobj = FindPrimitive(arr->at(4));
1973
1974 if ((event >= 0) && pad && (pad == gPad)) {
1975 Canvas()->fEvent = event;
1976 Canvas()->fEventX = argx;
1977 Canvas()->fEventY = argy;
1978
1979 Canvas()->fSelected = selobj;
1980
1981 ProcessExecs(pad);
1982 }
1983 }
1984
1985 } else if (arg.compare(0, 8, "PRIMIT6:") == 0) {
1986
1987 auto opt = TBufferJSON::FromJSON<TWebObjectOptions>(arg.c_str() + 8);
1988
1989 if (opt) {
1990 TPad *modpad = ProcessObjectOptions(*opt, nullptr);
1991
1992 // indicate that pad was modified
1993 if (modpad)
1994 modpad->Modified();
1995 }
1996
1997 } else if (arg.compare(0, 11, "PADCLICKED:") == 0) {
1998
1999 auto click = TBufferJSON::FromJSON<TWebPadClick>(arg.c_str() + 11);
2000
2001 if (click) {
2002
2003 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(click->padid));
2004
2005 if (pad && pad->InheritsFrom(TButton::Class())) {
2006 auto btn = (TButton *) pad;
2007 const char *mthd = btn->GetMethod();
2008 if (mthd && *mthd) {
2009 TVirtualPad::TContext ctxt(gROOT->GetSelectedPad(), kTRUE, kTRUE);
2010 gROOT->ProcessLine(mthd);
2011 }
2012 return kTRUE;
2013 }
2014
2015 if (pad && (pad != gPad)) {
2016 gPad = pad;
2020 }
2021
2022 if (!click->objid.empty()) {
2023 auto selobj = FindPrimitive(click->objid);
2024 Canvas()->SetClickSelected(selobj);
2025 Canvas()->fSelected = selobj;
2026 if (pad && selobj && fObjSelectSignal)
2027 fObjSelectSignal(pad, selobj);
2028 }
2029
2030 if ((click->x >= 0) && (click->y >= 0)) {
2031 Canvas()->fEvent = click->dbl ? kButton1Double : kButton1Up;
2032 Canvas()->fEventX = click->x;
2033 Canvas()->fEventY = click->y;
2034 if (click->dbl && fPadDblClickedSignal)
2035 fPadDblClickedSignal(pad, click->x, click->y);
2036 else if (!click->dbl && fPadClickedSignal)
2037 fPadClickedSignal(pad, click->x, click->y);
2038 }
2039
2040 ProcessExecs(pad);
2041 }
2042
2043 } else if (arg.compare(0, 8, "OBJEXEC:") == 0) {
2044
2045 auto buf = arg.substr(8);
2046 auto pos = buf.find(":");
2047
2048 if ((pos > 0) && (pos != std::string::npos)) {
2049 auto sid = buf.substr(0, pos);
2050 buf.erase(0, pos + 1);
2051
2052 TObjLink *lnk = nullptr;
2053 TPad *objpad = nullptr;
2054
2055 TObject *obj = FindPrimitive(sid, 1, nullptr, &lnk, &objpad);
2056
2057 if (obj && !buf.empty()) {
2058
2059 ProcessLinesForObject(obj, buf);
2060
2061 if (objpad)
2062 objpad->Modified();
2063 else
2064 Canvas()->Modified();
2065
2067 }
2068 }
2069
2070 } else if (arg.compare(0, 12, "EXECANDSEND:") == 0) {
2071
2072 // execute method and send data, used by drawing projections
2073
2074 std::string buf = arg.substr(12);
2075 std::string reply;
2076 TObject *obj = nullptr;
2077
2078 auto pos = buf.find(":");
2079
2080 if (pos > 0) {
2081 // only first client can execute commands
2082 reply = buf.substr(0, pos);
2083 buf.erase(0, pos + 1);
2084 pos = buf.find(":");
2085 if (pos > 0) {
2086 auto sid = buf.substr(0, pos);
2087 buf.erase(0, pos + 1);
2088 obj = FindPrimitive(sid);
2089 }
2090 }
2091
2092 if (obj && !buf.empty() && !reply.empty()) {
2093 std::stringstream exec;
2094 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj
2095 << ")->" << buf << ";";
2096 if (gDebug > 0)
2097 Info("ProcessData", "Obj %s Exec %s", obj->GetName(), exec.str().c_str());
2098
2099 auto res = gROOT->ProcessLine(exec.str().c_str());
2100 TObject *resobj = (TObject *)(res);
2101 if (resobj) {
2102 std::string send = reply;
2103 send.append(":");
2104 send.append(TBufferJSON::ToJSON(resobj, 23).Data());
2105 AddSendQueue(connid, send);
2106 if (reply[0] == 'D')
2107 delete resobj; // delete object if first symbol in reply is D
2108 }
2109 }
2110
2111 } else if (arg.compare(0, 6, "CLEAR:") == 0) {
2112 std::string snapid = arg.substr(6);
2113
2114 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(snapid));
2115
2116 if (pad) {
2117 pad->Clear();
2118 pad->Modified();
2120 } else {
2121 Error("ProcessData", "Not found pad with id %s to clear\n", snapid.c_str());
2122 }
2123 } else if (arg.compare(0, 7, "DIVIDE:") == 0) {
2124 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(7));
2125 if (arr && arr->size() == 2) {
2126 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(arr->at(0)));
2127 int nn = 0, n1 = 0, n2 = 0;
2128
2129 std::string divide = arr->at(1);
2130 auto p = divide.find('x');
2131 if (p == std::string::npos)
2132 p = divide.find('X');
2133
2134 if (p != std::string::npos) {
2135 n1 = std::stoi(divide.substr(0,p));
2136 n2 = std::stoi(divide.substr(p+1));
2137 } else {
2138 nn = std::stoi(divide);
2139 }
2140
2141 if (pad && ((nn > 1) || (n1*n2 > 1))) {
2142 pad->Clear();
2143 pad->Modified();
2144 if (nn > 1)
2145 pad->DivideSquare(nn);
2146 else
2147 pad->Divide(n1, n2);
2148 pad->cd(1);
2150 }
2151 }
2152
2153 } else if (arg.compare(0, 8, "DRAWOPT:") == 0) {
2154
2155 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(8));
2156 if (arr && arr->size() == 2) {
2157 TObjLink *objlnk = nullptr;
2158 FindPrimitive(arr->at(0), 1, nullptr, &objlnk);
2159 if (objlnk)
2160 objlnk->SetOption(arr->at(1).c_str());
2161 }
2162
2163 } else if (arg.compare(0, 8, "RESIZED:") == 0) {
2164
2165 auto arr = TBufferJSON::FromJSON<std::vector<int>>(arg.substr(8));
2166 if (arr && arr->size() == 7) {
2167 // set members directly to avoid redrawing of the client again
2168 Canvas()->fCw = arr->at(4);
2169 Canvas()->fCh = arr->at(5);
2170 fFixedSize = arr->at(6) > 0;
2171 arr->resize(4);
2172 SetWindowGeometry(*arr);
2173 }
2174
2175 } else if (arg.compare(0, 7, "POPOBJ:") == 0) {
2176
2177 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(7));
2178 if (arr && arr->size() == 2) {
2179 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(arr->at(0)));
2180 TObject *obj = FindPrimitive(arr->at(1), 0, pad);
2181 if (pad && obj && (obj != pad->GetListOfPrimitives()->Last())) {
2182 TIter next(pad->GetListOfPrimitives());
2183 while (auto o = next())
2184 if (obj == o) {
2185 TString opt = next.GetOption();
2186 pad->Remove(obj, kFALSE);
2187 pad->Add(obj, opt.Data());
2188 break;
2189 }
2190 }
2191 }
2192
2193 } else if (arg.compare(0, 8, "SHOWURL:") == 0) {
2194
2196 args.SetUrl(arg.substr(8));
2197 args.SetStandalone(false);
2198
2200
2201 } else if (arg == "INTERRUPT"s) {
2202
2203 gROOT->SetInterrupt();
2204
2205 } else {
2206
2207 // unknown message, probably should be processed by other implementation
2208 return kFALSE;
2209
2210 }
2211
2212 return kTRUE;
2213}
2214
2215//////////////////////////////////////////////////////////////////////////////////////////
2216/// Returns true if any pad in the canvas were modified
2217/// Reset modified flags, increment canvas version (if inc_version is true)
2218
2220{
2221 if (fPadsStatus.find(pad) == fPadsStatus.end())
2222 fPadsStatus[pad] = PadStatus{0, true, true};
2223
2224 auto &entry = fPadsStatus[pad];
2225 entry._detected = true;
2226 if (pad->IsModified()) {
2227 pad->Modified(kFALSE);
2228 entry._modified = true;
2229 }
2230
2231 TIter iter(pad->GetListOfPrimitives());
2232 while (auto obj = iter()) {
2233 if (obj->InheritsFrom(TPad::Class()))
2234 CheckPadModified(static_cast<TPad *>(obj));
2235 }
2236}
2237
2238//////////////////////////////////////////////////////////////////////////////////////////
2239/// Check if any pad on the canvas was modified
2240/// If yes, increment version of correspondent pad
2241/// Returns true when canvas really modified
2242
2244{
2245 // clear temporary flags
2246 for (auto &entry : fPadsStatus) {
2247 entry.second._detected = false;
2248 entry.second._modified = force_modified;
2249 }
2250
2251 // scan sub-pads
2253
2254 // remove no-longer existing pads
2255 bool is_any_modified = false;
2256 for(auto iter = fPadsStatus.begin(); iter != fPadsStatus.end(); ) {
2257 if (iter->second._modified)
2258 is_any_modified = true;
2259 if (!iter->second._detected)
2260 fPadsStatus.erase(iter++);
2261 else
2262 iter++;
2263 }
2264
2265 // if any pad modified, increment canvas version and set version of modified pads
2266 if (is_any_modified) {
2267 fCanvVersion++;
2268 for(auto &entry : fPadsStatus)
2269 if (entry.second._modified)
2270 entry.second.fVersion = fCanvVersion;
2271 }
2272
2273 return is_any_modified;
2274}
2275
2276//////////////////////////////////////////////////////////////////////////////////////////
2277/// Set window geometry as array with coordinates and dimensions
2278
2279void TWebCanvas::SetWindowGeometry(const std::vector<int> &arr)
2280{
2281 fWindowGeometry = arr;
2282 Canvas()->fWindowTopX = arr[0];
2283 Canvas()->fWindowTopY = arr[1];
2284 Canvas()->fWindowWidth = arr[2];
2285 Canvas()->fWindowHeight = arr[3];
2286 if (fWindow) {
2287 // position is unreliable and cannot be used
2288 // fWindow->SetPosition(arr[0], arr[1]);
2289 fWindow->SetGeometry(arr[2], arr[3]);
2290 }
2291}
2292
2293//////////////////////////////////////////////////////////////////////////////////////////
2294/// Returns window geometry including borders and menus
2295
2297{
2298 if (fWindowGeometry.size() == 4) {
2299 x = fWindowGeometry[0];
2300 y = fWindowGeometry[1];
2301 w = fWindowGeometry[2];
2302 h = fWindowGeometry[3];
2303 } else {
2304 x = Canvas()->fWindowTopX;
2305 y = Canvas()->fWindowTopY;
2306 w = Canvas()->fWindowWidth;
2307 h = Canvas()->fWindowHeight;
2308 }
2309 return 0;
2310}
2311
2312
2313//////////////////////////////////////////////////////////////////////////////////////////
2314/// if canvas or any subpad was modified,
2315/// scan all primitives in the TCanvas and subpads and convert them into
2316/// the structure which will be delivered to JSROOT client
2317
2319{
2321
2323
2324 if (!fProcessingData && !IsAsyncMode() && !async)
2326
2327 return kTRUE;
2328}
2329
2330//////////////////////////////////////////////////////////////////////////////////////////
2331/// Increment canvas version and force sending data to client - do not wait for reply
2332
2334{
2335 CheckCanvasModified(true);
2336
2337 if (!fWindow) {
2338 TCanvasWebSnapshot holder(IsReadOnly(), false, true); // readonly, set ids, batchmode
2339
2340 holder.SetScripts(ProcessCustomScripts(true));
2341
2342 CreatePadSnapshot(holder, Canvas(), 0, nullptr);
2343 } else {
2345 }
2346}
2347
2348//////////////////////////////////////////////////////////////////////////////////////////
2349/// Wait when specified version of canvas was painted and confirmed by browser
2350
2352{
2353 if (!fWindow)
2354 return kTRUE;
2355
2356 // simple polling loop until specified version delivered to the clients
2357 // first 500 loops done without sleep, then with 1ms sleep and last 500 with 100 ms sleep
2358
2359 long cnt = 0, cnt_limit = GetLongerPolling() ? 5500 : 1500;
2360
2361 if (gDebug > 2)
2362 Info("WaitWhenCanvasPainted", "version %ld", (long)ver);
2363
2364 while (cnt++ < cnt_limit) {
2365
2366 if (!fWindow->HasConnection(0, false)) {
2367 if (gDebug > 2)
2368 Info("WaitWhenCanvasPainted", "no connections - abort");
2369 return kFALSE; // wait ~1 min if no new connection established
2370 }
2371
2372 if ((fWebConn.size() > 1) && (fWebConn[1].fDrawVersion >= ver)) {
2373 if (gDebug > 2)
2374 Info("WaitWhenCanvasPainted", "ver %ld got painted", (long)ver);
2375 return kTRUE;
2376 }
2377
2379 if (cnt > 500)
2380 gSystem->Sleep((cnt < cnt_limit - 500) ? 1 : 100); // increase sleep interval when do very often
2381 }
2382
2383 if (gDebug > 2)
2384 Info("WaitWhenCanvasPainted", "timeout");
2385
2386 return kFALSE;
2387}
2388
2389//////////////////////////////////////////////////////////////////////////////////////////
2390/// Create JSON painting output for given pad
2391/// Produce JSON can be used for offline drawing with JSROOT
2392
2393TString TWebCanvas::CreatePadJSON(TPad *pad, Int_t json_compression, Bool_t batchmode)
2394{
2395 TString res;
2396 if (!pad)
2397 return res;
2398
2399 TCanvas *c = dynamic_cast<TCanvas *>(pad);
2400 if (c) {
2401 res = CreateCanvasJSON(c, json_compression, batchmode);
2402 } else {
2403 auto imp = std::make_unique<TWebCanvas>(pad->GetCanvas(), pad->GetName(), 0, 0, pad->GetWw(), pad->GetWh(), kTRUE);
2404
2405 TPadWebSnapshot holder(true, false, batchmode); // readonly, no ids, batchmode
2406
2407 imp->CreatePadSnapshot(holder, pad, 0, [&res, json_compression](TPadWebSnapshot *snap) {
2408 res = TBufferJSON::ToJSON(snap, json_compression);
2409 });
2410 }
2411
2412 return res;
2413}
2414
2415//////////////////////////////////////////////////////////////////////////////////////////
2416/// Create JSON painting output for given canvas
2417/// Produce JSON can be used for offline drawing with JSROOT
2418
2420{
2421 TString res;
2422
2423 if (!c)
2424 return res;
2425
2426 {
2427 auto imp = std::make_unique<TWebCanvas>(c, c->GetName(), 0, 0, c->GetWw(), c->GetWh(), kTRUE);
2428
2429 TCanvasWebSnapshot holder(true, false, batchmode); // readonly, no ids, batchmode
2430
2431 holder.SetScripts(ProcessCustomScripts(batchmode));
2432
2433 imp->CreatePadSnapshot(holder, c, 0, [&res, json_compression](TPadWebSnapshot *snap) {
2434 res = TBufferJSON::ToJSON(snap, json_compression);
2435 });
2436 }
2437
2438 return res;
2439}
2440
2441//////////////////////////////////////////////////////////////////////////////////////////
2442/// Create JSON painting output for given canvas and store into the file
2443/// See TBufferJSON::ExportToFile() method for more details about option
2444/// If option string starts with symbol 'b', JSON for batch mode will be generated
2445
2447{
2448 Int_t res = 0;
2449 Bool_t batchmode = kFALSE;
2450 if (option && *option == 'b') {
2451 batchmode = kTRUE;
2452 ++option;
2453 }
2454
2455 if (!c)
2456 return res;
2457
2458 {
2459 auto imp = std::make_unique<TWebCanvas>(c, c->GetName(), 0, 0, c->GetWw(), c->GetWh(), kTRUE);
2460
2461 TCanvasWebSnapshot holder(true, false, batchmode); // readonly, no ids, batchmode
2462
2463 holder.SetScripts(ProcessCustomScripts(batchmode));
2464
2465 imp->CreatePadSnapshot(holder, c, 0, [&res, filename, option](TPadWebSnapshot *snap) {
2467 });
2468 }
2469
2470 return res;
2471}
2472
2473//////////////////////////////////////////////////////////////////////////////////////////
2474/// Create image using batch (headless) capability of Chrome or Firefox browsers
2475/// Supported png, jpeg, svg, pdf formats
2476
2477bool TWebCanvas::ProduceImage(TPad *pad, const char *fileName, Int_t width, Int_t height)
2478{
2479 if (!pad)
2480 return false;
2481
2483 if (!json.Length())
2484 return false;
2485
2486 TString fname = fileName;
2487 const char *endings[4] = {"(", "[", "]", ")"};
2488 const char *suffix = nullptr;
2489 for (int n = 0; (n < 4) && !suffix; ++n) {
2490 if (fname.EndsWith(endings[n])) {
2491 fname.Resize(fname.Length() - 1);
2492 suffix = endings[n];
2493 }
2494 }
2495
2496 Bool_t append_batch = kTRUE, flush_batch = kTRUE;
2497
2498 std::string fmt = ROOT::RWebDisplayHandle::GetImageFormat(fname.Data());
2499 if (fmt.empty())
2500 return false;
2501
2502 if (suffix) {
2503 if (fmt != "pdf")
2504 return false;
2505 switch (*suffix) {
2506 case '(': gBatchMultiPdf = fname.Data(); flush_batch = kFALSE; break;
2507 case '[': gBatchMultiPdf = fname.Data(); append_batch = kFALSE; flush_batch = kFALSE; break;
2508 case ']': gBatchMultiPdf.clear(); append_batch = kFALSE; break;
2509 case ')': gBatchMultiPdf.clear(); fname.Append("+"); break;
2510 }
2511 } else if (fmt == "pdf") {
2512 if (!gBatchMultiPdf.empty()) {
2513 if (gBatchMultiPdf.compare(fileName) == 0) {
2514 append_batch = kTRUE;
2515 flush_batch = kFALSE;
2516 suffix = "+"; // to let append to the batch
2517 if ((gBatchFiles.size() > 0) && (gBatchFiles.back().compare(0, fname.Length(), fname.Data()) == 0))
2518 fname.Append("+"); // .pdf+ means appending image to previous
2519 } else {
2520 ::Error("TWebCanvas::ProduceImage", "Cannot change PDF name when multi-page PDF active");
2521 return false;
2522 }
2523 }
2524 } else if (!gBatchMultiPdf.empty()) {
2525 ::Error("TWebCanvas::ProduceImage", "Cannot produce other images when multi-page PDF active");
2526 return false;
2527 }
2528
2529 if (!width && !height) {
2530 if ((pad->GetCanvas() == pad) || (pad->IsA() == TCanvas::Class())) {
2531 width = pad->GetWw();
2532 height = pad->GetWh();
2533 } else {
2534 width = (Int_t) (pad->GetAbsWNDC() * pad->GetCanvas()->GetWw());
2535 height = (Int_t) (pad->GetAbsHNDC() * pad->GetCanvas()->GetWh());
2536 }
2537 }
2538
2539 if (!suffix && (!gBatchImageMode || (fmt == "s.pdf") || (fmt == "json") || (fmt == "s.png")))
2541
2542 if (append_batch) {
2543 gBatchFiles.emplace_back(fname.Data());
2544 gBatchJsons.emplace_back(json);
2545 gBatchWidths.emplace_back(width);
2546 gBatchHeights.emplace_back(height);
2547 }
2548
2549 if (!flush_batch || (gBatchJsons.size() < gBatchImageMode))
2550 return true;
2551
2552 return FlushBatchImages();
2553}
2554
2555//////////////////////////////////////////////////////////////////////////////////////////
2556/// Create images for several pads using batch (headless) capability of Chrome or Firefox browsers
2557/// Supported png, jpeg, svg, pdf, webp formats
2558/// One can include %d qualifier which will be replaced by image index using printf functionality.
2559/// If for pdf format %d qualifier not specified, all images will be stored in single PDF file.
2560/// For all other formats %d qualifier will be add before extension automatically
2561
2562bool TWebCanvas::ProduceImages(std::vector<TPad *> pads, const char *filename, Int_t width, Int_t height)
2563{
2564 if (pads.empty())
2565 return false;
2566
2567 std::vector<std::string> jsons;
2568 std::vector<Int_t> widths, heights;
2569
2570 for (unsigned n = 0; n < pads.size(); ++n) {
2571 auto pad = pads[n];
2572
2574 if (!json.Length())
2575 continue;
2576
2577 Int_t w = width, h = height;
2578
2579 if (!w && !h) {
2580 if ((pad->GetCanvas() == pad) || (pad->IsA() == TCanvas::Class())) {
2581 w = pad->GetWw();
2582 h = pad->GetWh();
2583 } else {
2584 w = (Int_t) (pad->GetAbsWNDC() * pad->GetCanvas()->GetWw());
2585 h = (Int_t) (pad->GetAbsHNDC() * pad->GetCanvas()->GetWh());
2586 }
2587 }
2588
2589 jsons.emplace_back(json.Data());
2590 widths.emplace_back(w);
2591 heights.emplace_back(h);
2592 }
2593
2595
2596 if (!gBatchImageMode || (fmt == "json") || (fmt == "s.png") || (fmt == "s.pdf"))
2597 return ROOT::RWebDisplayHandle::ProduceImages(filename, jsons, widths, heights);
2598
2599 auto fnames = ROOT::RWebDisplayHandle::ProduceImagesNames(filename, jsons.size());
2600
2601 gBatchFiles.insert(gBatchFiles.end(), fnames.begin(), fnames.end());
2602 gBatchJsons.insert(gBatchJsons.end(), jsons.begin(), jsons.end());
2603 gBatchWidths.insert(gBatchWidths.end(), widths.begin(), widths.end());
2604 gBatchHeights.insert(gBatchHeights.end(), heights.begin(), heights.end());
2605 if (gBatchJsons.size() < gBatchImageMode)
2606 return true;
2607
2608 return FlushBatchImages();
2609}
2610
2611
2612//////////////////////////////////////////////////////////////////////////////////////////
2613/// Process data for single primitive
2614/// Returns object pad if object was modified
2615
2617{
2618 TObjLink *lnk = nullptr;
2619 TPad *objpad = nullptr;
2620 TObject *obj = FindPrimitive(item.snapid, idcnt, pad, &lnk, &objpad);
2621
2622 if (item.fcust.compare("exec") == 0) {
2623 auto pos = item.opt.find("(");
2624 if (obj && (pos != std::string::npos) && obj->IsA()->GetMethodAllAny(item.opt.substr(0,pos).c_str())) {
2625 std::stringstream exec;
2626 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase
2627 << (size_t)obj << ")->" << item.opt << ";";
2628 if (gDebug > 0)
2629 Info("ProcessObjectOptions", "Obj %s Execute %s", obj->GetName(), exec.str().c_str());
2630 gROOT->ProcessLine(exec.str().c_str());
2631 } else {
2632 Error("ProcessObjectOptions", "Fail to execute %s for object %p %s", item.opt.c_str(), obj, obj ? obj->ClassName() : "---");
2633 objpad = nullptr;
2634 }
2635 return objpad;
2636 }
2637
2638 bool modified = false;
2639
2640 if (obj && lnk) {
2641 auto pos = item.opt.find(";;use_"); // special coding of extra options
2642 if (pos != std::string::npos) item.opt.resize(pos);
2643
2644 if (gDebug > 0)
2645 Info("ProcessObjectOptions", "Set draw option %s for object %s %s", item.opt.c_str(),
2646 obj->ClassName(), obj->GetName());
2647
2648 lnk->SetOption(item.opt.c_str());
2649
2650 modified = true;
2651 }
2652
2653 if (item.fcust.compare(0,10,"auto_exec:") == 0) {
2654 ProcessLinesForObject(obj, item.fcust.substr(10));
2655 } else if (item.fcust.compare("frame") == 0) {
2656 if (obj && obj->InheritsFrom(TFrame::Class())) {
2657 TFrame *frame = static_cast<TFrame *>(obj);
2658 if (item.fopt.size() >= 4) {
2659 frame->SetX1(item.fopt[0]);
2660 frame->SetY1(item.fopt[1]);
2661 frame->SetX2(item.fopt[2]);
2662 frame->SetY2(item.fopt[3]);
2663 modified = true;
2664 }
2665 }
2666 } else if (item.fcust.compare(0,4,"pave") == 0) {
2667 if (obj && obj->InheritsFrom(TPave::Class())) {
2668 TPave *pave = static_cast<TPave *>(obj);
2669 if ((item.fopt.size() >= 4) && objpad) {
2670 TVirtualPad::TContext ctxt(objpad, kFALSE);
2671
2672 // first time need to overcome init problem
2673 pave->ConvertNDCtoPad();
2674
2675 pave->SetX1NDC(item.fopt[0]);
2676 pave->SetY1NDC(item.fopt[1]);
2677 pave->SetX2NDC(item.fopt[2]);
2678 pave->SetY2NDC(item.fopt[3]);
2679 modified = true;
2680
2681 pave->ConvertNDCtoPad();
2682 }
2683 if ((item.fcust.length() > 4) && pave->InheritsFrom(TPaveStats::Class())) {
2684 // add text lines for statsbox
2685 auto stats = static_cast<TPaveStats *>(pave);
2686 stats->Clear();
2687 size_t pos_start = 6, pos_end;
2688 while ((pos_end = item.fcust.find(";;", pos_start)) != std::string::npos) {
2689 stats->AddText(item.fcust.substr(pos_start, pos_end - pos_start).c_str());
2690 pos_start = pos_end + 2;
2691 }
2692 stats->AddText(item.fcust.substr(pos_start).c_str());
2693 }
2694 }
2695 } else if (item.fcust.compare(0,9,"func_fail") == 0) {
2696 if (fTF1UseSave <= 0) {
2697 fTF1UseSave = 1;
2698 modified = true;
2699 }
2700 }
2701
2702 return modified ? objpad : nullptr;
2703}
2704
2705//////////////////////////////////////////////////////////////////////////////////////////////////
2706/// Search of object with given id in list of primitives
2707/// One could specify pad where search could be start
2708/// Also if object is in list of primitives, one could ask for entry link for such object,
2709/// This can allow to change draw option
2710
2711TObject *TWebCanvas::FindPrimitive(const std::string &sid, int idcnt, TPad *pad, TObjLink **objlnk, TPad **objpad)
2712{
2713 if (sid.empty() || (sid == "0"s))
2714 return nullptr;
2715
2716 if (!pad)
2717 pad = Canvas();
2718
2719 std::string subelement;
2720 long unsigned id = 0;
2721 bool search_hist = (sid == sid_pad_histogram);
2722 if (!search_hist) {
2723 auto separ = sid.find("#");
2724
2725 if (separ == std::string::npos) {
2726 id = std::stoul(sid);
2727 } else {
2728 subelement = sid.substr(separ + 1);
2729 id = std::stoul(sid.substr(0, separ));
2730 }
2731 if (TString::Hash(&pad, sizeof(pad)) == id)
2732 return pad;
2733 }
2734
2735 for (auto lnk = pad->GetListOfPrimitives()->FirstLink(); lnk != nullptr; lnk = lnk->Next()) {
2736 TObject *obj = lnk->GetObject();
2737 if (!obj) continue;
2738
2739 if (!search_hist && (TString::Hash(&obj, sizeof(obj)) != id)) {
2740 if (obj->InheritsFrom(TPad::Class())) {
2741 obj = FindPrimitive(sid, idcnt, (TPad *)obj, objlnk, objpad);
2742 if (objpad && !*objpad)
2743 *objpad = pad;
2744 if (obj)
2745 return obj;
2746 }
2747 continue;
2748 }
2749
2750 // one may require to access n-th object
2751 if (!search_hist && --idcnt > 0)
2752 continue;
2753
2754 if (objpad)
2755 *objpad = pad;
2756
2757 if (objlnk)
2758 *objlnk = lnk;
2759
2760 if (search_hist)
2761 subelement = "hist";
2762
2763 auto getHistogram = [](TObject *container) -> TH1* {
2764 auto offset = container->IsA()->GetDataMemberOffset("fHistogram");
2765 if (offset > 0)
2766 return *((TH1 **)((char *)container + offset));
2767 ::Error("getHistogram", "Cannot access fHistogram data member in %s", container->ClassName());
2768 return nullptr;
2769 };
2770
2771 while(!subelement.empty() && obj) {
2772 // do not return link if sub-selement is searched - except for histogram
2773 if (!search_hist && objlnk)
2774 *objlnk = nullptr;
2775
2776 std::string kind = subelement;
2777 auto separ = kind.find("#");
2778 if (separ == std::string::npos) {
2779 subelement.clear();
2780 } else {
2781 kind.resize(separ);
2782 subelement = subelement.substr(separ + 1);
2783 }
2784
2785 TH1 *h1 = obj->InheritsFrom(TH1::Class()) ? static_cast<TH1 *>(obj) : nullptr;
2786 TGraph *gr = obj->InheritsFrom(TGraph::Class()) ? static_cast<TGraph *>(obj) : nullptr;
2787 TGraph2D *gr2d = obj->InheritsFrom(TGraph2D::Class()) ? static_cast<TGraph2D *>(obj) : nullptr;
2788 TScatter *scatter = obj->InheritsFrom(TScatter::Class()) ? static_cast<TScatter *>(obj) : nullptr;
2789 TMultiGraph *mg = obj->InheritsFrom(TMultiGraph::Class()) ? static_cast<TMultiGraph *>(obj) : nullptr;
2790 THStack *hs = obj->InheritsFrom(THStack::Class()) ? static_cast<THStack *>(obj) : nullptr;
2791 TF1 *f1 = obj->InheritsFrom(TF1::Class()) ? static_cast<TF1 *>(obj) : nullptr;
2792
2793 if (kind.compare("hist") == 0) {
2794 if (h1)
2795 obj = h1;
2796 else if (gr)
2797 obj = getHistogram(gr);
2798 else if (mg)
2799 obj = getHistogram(mg);
2800 else if (hs && (hs->GetNhists() > 0))
2801 obj = getHistogram(hs);
2802 else if (scatter)
2803 obj = getHistogram(scatter);
2804 else if (f1)
2805 obj = getHistogram(f1);
2806 else if (gr2d)
2807 obj = getHistogram(gr2d);
2808 else
2809 obj = nullptr;
2810 } else if (kind.compare("x") == 0) {
2811 obj = h1 ? h1->GetXaxis() : nullptr;
2812 } else if (kind.compare("y") == 0) {
2813 obj = h1 ? h1->GetYaxis() : nullptr;
2814 } else if (kind.compare("z") == 0) {
2815 obj = h1 ? h1->GetZaxis() : nullptr;
2816 } else if ((kind.compare(0,5,"func_") == 0) || (kind.compare(0,5,"indx_") == 0)) {
2817 auto funcname = kind.substr(5);
2818 TList *col = nullptr;
2819 if (h1)
2820 col = h1->GetListOfFunctions();
2821 else if (gr)
2822 col = gr->GetListOfFunctions();
2823 else if (mg)
2824 col = mg->GetListOfFunctions();
2825 else if (scatter->GetGraph())
2826 col = scatter->GetGraph()->GetListOfFunctions();
2827 if (!col)
2828 obj = nullptr;
2829 else if (kind.compare(0,5,"func_") == 0)
2830 obj = col->FindObject(funcname.c_str());
2831 else
2832 obj = col->At(std::stoi(funcname));
2833 } else if (kind.compare(0,7,"graphs_") == 0) {
2834 TList *graphs = mg ? mg->GetListOfGraphs() : nullptr;
2835 obj = graphs ? graphs->At(std::stoi(kind.substr(7))) : nullptr;
2836 } else if (kind.compare(0,6,"hists_") == 0) {
2837 TList *hists = hs ? hs->GetHists() : nullptr;
2838 obj = hists ? hists->At(std::stoi(kind.substr(6))) : nullptr;
2839 } else if (kind.compare(0,6,"stack_") == 0) {
2840 auto stack = hs ? hs->GetStack() : nullptr;
2841 obj = stack ? stack->At(std::stoi(kind.substr(6))) : nullptr;
2842 } else if (kind.compare(0,7,"member_") == 0) {
2843 auto member = kind.substr(7);
2844 auto offset = obj->IsA() ? obj->IsA()->GetDataMemberOffset(member.c_str()) : 0;
2845 obj = (offset > 0) ? *((TObject **)((char *) obj + offset)) : nullptr;
2846 } else {
2847 obj = nullptr;
2848 }
2849 }
2850
2851 if (!search_hist || obj)
2852 return obj;
2853 }
2854
2855 return nullptr;
2856}
2857
2858//////////////////////////////////////////////////////////////////////////////////////////////////
2859/// Static method to create TWebCanvas instance
2860/// Used by plugin manager
2861
2863{
2864 Bool_t readonly = gEnv->GetValue("WebGui.FullCanvas", (Int_t) 1) == 0;
2865
2866 auto imp = new TWebCanvas(c, name, x, y, width, height, readonly);
2867
2868 c->fWindowTopX = x;
2869 c->fWindowTopY = y;
2870 c->fWindowWidth = width;
2871 c->fWindowHeight = height;
2872 if (!gROOT->IsBatch() && (height > 25))
2873 height -= 25;
2874 c->fCw = width;
2875 c->fCh = height;
2876
2877 return imp;
2878}
2879
@ kMouseMotion
Definition Buttons.h:23
@ kButton1Double
Definition Buttons.h:24
@ kButton1Up
Definition Buttons.h:19
nlohmann::json json
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
int Int_t
Definition RtypesCore.h:45
unsigned int UInt_t
Definition RtypesCore.h:46
short Font_t
Definition RtypesCore.h:81
constexpr Bool_t kFALSE
Definition RtypesCore.h:94
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:117
long long Long64_t
Definition RtypesCore.h:69
constexpr Bool_t kTRUE
Definition RtypesCore.h:93
R__EXTERN TEnv * gEnv
Definition TEnv.h:170
void Info(const char *location, const char *msgfmt,...)
Use this function for informational messages.
Definition TError.cxx:218
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:185
winID h TVirtualViewer3D TVirtualGLPainter p
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void data
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t hmin
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char filename
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t hmax
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void funcs
Option_t Option_t width
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t src
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t height
char name[80]
Definition TGX11.cxx:110
@ kCanDelete
Definition TObject.h:367
@ kMustCleanup
Definition TObject.h:368
Int_t gDebug
Definition TROOT.cxx:597
#define gROOT
Definition TROOT.h:406
R__EXTERN TStyle * gStyle
Definition TStyle.h:436
@ kReadPermission
Definition TSystem.h:45
R__EXTERN TSystem * gSystem
Definition TSystem.h:561
R__EXTERN TVirtualPS * gVirtualPS
Definition TVirtualPS.h:81
#define gPad
#define gVirtualX
Definition TVirtualX.h:337
static std::vector< WebFont_t > gWebFonts
static const std::string sid_pad_histogram
Color * colors
Definition X3DBuffer.c:21
Holds different arguments for starting browser with RWebDisplayHandle::Display() method.
EBrowserKind GetBrowserKind() const
returns configured browser kind, see EBrowserKind for supported values
void SetStandalone(bool on=true)
Set standalone mode for running browser, default on When disabled, normal browser window (or just tab...
RWebDisplayArgs & SetWidgetKind(const std::string &kind)
set widget kind
RWebDisplayArgs & SetSize(int w, int h)
set preferable web window width and height
RWebDisplayArgs & SetUrl(const std::string &url)
set window url
RWebDisplayArgs & SetPos(int x=-1, int y=-1)
set preferable web window x and y position, negative is default
@ kCEF
Chromium Embedded Framework - local display with CEF libs.
@ kQt5
Qt5 QWebEngine libraries - Chromium code packed in qt5.
@ kQt6
Qt6 QWebEngine libraries - Chromium code packed in qt6.
static bool ProduceImages(const std::string &fname, const std::vector< std::string > &jsons, const std::vector< int > &widths, const std::vector< int > &heights, const char *batch_file=nullptr)
Produce image file(s) using JSON data as source Invokes JSROOT drawing functionality in headless brow...
static std::vector< std::string > ProduceImagesNames(const std::string &fname, unsigned nfiles=1)
Produce vector of file names for specified file pattern Depending from supported file forma.
static std::string GetImageFormat(const std::string &fname)
Detect image format There is special handling of ".screenshot.pdf" and ".screenshot....
static bool ProduceImage(const std::string &fname, const std::string &json, int width=800, int height=600, const char *batch_file=nullptr)
Produce image file using JSON data as source Invokes JSROOT drawing functionality in headless browser...
static std::unique_ptr< RWebDisplayHandle > Display(const RWebDisplayArgs &args)
Create web display.
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
static bool EmbedFileDialog(const std::shared_ptr< RWebWindow > &window, unsigned connid, const std::string &args)
Create dialog instance to use as embedded dialog inside provided widget Loads libROOTBrowserv7 and tr...
static bool IsFileDialogMessage(const std::string &msg)
Check if this could be the message send by client to start new file dialog If returns true,...
static std::map< std::string, std::string > GetServerLocations()
Returns server locations as <std::string, std::string> Key is location name (with slash at the end) a...
Array of integers (32 bits per element).
Definition TArrayI.h:27
const Int_t * GetArray() const
Definition TArrayI.h:43
Int_t GetSize() const
Definition TArray.h:47
static TClass * Class()
virtual void SetFillColor(Color_t fcolor)
Set the fill area color.
Definition TAttFill.h:37
virtual void SetFillStyle(Style_t fstyle)
Set the fill area style.
Definition TAttFill.h:39
virtual void SetBottomMargin(Float_t bottommargin)
Set Pad bottom margin in fraction of the pad height.
Definition TAttPad.cxx:99
virtual void SetLeftMargin(Float_t leftmargin)
Set Pad left margin in fraction of the pad width.
Definition TAttPad.cxx:109
virtual void SetRightMargin(Float_t rightmargin)
Set Pad right margin in fraction of the pad width.
Definition TAttPad.cxx:119
Float_t GetRightMargin() const
Definition TAttPad.h:45
virtual void SetTopMargin(Float_t topmargin)
Set Pad top margin in fraction of the pad height.
Definition TAttPad.cxx:129
virtual void SetTextAlign(Short_t align=11)
Set the text alignment.
Definition TAttText.h:42
virtual void SetTextColor(Color_t tcolor=1)
Set the text color.
Definition TAttText.h:44
virtual void SetTextFont(Font_t tfont=62)
Set the text font.
Definition TAttText.h:46
virtual void SetTextSize(Float_t tsize=1)
Set the text size.
Definition TAttText.h:47
Double_t GetXmax() const
Definition TAxis.h:140
Double_t GetXmin() const
Definition TAxis.h:139
Int_t GetNbins() const
Definition TAxis.h:125
virtual void SetRangeUser(Double_t ufirst, Double_t ulast)
Set the viewing range for the axis from ufirst to ulast (in user coordinates, that is,...
Definition TAxis.cxx:1080
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis using bin numbers.
Definition TAxis.cxx:1052
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
Definition TBase64.cxx:131
static TString Encode(const char *data)
Transform data into a null terminated base64 string.
Definition TBase64.cxx:107
virtual void SetY2(Double_t y2)
Definition TBox.h:65
virtual void SetX1(Double_t x1)
Definition TBox.h:62
virtual void SetX2(Double_t x2)
Definition TBox.h:63
virtual void SetY1(Double_t y1)
Definition TBox.h:64
static Int_t ExportToFile(const char *filename, const TObject *obj, const char *option=nullptr)
Convert object into JSON and store in text file Returns size of the produce file Used in TObject::Sav...
static TString ToJSON(const T *obj, Int_t compact=0, const char *member_name=nullptr)
Definition TBufferJSON.h:75
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition TBufferJSON.h:39
@ kMapAsObject
store std::map, std::unordered_map as JSON object
Definition TBufferJSON.h:41
@ kSameSuppression
zero suppression plus compress many similar values together
Definition TBufferJSON.h:45
A TButton object is a user interface object.
Definition TButton.h:18
static TClass * Class()
ABC describing GUI independent main window (with menubar, scrollbars and a drawing area).
Definition TCanvasImp.h:30
TCanvas * Canvas() const
Definition TCanvasImp.h:58
void SetScripts(const std::string &src)
void SetFixedSize(bool on=true)
void SetHighlightConnect(bool on=true)
The Canvas class.
Definition TCanvas.h:23
UInt_t fCw
Width of the canvas along X (pixels)
Definition TCanvas.h:43
UInt_t GetWindowHeight() const
Definition TCanvas.h:162
void SetClickSelectedPad(TPad *pad)
Definition TCanvas.h:211
Int_t fWindowTopX
Top X position of window (in pixels)
Definition TCanvas.h:39
Int_t fEventX
! Last X mouse position in canvas
Definition TCanvas.h:46
TVirtualPadPainter * GetCanvasPainter()
Access and (probably) creation of pad painter.
Definition TCanvas.cxx:2616
UInt_t fWindowWidth
Width of window (including borders, etc.)
Definition TCanvas.h:41
Int_t fEventY
! Last Y mouse position in canvas
Definition TCanvas.h:47
UInt_t fWindowHeight
Height of window (including menubar, borders, etc.)
Definition TCanvas.h:42
TObject * fSelected
! Currently selected object
Definition TCanvas.h:49
UInt_t fCh
Height of the canvas along Y (pixels)
Definition TCanvas.h:44
UInt_t GetWindowWidth() const
Definition TCanvas.h:161
Int_t fWindowTopY
Top Y position of window (in pixels)
Definition TCanvas.h:40
void SetClickSelected(TObject *obj)
Definition TCanvas.h:209
@ kShowToolTips
Definition TCanvas.h:97
@ kShowEventStatus
Definition TCanvas.h:89
@ kMenuBar
Definition TCanvas.h:91
@ kShowEditor
Definition TCanvas.h:93
UInt_t GetWw() const override
Definition TCanvas.h:163
UInt_t GetWh() const override
Definition TCanvas.h:164
virtual void Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
Emit Highlighted() signal.
Definition TCanvas.cxx:1612
static TClass * Class()
Int_t fEvent
! Type of current or last handled event
Definition TCanvas.h:45
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:81
Longptr_t GetDataMemberOffset(const char *membername) const
return offset for member name.
Definition TClass.cxx:3477
Int_t Size() const
Return size of object of this class.
Definition TClass.cxx:5704
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4874
TMethod * GetMethodAllAny(const char *method)
Return pointer to method without looking at parameters.
Definition TClass.cxx:4384
void SetName(const char *name)
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
The color creation and management class.
Definition TColor.h:21
static const TArrayI & GetPalette()
Static function returning the current active palette.
Definition TColor.cxx:1516
static TClass * Class()
static Bool_t DefinedColors(Int_t set_always_on=0)
Static method returning kTRUE if some new colors have been defined after initialisation or since the ...
Definition TColor.cxx:1537
static TClass * Class()
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
TExec is a utility class that can be used to execute a C++ command when some event happens in a pad.
Definition TExec.h:26
virtual void Exec(const char *command="")
Execute the command referenced by this object.
Definition TExec.cxx:143
static TClass * Class()
1-Dim function class
Definition TF1.h:233
virtual TH1 * GetHistogram() const
Return a pointer to the histogram used to visualise the function Note that this histogram is managed ...
Definition TF1.cxx:1584
static TClass * Class()
@ kNotDraw
Definition TF1.h:346
virtual Bool_t IsValid() const
Return kTRUE if the function is valid.
Definition TF1.cxx:2880
virtual void Save(Double_t xmin, Double_t xmax, Double_t ymin, Double_t ymax, Double_t zmin, Double_t zmax)
Save values of function in array fSave.
Definition TF1.cxx:3159
TClass * IsA() const override
Definition TF1.h:755
Bool_t HasSave() const
Return true if function has data in fSave buffer.
Definition TF1.h:466
static TClass * Class()
Define a Frame.
Definition TFrame.h:19
static TClass * Class()
The axis painter class.
Definition TGaxis.h:24
static TClass * Class()
TF1 * GetFunction() const
Definition TGaxis.h:77
Graphics object made of three arrays X, Y and Z with the same number of points each.
Definition TGraph2D.h:41
static TClass * Class()
TH2D * GetHistogram(Option_t *option="")
By default returns a pointer to the Delaunay histogram.
TList * GetListOfFunctions() const
Definition TGraph2D.h:112
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
static TClass * Class()
@ kNoStats
Don't draw stats box.
Definition TGraph.h:75
TList * GetListOfFunctions() const
Definition TGraph.h:126
virtual TH1F * GetHistogram() const
Returns a pointer to the histogram used to draw the axis Takes into account the two following cases.
Definition TGraph.cxx:1428
1-D histogram with a double per channel (see TH1 documentation)
Definition TH1.h:670
TH1K class supports the nearest K Neighbours method, widely used in cluster analysis.
Definition TH1K.h:26
Double_t GetBinContent(Int_t bin) const override
Return content of global bin number bin.
Definition TH1K.cxx:116
static TClass * Class()
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:59
virtual void SetDirectory(TDirectory *dir)
By default, when a histogram is created, it is added to the list of histogram objects in the current ...
Definition TH1.cxx:8928
TAxis * GetZaxis()
Definition TH1.h:326
static TClass * Class()
virtual Int_t GetDimension() const
Definition TH1.h:283
@ kNoTitle
Don't draw the histogram title.
Definition TH1.h:170
@ kIsZoomed
Bit set when zooming on Y axis.
Definition TH1.h:169
TAxis * GetXaxis()
Definition TH1.h:324
virtual void SetMaximum(Double_t maximum=-1111)
Definition TH1.h:404
TAxis * GetYaxis()
Definition TH1.h:325
virtual void SetMinimum(Double_t minimum=-1111)
Definition TH1.h:405
virtual void SetBinContent(Int_t bin, Double_t content)
Set bin content see convention for numbering bins in TH1::GetBin In case the bin number is greater th...
Definition TH1.cxx:9213
virtual Double_t GetEntries() const
Return the current number of entries.
Definition TH1.cxx:4423
TList * GetListOfFunctions() const
Definition TH1.h:244
void SetName(const char *name) override
Change the name of this histogram.
Definition TH1.cxx:8951
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Definition TH1.cxx:1414
The Histogram stack class.
Definition THStack.h:40
TList * GetHists() const
Definition THStack.h:72
TObjArray * GetStack()
Return pointer to Stack. Build it if not yet done.
Definition THStack.cxx:607
Int_t GetNhists() const
Return the number of histograms in the stack.
Definition THStack.cxx:598
static TClass * Class()
static char * ReadFileContent(const char *filename, Int_t &len)
Reads content of file from the disk.
Option_t * GetOption() const
void Reset()
A doubly linked list.
Definition TList.h:38
TObject * FindObject(const char *name) const override
Find an object in this list using its name.
Definition TList.cxx:576
void Add(TObject *obj) override
Definition TList.h:83
TObject * Last() const override
Return the last object in the list. Returns 0 when list is empty.
Definition TList.cxx:691
virtual TObjLink * FirstLink() const
Definition TList.h:104
TObject * At(Int_t idx) const override
Returns the object at position idx. Returns 0 if idx is out of range.
Definition TList.cxx:355
void AddFirst(TObject *obj) override
Add object at the beginning of the list.
Definition TList.cxx:98
A TMultiGraph is a collection of TGraph (or derived) objects.
Definition TMultiGraph.h:34
TList * GetListOfGraphs() const
Definition TMultiGraph.h:68
static TClass * Class()
TList * GetListOfFunctions()
Return pointer to list of functions.
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
const char * GetName() const override
Returns name of object.
Definition TNamed.h:47
const char * GetTitle() const override
Returns title of object.
Definition TNamed.h:48
An array of TObjects.
Definition TObjArray.h:31
Mother of all ROOT objects.
Definition TObject.h:41
virtual const char * GetName() const
Returns name of object.
Definition TObject.cxx:444
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:199
virtual TObject * Clone(const char *newname="") const
Make a clone of an object using the Streamer facility.
Definition TObject.cxx:229
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:213
virtual TObject * FindObject(const char *name) const
Must be redefined in derived classes.
Definition TObject.cxx:408
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:786
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:530
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:488
virtual TClass * IsA() const
Definition TObject.h:243
virtual void Paint(Option_t *option="")
This method must be overridden if a class wants to paint itself.
Definition TObject.cxx:612
TPadWebSnapshot & NewSubPad()
Create new entry for subpad.
TWebSnapshot & NewPrimitive(TObject *obj=nullptr, const std::string &opt="", const std::string &suffix="")
Create new entry in list of primitives.
TWebSnapshot & NewSpecials()
Create new entry in list of primitives in the front.
void SetHasExecs(bool on=true)
void SetWithoutPrimitives(bool on=true)
void SetActive(bool on=true)
bool IsSetObjectIds() const
bool IsBatchMode() const
The most important graphics class in the ROOT system.
Definition TPad.h:28
Int_t GetTicky() const override
Definition TPad.h:239
Double_t fAbsYlowNDC
Absolute Y top left corner of pad in NDC [0,1].
Definition TPad.h:70
Double_t fXtoAbsPixelk
Conversion coefficient for X World to absolute pixel.
Definition TPad.h:41
virtual void DivideSquare(Int_t n, Float_t xmargin=0.01, Float_t ymargin=0.01, Int_t color=0)
"n" is the total number of sub-pads.
Definition TPad.cxx:1341
static TClass * Class()
Double_t fWNDC
Width of pad along X in Normalized Coordinates (NDC)
Definition TPad.h:66
void SetView(TView *view=nullptr) override
Set the current TView. Delete previous view if view=0.
Definition TPad.cxx:6195
TVirtualViewer3D * GetViewer3D(Option_t *type="") override
Create/obtain handle to 3D viewer.
Definition TPad.cxx:7151
Double_t fPixeltoYk
Conversion coefficient for pixel to Y World.
Definition TPad.h:59
void SetGrid(Int_t valuex=1, Int_t valuey=1) override
Definition TPad.h:335
Double_t fPhi
phi angle to view as lego/surface
Definition TPad.h:80
Double_t fPixeltoY
yworld = fPixeltoYk + fPixeltoY*ypixel
Definition TPad.h:60
Double_t fAbsXlowNDC
Absolute X top left corner of pad in NDC [0,1].
Definition TPad.h:69
TList * GetListOfExecs() const override
Definition TPad.h:246
void Divide(Int_t nx=1, Int_t ny=1, Float_t xmargin=0.01, Float_t ymargin=0.01, Int_t color=0) override
Automatic pad generation by division.
Definition TPad.cxx:1249
Double_t fXtoPixel
xpixel = fXtoPixelk + fXtoPixel*xworld
Definition TPad.h:43
Bool_t GetGridx() const override
Definition TPad.h:235
Double_t fX2
X of upper X coordinate.
Definition TPad.h:38
Double_t fPixeltoX
xworld = fPixeltoXk + fPixeltoX*xpixel
Definition TPad.h:57
Double_t fYtoPixel
ypixel = fYtoPixelk + fYtoPixel*yworld
Definition TPad.h:46
Double_t fAbsWNDC
Absolute Width of pad along X in NDC.
Definition TPad.h:71
TObject * Remove(TObject *obj, Bool_t modified=kTRUE) override
Remove object from list of primitives When.
Definition TPad.cxx:5407
UInt_t GetWw() const override
Get Ww.
Definition TPad.cxx:2837
Double_t fX1
X of lower X coordinate.
Definition TPad.h:36
TList * GetListOfPrimitives() const override
Definition TPad.h:245
Double_t fUymin
Minimum value on the Y axis.
Definition TPad.h:75
Int_t fLogz
(=0 if Z linear scale, =1 if log scale)
Definition TPad.h:93
Double_t fYtoPixelk
Conversion coefficient for Y World to pixel.
Definition TPad.h:45
Double_t fPixeltoXk
Conversion coefficient for pixel to X World.
Definition TPad.h:56
Bool_t IsModified() const override
Definition TPad.h:274
Double_t fY1
Y of lower Y coordinate.
Definition TPad.h:37
Double_t fYlowNDC
Y bottom left corner of pad in NDC [0,1].
Definition TPad.h:63
Double_t fAbsPixeltoXk
Conversion coefficient for absolute pixel to X World.
Definition TPad.h:55
void Clear(Option_t *option="") override
Delete all pad primitives.
Definition TPad.cxx:722
Int_t GetTickx() const override
Definition TPad.h:238
Double_t fUymax
Maximum value on the Y axis.
Definition TPad.h:77
TVirtualPad * GetMother() const override
Definition TPad.h:259
void Modified(Bool_t flag=true) override
Mark pad modified Will be repainted when TCanvas::Update() will be called next time.
Definition TPad.cxx:7369
TView * GetView() const override
Definition TPad.h:254
TClass * IsA() const override
Definition TPad.h:419
Bool_t GetGridy() const override
Definition TPad.h:236
Double_t fAbsHNDC
Absolute Height of pad along Y in NDC.
Definition TPad.h:72
void SetFixedAspectRatio(Bool_t fixed=kTRUE) override
Fix pad aspect ratio to current value if fixed is true.
Definition TPad.cxx:6031
Int_t fLogx
(=0 if X linear scale, =1 if log scale)
Definition TPad.h:91
Double_t GetAbsWNDC() const override
Definition TPad.h:222
UInt_t GetWh() const override
Get Wh.
Definition TPad.cxx:2829
TCanvas * GetCanvas() const override
Definition TPad.h:262
void Add(TObject *obj, Option_t *opt="", Bool_t modified=kTRUE) override
Add an object to list of primitives with speicified draw option When.
Definition TPad.cxx:418
Double_t fTheta
theta angle to view as lego/surface
Definition TPad.h:79
Double_t fXUpNDC
Definition TPad.h:64
TVirtualPad * cd(Int_t subpadnumber=0) override
Set Current pad.
Definition TPad.cxx:693
void Print(const char *filename="") const override
This method is equivalent to SaveAs("filename"). See TPad::SaveAs for details.
Definition TPad.cxx:4798
TFrame * GetFrame() override
Get frame.
Definition TPad.cxx:2955
Double_t fYUpNDC
Definition TPad.h:65
Double_t fYtoAbsPixelk
Conversion coefficient for Y World to absolute pixel.
Definition TPad.h:44
Double_t fXtoPixelk
Conversion coefficient for X World to pixel.
Definition TPad.h:42
Int_t fLogy
(=0 if Y linear scale, =1 if log scale)
Definition TPad.h:92
Double_t fHNDC
Height of pad along Y in Normalized Coordinates (NDC)
Definition TPad.h:67
Double_t fXlowNDC
X bottom left corner of pad in NDC [0,1].
Definition TPad.h:62
Double_t fUxmin
Minimum value on the X axis.
Definition TPad.h:74
Double_t GetAbsHNDC() const override
Definition TPad.h:223
void SetTicks(Int_t valuex=1, Int_t valuey=1) override
Definition TPad.h:355
Double_t fUxmax
Maximum value on the X axis.
Definition TPad.h:76
Double_t fY2
Y of upper Y coordinate.
Definition TPad.h:39
Double_t fAbsPixeltoYk
Conversion coefficient for absolute pixel to Y World.
Definition TPad.h:58
const char * GetName() const override
Returns name of object.
Definition TPad.h:260
The histogram statistics painter class.
Definition TPaveStats.h:18
virtual void SetStatFormat(const char *format="6.4g")
Change (i.e. set) the format for printing statistics.
virtual void SetFitFormat(const char *format="5.4g")
Change (i.e. set) the format for printing fit parameters in statistics box.
void SetParent(TObject *obj) override
Definition TPaveStats.h:52
static TClass * Class()
A Pave (see TPave) with text, lines or/and boxes inside.
Definition TPaveText.h:21
virtual TText * AddText(Double_t x1, Double_t y1, const char *label)
Add a new Text line to this pavetext at given coordinates.
static TClass * Class()
void Clear(Option_t *option="") override
Clear all lines in this pavetext.
virtual TText * GetLine(Int_t number) const
Get Pointer to line number in this pavetext.
A TBox with a bordersize and a shadow option.
Definition TPave.h:19
virtual void SetY1NDC(Double_t y1)
Definition TPave.h:84
virtual void ConvertNDCtoPad()
Convert pave coordinates from NDC to Pad coordinates.
Definition TPave.cxx:139
virtual void SetName(const char *name="")
Definition TPave.h:79
virtual void SetBorderSize(Int_t bordersize=4)
Sets the border size of the TPave box and shadow.
Definition TPave.h:77
virtual void SetY2NDC(Double_t y2)
Definition TPave.h:85
static TClass * Class()
virtual void SetX1NDC(Double_t x1)
Definition TPave.h:82
virtual void SetX2NDC(Double_t x2)
Definition TPave.h:83
A TScatter is able to draw four variables scatter plot on a single plot.
Definition TScatter.h:32
TGraph * GetGraph() const
Get the graph holding X and Y positions.
Definition TScatter.h:58
TH2F * GetHistogram() const
Get the graph histogram used for drawing axis.
Definition TScatter.cxx:166
static TClass * Class()
Basic string class.
Definition TString.h:139
Ssiz_t Length() const
Definition TString.h:417
void ToLower()
Change string to lower-case.
Definition TString.cxx:1182
Bool_t EndsWith(const char *pat, ECaseCompare cmp=kExact) const
Return true if string ends with the specified string.
Definition TString.cxx:2244
TSubString Strip(EStripType s=kTrailing, char c=' ') const
Return a substring of self stripped at beginning and/or end.
Definition TString.cxx:1163
const char * Data() const
Definition TString.h:376
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition TString.cxx:1152
@ kBoth
Definition TString.h:276
@ kIgnoreCase
Definition TString.h:277
Ssiz_t Last(char c) const
Find last occurrence of a character c.
Definition TString.cxx:931
void ToUpper()
Change string to upper case.
Definition TString.cxx:1195
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:677
TString & Append(const char *cs)
Definition TString.h:572
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition TString.cxx:2378
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:632
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:651
Int_t GetOptStat() const
Definition TStyle.h:245
Color_t GetStatTextColor() const
Definition TStyle.h:258
Int_t GetOptTitle() const
Definition TStyle.h:246
Float_t GetStatFontSize() const
Definition TStyle.h:261
Float_t GetStatX() const
Definition TStyle.h:264
Float_t GetPadRightMargin() const
Definition TStyle.h:214
Style_t GetTitleFont(Option_t *axis="X") const
Return title font.
Definition TStyle.cxx:1216
Float_t GetStatY() const
Definition TStyle.h:265
Color_t GetTitleFillColor() const
Definition TStyle.h:271
Style_t GetTitleStyle() const
Definition TStyle.h:273
Color_t GetStatColor() const
Definition TStyle.h:257
Float_t GetStatH() const
Definition TStyle.h:267
static TClass * Class()
Width_t GetTitleBorderSize() const
Definition TStyle.h:275
Width_t GetStatBorderSize() const
Definition TStyle.h:259
Color_t GetTitleTextColor() const
Definition TStyle.h:272
Style_t GetStatStyle() const
Definition TStyle.h:262
Float_t GetStatW() const
Definition TStyle.h:266
const char * GetFitFormat() const
Definition TStyle.h:199
const char * GetStatFormat() const
Definition TStyle.h:263
Style_t GetStatFont() const
Definition TStyle.h:260
Float_t GetTitleFontSize() const
Definition TStyle.h:274
virtual Bool_t ExpandPathName(TString &path)
Expand a pathname getting rid of special shell characters like ~.
Definition TSystem.cxx:1274
virtual Bool_t AccessPathName(const char *path, EAccessMode mode=kFileExists)
Returns FALSE if one can access a file using the specified access mode.
Definition TSystem.cxx:1296
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:437
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:416
static Long_t SelfId()
Static method returning the id for the current thread.
Definition TThread.cxx:549
Handles synchronous and a-synchronous timer events.
Definition TTimer.h:51
virtual void TurnOn()
Add the timer to the system timer list.
Definition TTimer.cxx:243
void SetTime(Long_t milliSec)
Definition TTimer.h:91
See TView3D.
Definition TView.h:25
static TView * CreateView(Int_t system=1, const Double_t *rmin=nullptr, const Double_t *rmax=nullptr)
Create a concrete default 3-d view via the plug-in manager.
Definition TView.cxx:27
virtual void SetAutoRange(Bool_t autorange=kTRUE)=0
TVirtualPS is an abstract interface to Postscript, PDF, SVG.
Definition TVirtualPS.h:30
To make it possible to use GL for 2D graphic in a TPad/TCanvas.
small helper class to store/restore gPad context in TPad methods
Definition TVirtualPad.h:61
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:51
Semi-Abstract base class defining a generic interface to the underlying, low level,...
Definition TVirtualX.h:46
void SetSlow(Bool_t slow=kTRUE)
TWebCanvasTimer(TWebCanvas &canv)
Bool_t IsSlow() const
void Timeout() override
used to send control messages to clients
TWebCanvas & fCanv
Basic TCanvasImp ABI implementation for Web-based Graphics Provides painting of main ROOT classes in ...
Definition TWebCanvas.h:35
TVirtualPadPainter * CreatePadPainter() override
Creates web-based pad painter.
void ForceUpdate() override
Increment canvas version and force sending data to client - do not wait for reply.
static void AddCustomClass(const std::string &clname, bool with_derived=false)
Assign custom class.
static TString CreatePadJSON(TPad *pad, Int_t json_compression=0, Bool_t batchmode=kFALSE)
Create JSON painting output for given pad Produce JSON can be used for offline drawing with JSROOT.
void SetCanvasSize(UInt_t w, UInt_t h) override
Set canvas size of web canvas.
UInt_t fColorsHash
! last hash of colors/palette
Definition TWebCanvas.h:106
Int_t fTF1UseSave
! use save buffer for TF1/TF2, 0:off, 1:prefer, 2:force
Definition TWebCanvas.h:107
void ShowCmd(const std::string &arg, Bool_t show)
Function used to send command to browser to toggle menu, toolbar, editors, ...
Long64_t fColorsVersion
! current colors/palette version, checked every time when new snapshot created
Definition TWebCanvas.h:105
virtual Bool_t IsReadOnly() const
Definition TWebCanvas.h:194
std::shared_ptr< ROOT::RWebWindow > fWindow
Definition TWebCanvas.h:88
virtual Bool_t IsJSSupportedClass(TObject *obj, Bool_t many_primitives=kFALSE)
Returns kTRUE when object is fully supported on JSROOT side In ROOT7 Paint function will just return ...
void AddCtrlMsg(unsigned connid, const std::string &key, const std::string &value)
Add control message for specified connection Same control message can be overwritten many time before...
static void SetCustomScripts(const std::string &src)
Configures custom script for canvas.
ObjectSelectSignal_t fObjSelectSignal
! signal emitted when new object selected in the pad
Definition TWebCanvas.h:115
PadClickedSignal_t fPadClickedSignal
! signal emitted when simple mouse click performed on the pad
Definition TWebCanvas.h:113
void SetLongerPolling(Bool_t on)
Definition TWebCanvas.h:250
UInt_t fStyleHash
! last hash of gStyle
Definition TWebCanvas.h:104
virtual Bool_t CanCreateObject(const std::string &)
Definition TWebCanvas.h:170
void ShowWebWindow(const ROOT::RWebDisplayArgs &user_args="")
Show canvas in specified place.
Int_t fPrimitivesMerge
! number of PS primitives, which will be merged together
Definition TWebCanvas.h:97
void Show() override
Show canvas in browser window.
Bool_t WaitWhenCanvasPainted(Long64_t ver)
Wait when specified version of canvas was painted and confirmed by browser.
static UInt_t gBatchImageMode
! configured batch size
Definition TWebCanvas.h:122
static std::string gCustomScripts
! custom JavaScript code or URL on JavaScript files to load before start drawing
Definition TWebCanvas.h:119
Bool_t IsAsyncMode() const
Definition TWebCanvas.h:254
UInt_t CalculateColorsHash()
Calculate hash function for all colors and palette.
void SetWindowGeometry(const std::vector< int > &arr)
Set window geometry as array with coordinates and dimensions.
Bool_t HasStatusBar() const override
Returns kTRUE if web canvas has status bar.
static std::vector< std::string > gCustomClasses
! list of custom classes, which can be delivered as is to client
Definition TWebCanvas.h:120
void Close() override
Close web canvas - not implemented.
static bool ProduceImages(std::vector< TPad * > pads, const char *filename, Int_t width=0, Int_t height=0)
Create images for several pads using batch (headless) capability of Chrome or Firefox browsers Suppor...
Bool_t HasMenuBar() const override
Returns kTRUE if web canvas has menu bar.
Int_t InitWindow() override
Initialize window for the web canvas At this place canvas is not yet register to the list of canvases...
void CheckPadModified(TPad *pad)
Returns true if any pad in the canvas were modified Reset modified flags, increment canvas version (i...
void RaiseWindow() override
Raise browser window.
static bool ProduceImage(TPad *pad, const char *filename, Int_t width=0, Int_t height=0)
Create image using batch (headless) capability of Chrome or Firefox browsers Supported png,...
void ActivateInEditor(TPad *pad, TObject *obj)
Activate object in editor in web browser.
std::vector< WebConn > fWebConn
! connections
Definition TWebCanvas.h:83
PadSignal_t fActivePadChangedSignal
! signal emitted when active pad changed in the canvas
Definition TWebCanvas.h:112
Bool_t GetLongerPolling() const
Definition TWebCanvas.h:251
UInt_t fClientBits
! latest status bits from client like editor visible or not
Definition TWebCanvas.h:92
std::function< void(TPadWebSnapshot *)> PadPaintingReady_t
Function called when pad painting produced.
Definition TWebCanvas.h:55
Int_t fPaletteDelivery
! colors palette delivery 0:never, 1:once, 2:always, 3:per subpad
Definition TWebCanvas.h:96
Bool_t fProcessingData
! flag used to prevent blocking methods when process data is invoked
Definition TWebCanvas.h:101
Bool_t HasToolTips() const override
Returns kTRUE if tooltips are activated in web canvas.
std::vector< TPad * > fAllPads
! list of all pads recognized during streaming
Definition TWebCanvas.h:93
friend class TWebCanvasTimer
Definition TWebCanvas.h:37
TWebCanvasTimer * fTimer
! timer to submit control messages
Definition TWebCanvas.h:84
static std::vector< std::string > gBatchJsons
! converted jsons batch job
Definition TWebCanvas.h:125
Long64_t fCanvVersion
! actual canvas version, changed with every new Modified() call
Definition TWebCanvas.h:91
std::vector< int > fWindowGeometry
! last received window geometry
Definition TWebCanvas.h:108
TPad * ProcessObjectOptions(TWebObjectOptions &item, TPad *pad, int idcnt=1)
Process data for single primitive Returns object pad if object was modified.
void CreateObjectSnapshot(TPadWebSnapshot &master, TPad *pad, TObject *obj, const char *opt, TWebPS *masterps=nullptr)
Creates representation of the object for painting in web browser.
std::map< TObject *, bool > fUsedObjs
! map of used objects during streaming
Definition TWebCanvas.h:94
void AddColorsPalette(TPadWebSnapshot &master)
Add special canvas objects with list of colors and color palette.
Long64_t fStyleVersion
! current gStyle object version, checked every time when new snapshot created
Definition TWebCanvas.h:103
static std::string gBatchMultiPdf
! name of current multi-page pdf file
Definition TWebCanvas.h:123
static void BatchImageMode(UInt_t n=100)
Configure batch image mode for web graphics.
std::vector< std::unique_ptr< ROOT::RWebDisplayHandle > > fHelpHandles
! array of handles for help widgets
Definition TWebCanvas.h:117
void AddSendQueue(unsigned connid, const std::string &msg)
Add message to send queue for specified connection If connid == 0, message will be add to all connect...
void SetWindowPosition(Int_t x, Int_t y) override
Set window position of web canvas.
UpdatedSignal_t fUpdatedSignal
! signal emitted when canvas updated or state is changed
Definition TWebCanvas.h:111
Int_t fJsonComp
! compression factor for messages send to the client
Definition TWebCanvas.h:98
static std::vector< int > gBatchWidths
! batch job widths
Definition TWebCanvas.h:126
~TWebCanvas() override
Destructor.
static std::string ProcessCustomScripts(bool batch)
For batch mode special handling of scripts are required Headless browser not able to load modules fro...
Bool_t fReadOnly
!< configured display
Definition TWebCanvas.h:90
std::map< TPad *, PadStatus > fPadsStatus
! map of pads in canvas and their status flags
Definition TWebCanvas.h:86
static Font_t AddFont(const char *name, const char *ttffile, Int_t precision=2)
Add font to static list of fonts supported by the canvas Name specifies name of the font,...
void AddCustomFonts(TPadWebSnapshot &master)
Add special canvas objects with custom fonts.
Bool_t CheckDataToSend(unsigned connid=0)
Check if any data should be send to client If connid != 0, only selected connection will be checked.
Bool_t PerformUpdate(Bool_t async) override
if canvas or any subpad was modified, scan all primitives in the TCanvas and subpads and convert them...
void AssignStatusBits(UInt_t bits)
Assign clients bits.
virtual Bool_t ProcessData(unsigned connid, const std::string &arg)
Handle data from web browser Returns kFALSE if message was not processed.
void ProcessLinesForObject(TObject *obj, const std::string &lines)
Execute one or several methods for selected object String can be separated by ";;" to let execute sev...
TWebCanvas(TCanvas *c, const char *name, Int_t x, Int_t y, UInt_t width, UInt_t height, Bool_t readonly=kTRUE)
Constructor.
static std::vector< int > gBatchHeights
! batch job heights
Definition TWebCanvas.h:127
static Int_t StoreCanvasJSON(TCanvas *c, const char *filename, const char *option="")
Create JSON painting output for given canvas and store into the file See TBufferJSON::ExportToFile() ...
static const std::string & GetCustomScripts()
Returns configured custom script.
void Iconify() override
Iconify browser window.
void SetWindowTitle(const char *newTitle) override
Set window title of web canvas.
UInt_t GetWindowGeometry(Int_t &x, Int_t &y, UInt_t &w, UInt_t &h) override
Returns window geometry including borders and menus.
static std::vector< std::string > gBatchFiles
! file names for batch job
Definition TWebCanvas.h:124
static TCanvasImp * NewCanvas(TCanvas *c, const char *name, Int_t x, Int_t y, UInt_t width, UInt_t height)
Static method to create TWebCanvas instance Used by plugin manager.
static TString CreateCanvasJSON(TCanvas *c, Int_t json_compression=0, Bool_t batchmode=kFALSE)
Create JSON painting output for given canvas Produce JSON can be used for offline drawing with JSROOT...
Bool_t HasEditor() const override
Returns kTRUE if web canvas has graphical editor.
Int_t fStyleDelivery
! gStyle delivery to clients: 0:never, 1:once, 2:always
Definition TWebCanvas.h:95
PadClickedSignal_t fPadDblClickedSignal
! signal emitted when simple mouse click performed on the pad
Definition TWebCanvas.h:114
void ProcessExecs(TPad *pad, TExec *extra=nullptr)
Process TExec objects in the pad.
static bool FlushBatchImages()
Flush batch images.
void CreatePadSnapshot(TPadWebSnapshot &paddata, TPad *pad, Long64_t version, PadPaintingReady_t func)
Create snapshot for pad and all primitives Callback function is used to create JSON in the middle of ...
Bool_t CheckCanvasModified(bool force_modified=false)
Check if any pad on the canvas was modified If yes, increment version of correspondent pad Returns tr...
virtual Bool_t DecodePadOptions(const std::string &, bool process_execs=false)
Decode all pad options, which includes ranges plus objects options.
Int_t GetPaletteDelivery() const
Definition TWebCanvas.h:245
void SetWindowSize(UInt_t w, UInt_t h) override
Set window size of web canvas.
static bool IsCustomClass(const TClass *cl)
Checks if class belongs to custom.
TObject * FindPrimitive(const std::string &id, int idcnt=1, TPad *pad=nullptr, TObjLink **objlnk=nullptr, TPad **objpad=nullptr)
Search of object with given id in list of primitives One could specify pad where search could be star...
Bool_t fFixedSize
! is canvas size fixed
Definition TWebCanvas.h:109
Int_t GetStyleDelivery() const
Definition TWebCanvas.h:242
void PopulateObjectMenu(void *obj, TClass *cl)
Class used to transport drawing options from the client.
std::vector< double > fopt
custom float array
std::string fcust
custom string
std::string snapid
id of the object
std::string opt
drawing options
void CreatePainting()
Definition TWebPS.cxx:26
Bool_t IsEmptyPainting() const
Definition TWebPS.h:32
TWebPainting * TakePainting()
Definition TWebPS.h:34
TWebPainting * GetPainting()
Definition TWebPS.h:33
Implement TVirtualPadPainter which abstracts painting operations.
Object used to store paint operations and deliver them to JSROOT.
void AddColor(Int_t indx, TColor *col)
Add custom color to operations.
void AddOper(const std::string &oper)
Add next custom operator to painting Operations are separated by semicolons Following operations are ...
@ kStyle
gStyle object
@ kObject
object itself
@ kSVG
list of SVG primitives
@ kSubPad
subpad
@ kFont
custom web font
@ kColors
list of ROOT colors + palette
void SetSnapshot(Int_t kind, TObject *snapshot, Bool_t owner=kFALSE)
SetUse pointer to assign object id - TString::Hash.
void SetObjectIDAsPtr(void *ptr, const std::string &suffix="")
Use pointer to assign object id - TString::Hash.
Double_t y[n]
Definition legend1.C:17
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16
TGraphErrors * gr
Definition legend1.C:25
TH1F * h1
Definition legend1.C:5
TF1 * f1
Definition legend1.C:11
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:721
bool _detected
! if pad was detected during last scan
Definition TWebCanvas.h:78
TString fName
TString fFormat
WebFont_t()=default
TString fData
WebFont_t(Int_t indx, const TString &name, const TString &fmt, const TString &data)