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-2021, 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"
17
18#include "TSystem.h"
19#include "TStyle.h"
20#include "TCanvas.h"
21#include "TFrame.h"
22#include "TPaveText.h"
23#include "TPaveStats.h"
24#include "TText.h"
25#include "TROOT.h"
26#include "TClass.h"
27#include "TColor.h"
28#include "TObjArray.h"
29#include "TArrayI.h"
30#include "TList.h"
31#include "TH1.h"
32#include "TEnv.h"
33#include "TError.h"
34#include "TGraph.h"
35#include "TBufferJSON.h"
36#include "TBase64.h"
37#include "TAtt3D.h"
38#include "TView.h"
39
40#include <cstdio>
41#include <cstring>
42#include <fstream>
43#include <iostream>
44#include <memory>
45#include <sstream>
46
47/** \class TWebCanvas
48\ingroup webgui6
49
50Basic TCanvasImp ABI implementation for Web-based GUI
51Provides painting of main ROOT6 classes in web browsers
52Major interactive features implemented in TWebCanvasFull class.
53
54*/
55
56using namespace std::string_literals;
57
58////////////////////////////////////////////////////////////////////////////////
59/// Constructor
60
62 : TCanvasImp(c, name, x, y, width, height)
63{
64 fReadOnly = readonly;
65 fStyleDelivery = gEnv->GetValue("WebGui.StyleDelivery", 1);
66 fPaletteDelivery = gEnv->GetValue("WebGui.PaletteDelivery", 1);
67 fPrimitivesMerge = gEnv->GetValue("WebGui.PrimitivesMerge", 100);
69}
70
71////////////////////////////////////////////////////////////////////////////////
72/// Initialize window for the web canvas
73/// At this place canvas is not yet register to the list of canvases - one cannot call RWebWindow::Show()
74
76{
77 return 111222333; // should not be used at all
78}
79
80////////////////////////////////////////////////////////////////////////////////
81/// Creates web-based pad painter
82
84{
85 return new TWebPadPainter();
86}
87
88////////////////////////////////////////////////////////////////////////////////
89/// Returns kTRUE when object is fully supported on JSROOT side
90/// In ROOT7 Paint function will just return appropriate flag that object can be displayed on JSROOT side
91
93{
94 if (!obj)
95 return kTRUE;
96
97 static const struct {
98 const char *name;
99 bool with_derived;
100 } supported_classes[] = {{"TH1", true},
101 {"TF1", true},
102 {"TGraph", true},
103 {"TFrame", false},
104 {"THStack", false},
105 {"TMultiGraph", false},
106 {"TGraphPolargram", true},
107 {"TPave", true},
108 {"TGaxis", false},
109 {"TPave", true},
110 {"TArrow", false},
111 {"TBox", false}, // in principle, can be handled via TWebPainter
112 {"TWbox", false}, // some extra calls which cannot be handled via TWebPainter
113 {"TLine", false}, // also can be handler via TWebPainter
114 {"TText", false},
115 {"TLatex", false},
116 {"TMathText", false},
117 {"TMarker", false},
118 {"TPolyMarker", false},
119 {"TPolyMarker3D", false},
120 {"TPolyLine3D", false},
121 {"TGraph2D", false},
122 {"TGraph2DErrors", false},
123 {"TASImage", false},
124 {"TRatioPlot", false},
125 {"TSpline", false},
126 {"TSpline3", false},
127 {"TSpline5", false},
128 {"TGeoManager", false},
129 {"TPolyLine3D", false},
130 {"TPolyMarker3D", false},
131 {nullptr, false}};
132
133 // fast check of class name
134 for (int i = 0; supported_classes[i].name != nullptr; ++i)
135 if (strcmp(supported_classes[i].name, obj->ClassName()) == 0)
136 return kTRUE;
137
138 // now check inheritance only for configured classes
139 for (int i = 0; supported_classes[i].name != nullptr; ++i)
140 if (supported_classes[i].with_derived)
141 if (obj->InheritsFrom(supported_classes[i].name))
142 return kTRUE;
143
144 return IsCustomClass(obj->IsA());
145}
146
147//////////////////////////////////////////////////////////////////////////////////////////////////
148/// Configures custom script for canvas.
149/// If started from "load:" or "assert:" prefix will be loaded with JSROOT.AssertPrerequisites function
150/// Script should implement custom user classes, which transferred as is to client
151/// In the script draw handler for appropriate classes would be assigned
152
153void TWebCanvas::SetCustomScripts(const std::string &src)
154{
155 fCustomScripts = src;
156}
157
158//////////////////////////////////////////////////////////////////////////////////////////////////
159/// Assign custom class
160
161void TWebCanvas::AddCustomClass(const std::string &clname, bool with_derived)
162{
163 if (with_derived)
164 fCustomClasses.emplace_back("+"s + clname);
165 else
166 fCustomClasses.emplace_back(clname);
167}
168
169//////////////////////////////////////////////////////////////////////////////////////////////////
170/// Checks if class belongs to custom
171
173{
174 for (auto &name : fCustomClasses) {
175 if (name[0] == '+') {
176 if (cl->InheritsFrom(name.substr(1).c_str()))
177 return true;
178 } else if (name.compare(cl->GetName()) == 0) {
179 return true;
180 }
181 }
182 return false;
183}
184
185//////////////////////////////////////////////////////////////////////////////////////////////////
186/// Creates representation of the object for painting in web browser
187
188void TWebCanvas::CreateObjectSnapshot(TPadWebSnapshot &master, TPad *pad, TObject *obj, const char *opt, TWebPS *masterps)
189{
190 if (IsJSSupportedClass(obj)) {
191 master.NewPrimitive(obj, opt).SetSnapshot(TWebSnapshot::kObject, obj);
192 return;
193 }
194
195 // painter is not necessary for batch canvas, but keep configuring it for a while
196 auto *painter = dynamic_cast<TWebPadPainter *>(Canvas()->GetCanvasPainter());
197
199
200 TView *view = nullptr;
201 TVirtualPad *savepad = gPad;
202
203 pad->cd();
204
205 if (obj->InheritsFrom(TAtt3D::Class()) && !pad->GetView()) {
206 pad->GetViewer3D("pad");
207 view = TView::CreateView(1, 0, 0); // Cartesian view by default
208 pad->SetView(view);
209
210 // Set view to perform first auto-range (scaling) pass
211 view->SetAutoRange(kTRUE);
212 }
213
214 TVirtualPS *saveps = gVirtualPS;
215
216 TWebPS ps;
217 gVirtualPS = masterps ? masterps : &ps;
218 if (painter)
219 painter->SetPainting(ps.GetPainting());
220
221 // calling Paint function for the object
222 obj->Paint(opt);
223
224 if (view) {
225 view->SetAutoRange(kFALSE);
226 // call 3D paint once again to make real drawing
227 obj->Paint(opt);
228 pad->SetView(nullptr);
229 }
230
231 if (painter)
232 painter->SetPainting(nullptr);
233
234 gVirtualPS = saveps;
235 if (savepad)
236 savepad->cd();
237
238 // if there are master PS, do not create separate entries
239 if (!masterps && !ps.IsEmptyPainting())
241}
242
243//////////////////////////////////////////////////////////////////////////////////////////////////
244/// Add special canvas objects like colors list at selected palette
245
247{
248 TObjArray *colors = (TObjArray *)gROOT->GetListOfColors();
249
250 if (!colors)
251 return;
252
253 Int_t cnt = 0;
254 for (Int_t n = 0; n <= colors->GetLast(); ++n)
255 if (colors->At(n))
256 cnt++;
257
258 if (cnt <= 598)
259 return; // normally there are 598 colors defined
260
262
263 auto *listofcols = new TWebPainting;
264 for (Int_t n = 0; n <= colors->GetLast(); ++n)
265 if (colors->At(n))
266 listofcols->AddColor(n, (TColor *)colors->At(n));
267
268 // store palette in the buffer
269 auto *tgt = listofcols->Reserve(pal.GetSize());
270 for (Int_t i = 0; i < pal.GetSize(); i++)
271 tgt[i] = pal[i];
272 listofcols->FixSize();
273
274 master.NewSpecials().SetSnapshot(TWebSnapshot::kColors, listofcols, kTRUE);
275}
276
277//////////////////////////////////////////////////////////////////////////////////////////////////
278/// Create snapshot for pad and all primitives
279/// Callback function is used to create JSON in the middle of data processing -
280/// when all misc objects removed from canvas list of primitives or histogram list of functions
281/// After that objects are moved back to their places
282
284{
285 paddata.SetActive(pad == gPad);
286 paddata.SetObjectIDAsPtr(pad);
287 paddata.SetSnapshot(TWebSnapshot::kSubPad, pad); // add ref to the pad
288
289 if (resfunc && (GetStyleDelivery() > (version > 0 ? 1 : 0)))
291
292 TList *primitives = pad->GetListOfPrimitives();
293
294 if (primitives) fPrimitivesLists.Add(primitives); // add list of primitives
295
296 TWebPS masterps;
297 bool usemaster = primitives ? (primitives->GetSize() > fPrimitivesMerge) : false;
298
299 TIter iter(primitives);
300 TObject *obj = nullptr;
301 TFrame *frame = nullptr;
302 TPaveText *title = nullptr;
303 bool need_frame = false;
304 std::string need_title;
305
306 while ((obj = iter()) != nullptr) {
307 if (obj->InheritsFrom(TFrame::Class())) {
308 frame = static_cast<TFrame *>(obj);
309 } else if (obj->InheritsFrom(TH1::Class())) {
310 need_frame = true;
311 if (!obj->TestBit(TH1::kNoTitle) && (strlen(obj->GetTitle())>0)) need_title = obj->GetTitle();
312 } else if (obj->InheritsFrom(TGraph::Class())) {
313 need_frame = true;
314 if (strlen(obj->GetTitle())>0) need_title = obj->GetTitle();
315 } else if (obj->InheritsFrom(TPaveText::Class())) {
316 if (strcmp(obj->GetName(),"title") == 0)
317 title = static_cast<TPaveText *>(obj);
318 }
319 }
320
321 if (need_frame && !frame && primitives && CanCreateObject("TFrame")) {
322 frame = pad->GetFrame();
323 primitives->AddFirst(frame);
324 }
325
326 if (!need_title.empty()) {
327 if (title) {
328 auto line0 = title->GetLine(0);
329 if (line0 && !IsReadOnly()) line0->SetTitle(need_title.c_str());
330 } else if (primitives && CanCreateObject("TPaveText")) {
331 title = new TPaveText(0, 0, 0, 0, "blNDC");
334 title->SetName("title");
337 title->SetTextFont(gStyle->GetTitleFont(""));
338 if (gStyle->GetTitleFont("") % 10 > 2)
340 title->AddText(need_title.c_str());
341 title->SetBit(kCanDelete);
342 primitives->Add(title);
343 }
344 }
345
346 auto flush_master = [&]() {
347 if (!usemaster || masterps.IsEmptyPainting()) return;
348
350 masterps.CreatePainting(); // create for next operations
351 };
352
353 iter.Reset();
354
355 bool first_obj = true;
356
357 while ((obj = iter()) != nullptr) {
358 if (obj->InheritsFrom(TPad::Class())) {
359 flush_master();
360 CreatePadSnapshot(paddata.NewSubPad(), (TPad *)obj, version, nullptr);
361 } else if (obj->InheritsFrom(TH1::Class())) {
362 flush_master();
363
364 TH1 *hist = (TH1 *)obj;
365 TIter fiter(hist->GetListOfFunctions());
366 TObject *fobj = nullptr;
367 TPaveStats *stats = nullptr;
368 TObject *palette = nullptr;
369
370 hist->BufferEmpty();
371
372 while ((fobj = fiter()) != nullptr) {
373 if (fobj->InheritsFrom(TPaveStats::Class()))
374 stats = dynamic_cast<TPaveStats *> (fobj);
375 else if (fobj->InheritsFrom("TPaletteAxis"))
376 palette = fobj;
377 }
378
379 if (!stats && first_obj && (gStyle->GetOptStat() > 0) && CanCreateObject("TPaveStats")) {
380 stats = new TPaveStats(
383 gStyle->GetStatX(),
384 gStyle->GetStatY(), "brNDC");
385
386 stats->SetParent(hist);
387 stats->SetOptFit(gStyle->GetOptFit());
388 stats->SetOptStat(gStyle->GetOptStat());
392 stats->SetTextFont(gStyle->GetStatFont());
393 if (gStyle->GetStatFont()%10 > 2)
397 stats->SetName("stats");
398
400 stats->SetTextAlign(12);
401 stats->SetBit(kCanDelete);
402 stats->SetBit(kMustCleanup);
403
404 hist->GetListOfFunctions()->Add(stats);
405 }
406
407 TString hopt = iter.GetOption();
408
409 if (!palette && CanCreateObject("TPaletteAxis") && (hist->GetDimension() > 1) &&
410 (hopt.Index("colz", 0, TString::kIgnoreCase) != kNPOS)) {
411 std::stringstream exec;
412 exec << "new TPaletteAxis(0,0,0,0, (TH1*)" << std::hex << std::showbase << (size_t)hist << ");";
413 palette = (TObject *)gROOT->ProcessLine(exec.str().c_str());
414 if (palette)
415 hist->GetListOfFunctions()->AddFirst(palette);
416 }
417
418 if (title && first_obj) hopt.Append(";;use_pad_title");
419
420 // if (stats) hopt.Append(";;use_pad_stats");
421
422 if (palette) hopt.Append(";;use_pad_palette");
423
424 paddata.NewPrimitive(obj, hopt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
425
426 // do not extract objects from list of functions - stats and func need to be handled together with hist
427 //
428 // fiter.Reset();
429 // while ((fobj = fiter()) != nullptr)
430 // CreateObjectSnapshot(paddata, pad, fobj, fiter.GetOption());
431
432 // fPrimitivesLists.Add(hist->GetListOfFunctions());
433
434 first_obj = false;
435 } else if (obj->InheritsFrom(TGraph::Class())) {
436 flush_master();
437
438 TGraph *gr = (TGraph *)obj;
439
440 TIter fiter(gr->GetListOfFunctions());
441 TObject *fobj = nullptr;
442 TPaveStats *stats = nullptr;
443
444 while ((fobj = fiter()) != nullptr) {
445 if (fobj->InheritsFrom(TPaveStats::Class()))
446 stats = dynamic_cast<TPaveStats *> (fobj);
447 }
448
449 // ensure histogram exists on server to draw it properly on clients side
450 if (!IsReadOnly() && first_obj)
451 gr->GetHistogram();
452
453 TString gropt = iter.GetOption();
454 if (title && first_obj) gropt.Append(";;use_pad_title");
455 if (stats) gropt.Append(";;use_pad_stats");
456
457 paddata.NewPrimitive(obj, gropt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
458
459 fiter.Reset();
460 while ((fobj = fiter()) != nullptr)
461 CreateObjectSnapshot(paddata, pad, fobj, fiter.GetOption());
462
464 first_obj = false;
465 } else if (IsJSSupportedClass(obj)) {
466 flush_master();
467 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
468 } else {
469 CreateObjectSnapshot(paddata, pad, obj, iter.GetOption(), usemaster ? &masterps : nullptr);
470 }
471 }
472
473 flush_master();
474
475 bool provide_colors = GetPaletteDelivery() > 0;
476 if (GetPaletteDelivery() == 1)
477 provide_colors = !!resfunc && (version <= 0);
478 else if (GetPaletteDelivery() == 2)
479 provide_colors = !!resfunc;
480
481 // add specials after painting is performed - new colors may be generated only during painting
482 if (provide_colors)
483 AddColorsPalette(paddata);
484
485 if (!resfunc)
486 return;
487
488 // now move all primitives and functions into separate list to perform I/O
489
490 TList save_lst;
491 TIter diter(&fPrimitivesLists);
492 TList *dlst = nullptr;
493 while ((dlst = (TList *)diter()) != nullptr) {
494 TIter fiter(dlst);
495 while ((obj = fiter()) != nullptr)
496 save_lst.Add(obj, fiter.GetOption());
497 save_lst.Add(dlst); // add list itself to have marker
498 dlst->Clear("nodelete");
499 }
500
501 // execute function to prevent storing of colors with custom TCanvas streamer
502 // TODO: Olivier - we need to change logic here!
504
505 // invoke callback for master painting
506 resfunc(&paddata);
507
508 TIter siter(&save_lst);
509 diter.Reset();
510 while ((dlst = (TList *)diter()) != nullptr) {
511 while ((obj = siter()) != nullptr) {
512 if (obj == dlst)
513 break;
514 dlst->Add(obj, siter.GetOption());
515 }
516 }
517
518 save_lst.Clear("nodelete");
519
520 fPrimitivesLists.Clear("nodelete");
521}
522
523//////////////////////////////////////////////////////////////////////////////////////////////////
524/// Add message to send queue for specified connection
525/// If connid == 0, message will be add to all connections
526/// Return kFALSE if queue is full or connection is not exists
527
528Bool_t TWebCanvas::AddToSendQueue(unsigned connid, const std::string &msg)
529{
530 Bool_t res = false;
531 for (auto &conn : fWebConn) {
532 if ((conn.fConnId == connid) || (connid == 0)) {
533 conn.fSend.emplace(msg);
534 res = kTRUE;
535 }
536 }
537 return res;
538}
539
540
541//////////////////////////////////////////////////////////////////////////////////////////////////
542/// Check if any data should be send to client
543/// If connid != 0, only selected connection will be checked
544
545void TWebCanvas::CheckDataToSend(unsigned connid)
546{
547 if (!Canvas())
548 return;
549
550 for (auto &conn : fWebConn) {
551 if (connid && (conn.fConnId != connid))
552 continue;
553
554 // check if direct data sending is possible
555 if (!fWindow->CanSend(conn.fConnId, true))
556 continue;
557
558 std::string buf;
559
560 if ((conn.fSendVersion < fCanvVersion) && (conn.fSendVersion == conn.fDrawVersion)) {
561
562 buf = "SNAP6:";
563
565
566 // scripts send only when canvas drawn for the first time
567 if (!conn.fSendVersion)
569
570 CreatePadSnapshot(holder, Canvas(), conn.fSendVersion, [&buf,this](TPadWebSnapshot *snap) {
571 buf.append(TBufferJSON::ToJSON(snap, fJsonComp).Data());
572 });
573
574 conn.fSendVersion = fCanvVersion;
575
576 } else if (!conn.fSend.empty()) {
577
578 std::swap(buf, conn.fSend.front());
579 conn.fSend.pop();
580
581 }
582
583 if (!buf.empty())
584 fWindow->Send(conn.fConnId, buf);
585 }
586}
587
588//////////////////////////////////////////////////////////////////////////////////////////
589/// Close web canvas - not implemented
590
592{
593}
594
595//////////////////////////////////////////////////////////////////////////////////////////
596/// Show canvas in specified place.
597/// If parameter args not specified, default ROOT web display will be used
598
600{
601 if (!fWindow) {
603
604 fWindow->SetConnLimit(0); // configure connections limit
605
606 fWindow->SetDefaultPage("file:rootui5sys/canv/canvas6.html");
607
608 fWindow->SetCallBacks(
609 // connection
610 [this](unsigned connid) {
611 fWebConn.emplace_back(connid);
612 CheckDataToSend(connid);
613 },
614 // data
615 [this](unsigned connid, const std::string &arg) {
616 ProcessData(connid, arg);
617 CheckDataToSend(connid);
618 },
619 // disconnect
620 [this](unsigned connid) {
621 unsigned indx = 0;
622 for (auto &c : fWebConn) {
623 if (c.fConnId == connid) {
624 fWebConn.erase(fWebConn.begin() + indx);
625 break;
626 }
627 indx++;
628 }
629 });
630 }
631
632 auto w = Canvas()->GetWw(), h = Canvas()->GetWh();
633
634 if ((w > 10) && (w < 50000) && (h > 10) && (h < 30000))
635 fWindow->SetGeometry(w + 6, h + 22);
636
641
642 fWindow->Show(args);
643}
644
645//////////////////////////////////////////////////////////////////////////////////////////
646/// Show canvas in browser window
647
649{
651 args.SetWidgetKind("TCanvas");
652 ShowWebWindow(args);
653}
654
655//////////////////////////////////////////////////////////////////////////////////////////
656/// Function used to send command to browser to toggle menu, toolbar, editors, ...
657
658void TWebCanvas::ShowCmd(const std::string &arg, Bool_t show)
659{
660 if (AddToSendQueue(0, "SHOW:"s + arg + (show ? ":1"s : ":0"s)))
662}
663
664//////////////////////////////////////////////////////////////////////////////////////////
665/// Activate object in editor in web browser
666
668{
669 if (!pad || !obj) return;
670
671 UInt_t hash = TString::Hash(&obj, sizeof(obj));
672
673 if (AddToSendQueue(0, "EDIT:"s + std::to_string(hash)))
675}
676
677//////////////////////////////////////////////////////////////////////////////////////////
678/// Returns kTRUE if web canvas has graphical editor
679
681{
682 return (fClientBits & TCanvas::kShowEditor) != 0;
683}
684
685//////////////////////////////////////////////////////////////////////////////////////////
686/// Returns kTRUE if web canvas has menu bar
687
689{
690 return (fClientBits & TCanvas::kMenuBar) != 0;
691}
692
693//////////////////////////////////////////////////////////////////////////////////////////
694/// Returns kTRUE if web canvas has status bar
695
697{
699}
700
701//////////////////////////////////////////////////////////////////////////////////////////
702/// Returns kTRUE if tooltips are activated in web canvas
703
705{
706 return (fClientBits & TCanvas::kShowToolTips) != 0;
707}
708
709//////////////////////////////////////////////////////////////////////////////////////////
710/// Assign clients bits
711
713{
714 fClientBits = bits;
719}
720
721//////////////////////////////////////////////////////////////////////////////////////////////////
722/// Decode all pad options, which includes ranges plus objects options
723
725{
726 if (IsReadOnly() || msg.empty())
727 return kFALSE;
728
729 auto arr = TBufferJSON::FromJSON<std::vector<TWebPadOptions>>(msg);
730
731 if (!arr)
732 return kFALSE;
733
734 for (unsigned n = 0; n < arr->size(); ++n) {
735 auto &r = arr->at(n);
736 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(r.snapid));
737
738 if (!pad)
739 continue;
740
741 if (pad == Canvas()) AssignStatusBits(r.bits);
742
743 if (r.active && (pad != gPad)) gPad = pad;
744
745 if ((pad->GetTickx() != r.tickx) || (pad->GetTicky() != r.ticky))
746 pad->SetTicks(r.tickx, r.ticky);
747 if ((pad->GetGridx() != r.gridx) || (pad->GetGridy() != r.gridy))
748 pad->SetGrid(r.gridx, r.gridy);
749 if (r.logx != pad->GetLogx())
750 pad->SetLogx(r.logx);
751 if (r.logy != pad->GetLogy())
752 pad->SetLogy(r.logy);
753 if (r.logz != pad->GetLogz())
754 pad->SetLogz(r.logz);
755
756 pad->SetLeftMargin(r.mleft);
757 pad->SetRightMargin(r.mright);
758 pad->SetTopMargin(r.mtop);
759 pad->SetBottomMargin(r.mbottom);
760
761 if (r.ranges) {
762
763 Double_t ux1_, ux2_, uy1_, uy2_, px1_, px2_, py1_, py2_;
764
765 pad->GetRange(px1_, py1_, px2_, py2_);
766 pad->GetRangeAxis(ux1_, uy1_, ux2_, uy2_);
767
768 bool same_range = (r.ux1 == ux1_) && (r.ux2 == ux2_) && (r.uy1 == uy1_) && (r.uy2 == uy2_) &&
769 (r.px1 == px1_) && (r.px2 == px2_) && (r.py1 == py1_) && (r.py2 == py2_);
770
771 if (!same_range) {
772 pad->RangeAxis(r.ux1, r.uy1, r.ux2, r.uy2);
773
774 pad->Range(r.px1, r.py1, r.px2, r.py2);
775
776 if (gDebug > 1)
777 Info("DecodeAllRanges", "Change ranges for pad %s", pad->GetName());
778 }
779 }
780
781 pad->SetPad(r.mleft, r.mbottom, 1-r.mright, 1-r.mtop);
782
783 TH1 *hist = static_cast<TH1 *>(FindPrimitive("histogram", pad));
784
785 if (hist) {
786 double hmin = 0, hmax = 0;
787
788 if (r.zx1 == r.zx2)
789 hist->GetXaxis()->SetRange(0,0);
790 else
791 hist->GetXaxis()->SetRangeUser(r.zx1, r.zx2);
792
793 if (hist->GetDimension() == 1) {
794 hmin = r.zy1;
795 hmax = r.zy2;
796 } else if (r.zy1 == r.zy2) {
797 hist->GetYaxis()->SetRange(0,0);
798 } else {
799 hist->GetYaxis()->SetRangeUser(r.zy1, r.zy2);
800 }
801
802 if (hist->GetDimension() == 2) {
803 hmin = r.zz1;
804 hmax = r.zz2;
805 } else if (hist->GetDimension() == 3) {
806 if (r.zz1 == r.zz2) {
807 hist->GetZaxis()->SetRange(0,0);
808 } else {
809 hist->GetZaxis()->SetRangeUser(r.zz1, r.zz2);
810 }
811 }
812
813 if (hmin == hmax) { hist->SetMinimum(); hist->SetMaximum(); }
814 else { hist->SetMinimum(hmin); hist->SetMaximum(hmax); }
815
816 }
817
818 for (auto &item : r.primitives)
819 ProcessObjectOptions(item, pad);
820
821 // without special objects no need for explicit update of the pad
822 if (fHasSpecials)
823 pad->Modified(kTRUE);
824
825 }
826
827 if (fUpdatedSignal) fUpdatedSignal(); // invoke signal
828
829 return kTRUE;
830}
831
832//////////////////////////////////////////////////////////////////////////////////////////
833/// Handle data from web browser
834/// Returns kFALSE if message was not processed
835
836Bool_t TWebCanvas::ProcessData(unsigned connid, const std::string &arg)
837{
838 if (arg.empty())
839 return kTRUE;
840
841 // try to identify connection for given WS request
842 unsigned indx = 0;
843 for (auto &c : fWebConn) {
844 if (c.fConnId == connid) break;
845 indx++;
846 }
847 if (indx >= fWebConn.size())
848 return kTRUE;
849
850 struct FlagGuard {
851 Bool_t &flag;
852 FlagGuard(Bool_t &_flag) : flag(_flag) { flag = true; }
853 ~FlagGuard() { flag = false; }
854 };
855
856 FlagGuard guard(fProcessingData);
857
858 const char *cdata = arg.c_str();
859
860 if (arg == "KEEPALIVE") {
861 // do nothing
862
863 } else if (arg == "QUIT") {
864
865 // use window manager to correctly terminate http server
866 fWindow->TerminateROOT();
867
868 } else if (arg.compare(0, 7, "READY6:") == 0) {
869
870 // this is reply on drawing of ROOT6 snapshot
871 // it confirms when drawing of specific canvas version is completed
872
873 cdata += 7;
874
875 const char *separ = strchr(cdata, ':');
876 if (!separ) {
877 fWebConn[indx].fDrawVersion = std::stoll(cdata);
878 } else {
879 fWebConn[indx].fDrawVersion = std::stoll(std::string(cdata, separ - cdata));
880 if ((indx == 0) && !IsReadOnly())
881 DecodePadOptions(separ+1);
882 }
883
884 } else if (arg == "RELOAD") {
885
886 // trigger reload of canvas data
887 fWebConn[indx].fSendVersion = fWebConn[indx].fDrawVersion = 0;
888
889 } else if (arg.compare(0, 5, "SAVE:") == 0) {
890
891 // save image produced by the client side - like png or svg
892 const char *img = cdata + 5;
893
894 const char *separ = strchr(img, ':');
895 if (separ) {
896 TString filename(img, separ - img);
897 img = separ + 1;
898
899 std::ofstream ofs(filename.Data());
900
901 if (filename.Index(".svg") != kNPOS) {
902 // ofs << "<?xml version=\"1.0\" standalone=\"no\"?>";
903 ofs << img;
904 } else {
905 TString binary = TBase64::Decode(img);
906 ofs.write(binary.Data(), binary.Length());
907 }
908 ofs.close();
909
910 Info("ProcessData", "File %s has been created", filename.Data());
911 }
912
913 } else if (arg.compare(0, 8, "PRODUCE:") == 0) {
914
915 // create ROOT, PDF, ... files using native ROOT functionality
916 Canvas()->Print(arg.c_str() + 8);
917
918 } else if (arg.compare(0, 9, "OPTIONS6:") == 0) {
919
920 if ((indx == 0) && !IsReadOnly())
921 DecodePadOptions(arg.substr(9));
922
923 } else if (arg.compare(0, 11, "STATUSBITS:") == 0) {
924
925 if (indx == 0) {
926 AssignStatusBits(std::stoul(arg.substr(11)));
927 if (fUpdatedSignal) fUpdatedSignal(); // invoke signal
928 }
929
930 } else if (IsReadOnly()) {
931
932 // all following messages are not allowed in readonly mode
933 return kFALSE;
934
935 } else if (arg.compare(0, 8, "GETMENU:") == 0) {
936
937 TObject *obj = FindPrimitive(arg.substr(8));
938 if (!obj)
939 obj = Canvas();
940
941 TWebMenuItems items(arg.c_str() + 8);
942 items.PopulateObjectMenu(obj, obj->IsA());
943 std::string buf = "MENU:";
944 buf.append(TBufferJSON::ToJSON(&items, 103).Data());
945
946 AddToSendQueue(connid, buf);
947
948 } else if (arg.compare(0, 8, "PRIMIT6:") == 0) {
949
950 if (IsFirstConn(connid) && !IsReadOnly()) { // only first connection can modify object
951
952 auto opt = TBufferJSON::FromJSON<TWebObjectOptions>(arg.c_str() + 8);
953
954 if (opt) {
955 TPad *modpad = ProcessObjectOptions(*opt, nullptr);
956
957 // indicate that pad was modified
958 if (modpad)
959 modpad->Modified();
960 }
961 }
962
963 } else if (arg.compare(0, 11, "PADCLICKED:") == 0) {
964
965 auto click = TBufferJSON::FromJSON<TWebPadClick>(arg.c_str() + 11);
966
967 if (click && IsFirstConn(connid) && !IsReadOnly()) {
968
969 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(click->padid));
970 if (pad && (pad != gPad)) {
971 Info("ProcessData", "Activate pad %s", pad->GetName());
972 gPad = pad;
976 }
977
978 if (!click->objid.empty()) {
979 TObject *selobj = FindPrimitive(click->objid);
980 Canvas()->SetClickSelected(selobj);
981 if (pad && selobj && fObjSelectSignal)
982 fObjSelectSignal(pad, selobj);
983 }
984
985 if ((click->x >= 0) && (click->y >= 0)) {
986 if (click->dbl && fPadDblClickedSignal)
987 fPadDblClickedSignal(pad, click->x, click->y);
988 else if (fPadClickedSignal)
989 fPadClickedSignal(pad, click->x, click->y);
990 }
991 }
992
993 } else if (arg.compare(0, 8, "OBJEXEC:") == 0) {
994
995 auto buf = arg.substr(8);
996 auto pos = buf.find(":");
997
998 if ((pos > 0) && IsFirstConn(connid) && !IsReadOnly()) { // only first client can execute commands
999 auto sid = buf.substr(0, pos);
1000 buf.erase(0, pos + 1);
1001
1002 TObject *obj = FindPrimitive(sid);
1003 if (obj && !buf.empty()) {
1004
1005 while (!buf.empty()) {
1006 std::string sub = buf;
1007 pos = buf.find(";;");
1008 if (pos == std::string::npos) {
1009 sub = buf;
1010 buf.clear();
1011 } else {
1012 sub = buf.substr(0,pos);
1013 buf = buf.substr(pos+2);
1014 }
1015 if (sub.empty()) continue;
1016
1017 std::stringstream exec;
1018 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj << ")->" << sub << ";";
1019 Info("ProcessData", "Obj %s Execute %s", obj->GetName(), exec.str().c_str());
1020 gROOT->ProcessLine(exec.str().c_str());
1021 }
1022
1024 }
1025 }
1026
1027 } else if (arg.compare(0, 12, "EXECANDSEND:") == 0) {
1028
1029 // execute method and send data, used by drawing projections
1030
1031 std::string buf = arg.substr(12);
1032 std::string reply;
1033 TObject *obj = nullptr;
1034
1035 auto pos = buf.find(":");
1036
1037 if ((pos > 0) && IsFirstConn(connid) && !IsReadOnly()) {
1038 // only first client can execute commands
1039 reply = buf.substr(0, pos);
1040 buf.erase(0, pos + 1);
1041 pos = buf.find(":");
1042 if (pos > 0) {
1043 auto sid = buf.substr(0, pos);
1044 buf.erase(0, pos + 1);
1045 obj = FindPrimitive(sid);
1046 }
1047 }
1048
1049 if (obj && !buf.empty() && !reply.empty()) {
1050 std::stringstream exec;
1051 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj
1052 << ")->" << buf << ";";
1053 if (gDebug > 1)
1054 Info("ProcessData", "Obj %s Exec %s", obj->GetName(), exec.str().c_str());
1055
1056 Long_t res = gROOT->ProcessLine(exec.str().c_str());
1057 TObject *resobj = (TObject *)res;
1058 if (resobj) {
1059 std::string send = reply;
1060 send.append(":");
1061 send.append(TBufferJSON::ToJSON(resobj, 23).Data());
1062 AddToSendQueue(connid, send);
1063 if (reply[0] == 'D')
1064 delete resobj; // delete object if first symbol in reply is D
1065 }
1066 }
1067
1068 } else {
1069
1070 // unknown message, probably should be processed by other implementation
1071 return kFALSE;
1072 }
1073
1074 return kTRUE;
1075}
1076
1077//////////////////////////////////////////////////////////////////////////////////////////
1078/// Returns true if any pad in the canvas were modified
1079/// Reset modified flags, increment canvas version (if inc_version is true)
1080
1082{
1083 Bool_t modified = kFALSE;
1084
1085 if (pad->IsModified()) {
1086 pad->Modified(kFALSE);
1087 modified = kTRUE;
1088 }
1089
1090 TIter iter(pad->GetListOfPrimitives());
1091 TObject *obj = nullptr;
1092 while ((obj = iter()) != nullptr) {
1093 if (obj->InheritsFrom(TPad::Class()) && CheckPadModified(static_cast<TPad *>(obj), kFALSE))
1094 modified = kTRUE;
1095 }
1096
1097 if (inc_version && modified)
1098 fCanvVersion++;
1099
1100 return modified;
1101}
1102
1103//////////////////////////////////////////////////////////////////////////////////////////
1104/// Returns window geometry including borders and menus
1105
1107{
1108 x = 0;
1109 y = 0;
1110 w = Canvas()->GetWw() + 4;
1111 h = Canvas()->GetWh() + 28;
1112 return 0;
1113}
1114
1115//////////////////////////////////////////////////////////////////////////////////////////
1116/// if canvas or any subpad was modified,
1117/// scan all primitives in the TCanvas and subpads and convert them into
1118/// the structure which will be delivered to JSROOT client
1119
1121{
1123
1125
1126 if (!fProcessingData && !IsAsyncMode())
1128
1129 return kTRUE;
1130}
1131
1132//////////////////////////////////////////////////////////////////////////////////////////
1133/// Increment canvas version and force sending data to client - do not wit for reply
1134
1136{
1137 fCanvVersion++;
1138
1140}
1141
1142//////////////////////////////////////////////////////////////////////////////////////////
1143/// Wait when specified version of canvas was painted and confirmed by browser
1144
1146{
1147 // simple polling loop until specified version delivered to the clients
1148 // first 500 loops done without sleep, then with 1ms sleep and last 500 with 100 ms sleep
1149
1150 long cnt = 0, cnt_limit = GetLongerPolling() ? 5500 : 1500;
1151
1152 if (gDebug > 2)
1153 Info("WaitWhenCanvasPainted", "version %ld", (long)ver);
1154
1155 while (cnt++ < cnt_limit) {
1156
1157 if (!fWindow->HasConnection(0, false)) {
1158 if (gDebug > 2)
1159 Info("WaitWhenCanvasPainted", "no connections - abort");
1160 return kFALSE; // wait ~1 min if no new connection established
1161 }
1162
1163 if ((fWebConn.size() > 0) && (fWebConn.front().fDrawVersion >= ver)) {
1164 if (gDebug > 2)
1165 Info("WaitWhenCanvasPainted", "ver %ld got painted", (long)ver);
1166 return kTRUE;
1167 }
1168
1170 if (cnt > 500)
1171 gSystem->Sleep((cnt < cnt_limit - 500) ? 1 : 100); // increase sleep interval when do very often
1172 }
1173
1174 if (gDebug > 2)
1175 Info("WaitWhenCanvasPainted", "timeout");
1176
1177 return kFALSE;
1178}
1179
1180//////////////////////////////////////////////////////////////////////////////////////////
1181/// Create JSON painting output for given canvas
1182/// Produce JSON can be used for offline drawing with JSROOT
1183
1185{
1186 TString res;
1187
1188 if (!c)
1189 return res;
1190
1191 Bool_t isbatch = c->IsBatch();
1192 c->SetBatch(kTRUE);
1193
1194 {
1195 auto imp = std::make_unique<TWebCanvas>(c, c->GetName(), 0, 0, 1000, 500);
1196
1197 TCanvasWebSnapshot holder(true, 1); // always readonly
1198
1199 imp->CreatePadSnapshot(holder, c, 0, [&res, json_compression](TPadWebSnapshot *snap) {
1200 res = TBufferJSON::ToJSON(snap, json_compression);
1201 });
1202 }
1203
1204 c->SetBatch(isbatch);
1205 return res;
1206}
1207
1208//////////////////////////////////////////////////////////////////////////////////////////
1209/// Create JSON painting output for given canvas and store into the file
1210/// See TBufferJSON::ExportToFile() method for more details
1211
1212Int_t TWebCanvas::StoreCanvasJSON(TCanvas *c, const char *filename, const char *option)
1213{
1214 Int_t res{0};
1215
1216 if (!c)
1217 return res;
1218
1219 Bool_t isbatch = c->IsBatch();
1220 c->SetBatch(kTRUE);
1221
1222 {
1223 auto imp = std::make_unique<TWebCanvas>(c, c->GetName(), 0, 0, 1000, 500);
1224
1225 TCanvasWebSnapshot holder(true, 1); // always readonly
1226
1227 imp->CreatePadSnapshot(holder, c, 0, [&res, filename, option](TPadWebSnapshot *snap) {
1228 res = TBufferJSON::ExportToFile(filename, snap, option);
1229 });
1230 }
1231
1232 c->SetBatch(isbatch);
1233 return res;
1234}
1235
1236//////////////////////////////////////////////////////////////////////////////////////////
1237/// Create image using batch (headless) capability of Chrome browser
1238/// Supported png, jpeg, svg, pdf formats
1239
1240bool TWebCanvas::ProduceImage(TCanvas *c, const char *fileName, Int_t width, Int_t height)
1241{
1242 if (!c)
1243 return false;
1244
1246 if (!json.Length())
1247 return false;
1248
1249 return ROOT::Experimental::RWebDisplayHandle::ProduceImage(fileName, json.Data(), width ? width : c->GetWw(), height ? height : c->GetWh());
1250}
1251
1252//////////////////////////////////////////////////////////////////////////////////////////
1253/// Process data for single primitive
1254/// Returns object pad if object was modified
1255
1257{
1258 TObjLink *lnk = nullptr;
1259 TPad *objpad = nullptr;
1260 TObject *obj = FindPrimitive(item.snapid, pad, &lnk, &objpad);
1261
1262 if (item.fcust.compare("exec") == 0) {
1263 auto pos = item.opt.find("(");
1264 if (obj && (pos != std::string::npos) && obj->IsA()->GetMethodAllAny(item.opt.substr(0,pos).c_str())) {
1265 std::stringstream exec;
1266 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase
1267 << (size_t)obj << ")->" << item.opt << ";";
1268 Info("ProcessObjectOptions", "Obj %s Execute %s", obj->GetName(), exec.str().c_str());
1269 gROOT->ProcessLine(exec.str().c_str());
1270 } else {
1271 Error("ProcessObjectOptions", "Fail to execute %s for object %p %s", item.opt.c_str(), obj, obj ? obj->ClassName() : "---");
1272 objpad = nullptr;
1273 }
1274 return objpad;
1275 }
1276
1277 bool modified = false;
1278
1279 if (obj && lnk) {
1280 auto pos = item.opt.find(";;use_"); // special coding of extra options
1281 if (pos != std::string::npos) item.opt.resize(pos);
1282
1283 if (gDebug > 1)
1284 Info("ProcessObjectOptions", "Set draw option %s for object %s %s", item.opt.c_str(),
1285 obj->ClassName(), obj->GetName());
1286
1287 lnk->SetOption(item.opt.c_str());
1288
1289 modified = true;
1290 }
1291
1292 if (item.fcust.compare("frame") == 0) {
1293 if (obj && obj->InheritsFrom(TFrame::Class())) {
1294 TFrame *frame = static_cast<TFrame *>(obj);
1295 if (item.fopt.size() >= 4) {
1296 frame->SetX1(item.fopt[0]);
1297 frame->SetY1(item.fopt[1]);
1298 frame->SetX2(item.fopt[2]);
1299 frame->SetY2(item.fopt[3]);
1300 modified = true;
1301 }
1302 }
1303 } else if (item.fcust.compare("pave") == 0) {
1304 if (obj && obj->InheritsFrom(TPave::Class())) {
1305 TPave *pave = static_cast<TPave *>(obj);
1306 if ((item.fopt.size() >= 4) && objpad) {
1307 auto save = gPad;
1308 gPad = objpad;
1309
1310 // first time need to overcome init problem
1311 pave->ConvertNDCtoPad();
1312
1313 pave->SetX1NDC(item.fopt[0]);
1314 pave->SetY1NDC(item.fopt[1]);
1315 pave->SetX2NDC(item.fopt[2]);
1316 pave->SetY2NDC(item.fopt[3]);
1317 modified = true;
1318
1319 pave->ConvertNDCtoPad();
1320 gPad = save;
1321 }
1322 }
1323 }
1324
1325 return modified ? objpad : nullptr;
1326}
1327
1328//////////////////////////////////////////////////////////////////////////////////////////////////
1329/// Search of object with given id in list of primitives
1330/// One could specify pad where search could be start
1331/// Also if object is in list of primitives, one could ask for entry link for such object,
1332/// This can allow to change draw option
1333
1334TObject *TWebCanvas::FindPrimitive(const std::string &sid, TPad *pad, TObjLink **padlnk, TPad **objpad)
1335{
1336
1337 if (!pad)
1338 pad = Canvas();
1339
1340 std::string kind;
1341 auto separ = sid.find("#");
1342 long unsigned id = 0;
1343 bool search_hist = false;
1344
1345 if (sid == "histogram") {
1346 search_hist = true;
1347 } else if (separ == std::string::npos) {
1348 id = std::stoul(sid);
1349 } else {
1350 kind = sid.substr(separ + 1);
1351 id = std::stoul(sid.substr(0, separ));
1352 }
1353
1354 if (!search_hist && TString::Hash(&pad, sizeof(pad)) == id)
1355 return pad;
1356
1357 TObjLink *lnk = pad->GetListOfPrimitives()->FirstLink();
1358 while (lnk) {
1359 TObject *obj = lnk->GetObject();
1360 if (!obj) {
1361 lnk = lnk->Next();
1362 continue;
1363 }
1364 TH1 *h1 = obj->InheritsFrom(TH1::Class()) ? static_cast<TH1 *>(obj) : nullptr;
1365 TGraph *gr = obj->InheritsFrom(TGraph::Class()) ? static_cast<TGraph *>(obj) : nullptr;
1366
1367 if (search_hist) {
1368 if (h1) return h1;
1369 if (gr) {
1370 auto offset = TGraph::Class()->GetDataMemberOffset("fHistogram");
1371 if (offset > 0) {
1372 return *((TH1 **)((char*) gr + offset));
1373 } else {
1374 printf("ERROR: Cannot access fHistogram data member in TGraph\n");
1375 return nullptr;
1376 }
1377 }
1378 lnk = lnk->Next();
1379 continue;
1380 }
1381
1382 if (TString::Hash(&obj, sizeof(obj)) == id) {
1383 if (objpad)
1384 *objpad = pad;
1385
1386 if (gr && (kind.find("hist")==0)) {
1387 // access to graph histogram
1388 obj = h1 = gr->GetHistogram();
1389 kind.erase(0,4);
1390 if (!kind.empty() && (kind[0]=='#')) kind.erase(0,1);
1391 padlnk = nullptr;
1392 }
1393
1394 if (h1 && (kind == "x"))
1395 return h1->GetXaxis();
1396 if (h1 && (kind == "y"))
1397 return h1->GetYaxis();
1398 if (h1 && (kind == "z"))
1399 return h1->GetZaxis();
1400
1401 if ((h1 || gr) && !kind.empty() && (kind.compare(0,5,"func_") == 0)) {
1402 auto funcname = kind.substr(5);
1404 return col ? col->FindObject(funcname.c_str()) : nullptr;
1405 }
1406
1407 if (!kind.empty() && (kind.compare(0,7,"member_") == 0)) {
1408 auto member = kind.substr(7);
1409 auto offset = obj->IsA() ? obj->IsA()->GetDataMemberOffset(member.c_str()) : 0;
1410 if (offset > 0) {
1411 TObject **mobj = (TObject **)((char*) obj + offset);
1412 return *mobj;
1413 }
1414 return nullptr;
1415 }
1416
1417 if (padlnk)
1418 *padlnk = lnk;
1419 return obj;
1420 }
1421 if (h1 || gr) {
1423 TObject *fobj = nullptr;
1424 while ((fobj = fiter()) != nullptr)
1425 if (TString::Hash(&fobj, sizeof(fobj)) == id) {
1426 if (objpad)
1427 *objpad = pad;
1428 return fobj;
1429 }
1430 } else if (obj->InheritsFrom(TPad::Class())) {
1431 obj = FindPrimitive(sid, (TPad *)obj, padlnk, objpad);
1432 if (objpad && !*objpad)
1433 *objpad = pad;
1434 if (obj)
1435 return obj;
1436 }
1437 lnk = lnk->Next();
1438 }
1439
1440 return nullptr;
1441}
1442
1443
ROOT::R::TRInterface & r
Definition Object.C:4
#define c(i)
Definition RSha256.hxx:101
#define h(i)
Definition RSha256.hxx:106
const Ssiz_t kNPOS
Definition RtypesCore.h:124
const Bool_t kFALSE
Definition RtypesCore.h:101
long Long_t
Definition RtypesCore.h:54
long long Long64_t
Definition RtypesCore.h:80
const Bool_t kTRUE
Definition RtypesCore.h:100
include TDocParser_001 C image html pict1_TDocParser_001 png width
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:220
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:187
XFontStruct * id
Definition TGX11.cxx:109
char name[80]
Definition TGX11.cxx:110
@ kCanDelete
Definition TObject.h:369
@ kMustCleanup
Definition TObject.h:370
Int_t gDebug
Definition TROOT.cxx:592
#define gROOT
Definition TROOT.h:404
R__EXTERN TStyle * gStyle
Definition TStyle.h:413
R__EXTERN TSystem * gSystem
Definition TSystem.h:559
R__EXTERN TVirtualPS * gVirtualPS
Definition TVirtualPS.h:81
#define gPad
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
@ kCEF
Chromium Embedded Framework - local display with CEF libs.
@ kQt6
Qt6 QWebEngine libraries - Chromium code packed in qt6.
@ kQt5
Qt5 QWebEngine libraries - Chromium code packed in qt5.
RWebDisplayArgs & SetWidgetKind(const std::string &kind)
set widget kind
static bool ProduceImage(const std::string &fname, const std::string &json, int width=800, int height=600)
Produce image file using JSON data as source Invokes JSROOT drawing functionality in headless browser...
static std::shared_ptr< RWebWindow > Create()
Create new RWebWindow Using default RWebWindowsManager.
Array of integers (32 bits per element).
Definition TArrayI.h:27
Int_t GetSize() const
Definition TArray.h:47
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
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
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:946
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis using bin numbers.
Definition TAxis.cxx:920
static TString Decode(const char *data)
Decode a base64 string date into a generic TString.
Definition TBase64.cxx:131
virtual void SetY2(Double_t y2)
Definition TBox.h:64
virtual void SetX1(Double_t x1)
Definition TBox.h:61
virtual void SetX2(Double_t x2)
Definition TBox.h:62
virtual void SetY1(Double_t y1)
Definition TBox.h:63
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
@ kSameSuppression
zero suppression plus compress many similar values together
Definition TBufferJSON.h:45
ABC describing GUI independent main window (with menubar, scrollbars and a drawing area).
Definition TCanvasImp.h:30
TCanvas * Canvas() const
Definition TCanvasImp.h:55
void SetScripts(const std::string &src)
The Canvas class.
Definition TCanvas.h:23
void SetClickSelectedPad(TPad *pad)
Definition TCanvas.h:207
TVirtualPadPainter * GetCanvasPainter()
Access and (probably) creation of pad painter.
Definition TCanvas.cxx:2605
void SetClickSelected(TObject *obj)
Definition TCanvas.h:205
UInt_t GetWw() const override
Definition TCanvas.h:161
UInt_t GetWh() const override
Definition TCanvas.h:162
@ kShowToolTips
Definition TCanvas.h:95
@ kShowEventStatus
Definition TCanvas.h:87
@ kMenuBar
Definition TCanvas.h:89
@ kShowEditor
Definition TCanvas.h:91
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:80
Bool_t InheritsFrom(const char *cl) const
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4860
Collection abstract base class.
Definition TCollection.h:65
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
The color creation and management class.
Definition TColor.h:19
static const TArrayI & GetPalette()
Static function returning the current active palette.
Definition TColor.cxx:1461
static Bool_t DefinedColors()
Static function returning kTRUE if some new colors have been defined after initialisation or since th...
Definition TColor.cxx:1479
virtual Int_t GetValue(const char *name, Int_t dflt) const
Returns the integer value for a resource.
Definition TEnv.cxx:491
Define a Frame.
Definition TFrame.h:19
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
TList * GetListOfFunctions() const
Definition TGraph.h:119
TH1F * GetHistogram() const
Returns a pointer to the histogram used to draw the axis Takes into account the two following cases.
Definition TGraph.cxx:1485
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:58
TAxis * GetZaxis()
Definition TH1.h:322
virtual Int_t GetDimension() const
Definition TH1.h:282
@ kNoTitle
Don't draw the histogram title.
Definition TH1.h:169
TAxis * GetXaxis()
Get the behaviour adopted by the object about the statoverflows. See EStatOverflows for more informat...
Definition TH1.h:320
virtual void SetMaximum(Double_t maximum=-1111)
Definition TH1.h:398
TAxis * GetYaxis()
Definition TH1.h:321
virtual void SetMinimum(Double_t minimum=-1111)
Definition TH1.h:399
TList * GetListOfFunctions() const
Definition TH1.h:243
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Definition TH1.cxx:1403
Option_t * GetOption() const
void Reset()
A doubly linked list.
Definition TList.h:38
virtual void Add(TObject *obj)
Definition TList.h:81
virtual void AddFirst(TObject *obj)
Add object at the beginning of the list.
Definition TList.cxx:100
virtual TObjLink * FirstLink() const
Definition TList.h:102
virtual void Clear(Option_t *option="")
Remove all objects from the list.
Definition TList.cxx:402
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:164
virtual const char * GetName() const
Returns name of object.
Definition TNamed.h:47
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:429
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition TObject.h:201
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:200
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:766
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:515
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:473
virtual void Paint(Option_t *option="")
This method must be overridden if a class wants to paint itself.
Definition TObject.cxx:591
TPadWebSnapshot & NewSubPad()
Create new entry for subpad.
TWebSnapshot & NewSpecials()
Create new entry in list of primitives in the front.
void SetActive(bool on=true)
TWebSnapshot & NewPrimitive(TObject *obj=nullptr, const std::string &opt="")
Create new entry in list of primitives.
The most important graphics class in the ROOT system.
Definition TPad.h:26
Int_t GetTicky() const override
Definition TPad.h:233
void SetView(TView *view=nullptr) override
Set the current TView. Delete previous view if view=0.
Definition TPad.cxx:6062
TVirtualViewer3D * GetViewer3D(Option_t *type="") override
Create/obtain handle to 3D viewer.
Definition TPad.cxx:7015
void SetGrid(Int_t valuex=1, Int_t valuey=1) override
Definition TPad.h:326
Bool_t GetGridx() const override
Definition TPad.h:229
void SetLogz(Int_t value=1) override
Set Lin/Log scale for Z.
Definition TPad.cxx:5978
TList * GetListOfPrimitives() const override
Definition TPad.h:239
void SetPad(const char *name, const char *title, Double_t xlow, Double_t ylow, Double_t xup, Double_t yup, Color_t color=35, Short_t bordersize=5, Short_t bordermode=-1) override
Set all pad parameters.
Definition TPad.cxx:6038
void Range(Double_t x1, Double_t y1, Double_t x2, Double_t y2) override
Set world coordinate system for the pad.
Definition TPad.cxx:5209
Bool_t IsModified() const override
Definition TPad.h:268
Int_t GetTickx() const override
Definition TPad.h:232
void Modified(Bool_t flag=1) override
Definition TPad.h:413
void SetLogy(Int_t value=1) override
Set Lin/Log scale for Y.
Definition TPad.cxx:5967
TView * GetView() const override
Definition TPad.h:248
Bool_t GetGridy() const override
Definition TPad.h:230
Int_t GetLogz() const override
Definition TPad.h:252
void RangeAxis(Double_t xmin, Double_t ymin, Double_t xmax, Double_t ymax) override
Set axis coordinate system for the pad.
Definition TPad.cxx:5247
TVirtualPad * cd(Int_t subpadnumber=0) override
Set Current pad.
Definition TPad.cxx:604
Int_t GetLogy() const override
Definition TPad.h:251
void Print(const char *filename="") const override
This method is equivalent to SaveAs("filename"). See TPad::SaveAs for details.
Definition TPad.cxx:4676
TFrame * GetFrame() override
Get frame.
Definition TPad.cxx:2866
void GetRangeAxis(Double_t &xmin, Double_t &ymin, Double_t &xmax, Double_t &ymax) override
Return pad axis coordinates range.
Definition TPad.cxx:2954
void SetTicks(Int_t valuex=1, Int_t valuey=1) override
Definition TPad.h:346
void GetRange(Double_t &x1, Double_t &y1, Double_t &x2, Double_t &y2) override
Return pad world coordinates range.
Definition TPad.cxx:2943
void SetLogx(Int_t value=1) override
Set Lin/Log scale for X.
Definition TPad.cxx:5953
Int_t GetLogx() const override
Definition TPad.h:250
const char * GetName() const override
Returns name of object.
Definition TPad.h:254
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.
void SetOptStat(Int_t stat=1)
Set the stat option.
virtual void SetParent(TObject *obj)
Definition TPaveStats.h:52
virtual void SetFitFormat(const char *format="5.4g")
Change (i.e. set) the format for printing fit parameters in statistics box.
void SetOptFit(Int_t fit=1)
Set the fit option.
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.
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:80
virtual void ConvertNDCtoPad()
Convert pave coordinates from NDC to Pad coordinates.
Definition TPave.cxx:139
virtual void SetName(const char *name="")
Definition TPave.h:75
virtual void SetBorderSize(Int_t bordersize=4)
Definition TPave.h:73
virtual void SetY2NDC(Double_t y2)
Definition TPave.h:81
virtual void SetX1NDC(Double_t x1)
Definition TPave.h:78
virtual void SetX2NDC(Double_t x2)
Definition TPave.h:79
Basic string class.
Definition TString.h:136
Ssiz_t Length() const
Definition TString.h:410
const char * Data() const
Definition TString.h:369
@ kIgnoreCase
Definition TString.h:268
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:662
TString & Append(const char *cs)
Definition TString.h:564
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition TString.h:639
Int_t GetOptStat() const
Definition TStyle.h:236
Color_t GetStatTextColor() const
Definition TStyle.h:249
Float_t GetStatFontSize() const
Definition TStyle.h:252
Float_t GetStatX() const
Definition TStyle.h:255
Style_t GetTitleFont(Option_t *axis="X") const
Return title font.
Definition TStyle.cxx:1164
Float_t GetStatY() const
Definition TStyle.h:256
Color_t GetTitleFillColor() const
Definition TStyle.h:262
Style_t GetTitleStyle() const
Definition TStyle.h:264
Color_t GetStatColor() const
Definition TStyle.h:248
Float_t GetStatH() const
Definition TStyle.h:258
Width_t GetTitleBorderSize() const
Definition TStyle.h:266
Width_t GetStatBorderSize() const
Definition TStyle.h:250
Color_t GetTitleTextColor() const
Definition TStyle.h:263
Style_t GetStatStyle() const
Definition TStyle.h:253
Float_t GetStatW() const
Definition TStyle.h:257
const char * GetFitFormat() const
Definition TStyle.h:191
const char * GetStatFormat() const
Definition TStyle.h:254
Int_t GetOptFit() const
Definition TStyle.h:235
Style_t GetStatFont() const
Definition TStyle.h:251
Float_t GetTitleFontSize() const
Definition TStyle.h:265
virtual void Sleep(UInt_t milliSec)
Sleep milliSec milli seconds.
Definition TSystem.cxx:440
virtual Bool_t ProcessEvents()
Process pending events (GUI, timers, sockets).
Definition TSystem.cxx:419
See TView3D.
Definition TView.h:25
virtual void SetAutoRange(Bool_t autorange=kTRUE)=0
static TView * CreateView(Int_t system=1, const Double_t *rmin=0, const Double_t *rmax=0)
Create a concrete default 3-d view via the plug-in manager.
Definition TView.cxx:27
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.
TVirtualPad is an abstract base class for the Pad and Canvas classes.
Definition TVirtualPad.h:51
virtual TVirtualPad * cd(Int_t subpadnumber=0)=0
TVirtualPadPainter * CreatePadPainter() override
Creates web-based pad painter.
void ForceUpdate() override
Increment canvas version and force sending data to client - do not wit for reply.
void AddCustomClass(const std::string &clname, bool with_derived=false)
Assign custom class.
Bool_t CheckPadModified(TPad *pad, Bool_t inc_version=kTRUE)
Returns true if any pad in the canvas were modified Reset modified flags, increment canvas version (i...
void ShowCmd(const std::string &arg, Bool_t show)
Function used to send command to browser to toggle menu, toolbar, editors, ...
std::string fCustomScripts
! custom JavaScript code or URL on JavaScript files to load before start drawing
Definition TWebCanvas.h:73
virtual Bool_t IsReadOnly() const
Definition TWebCanvas.h:132
virtual Bool_t IsJSSupportedClass(TObject *obj)
Returns kTRUE when object is fully supported on JSROOT side In ROOT7 Paint function will just return ...
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:84
PadClickedSignal_t fPadClickedSignal
! signal emitted when simple mouse click performed on the pad
Definition TWebCanvas.h:82
static bool ProduceImage(TCanvas *c, const char *filename, Int_t width=0, Int_t height=0)
Create image using batch (headless) capability of Chrome browser Supported png, jpeg,...
void SetLongerPolling(Bool_t on)
Definition TWebCanvas.h:189
virtual Bool_t CanCreateObject(const std::string &)
Definition TWebCanvas.h:118
Int_t fPrimitivesMerge
! number of PS primitives, which will be merged together
Definition TWebCanvas.h:71
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.
std::vector< std::string > fCustomClasses
! list of custom classes, which can be delivered as is to client
Definition TWebCanvas.h:74
Bool_t IsAsyncMode() const
Definition TWebCanvas.h:198
static TString CreateCanvasJSON(TCanvas *c, Int_t json_compression=0)
Create JSON painting output for given canvas Produce JSON can be used for offline drawing with JSROOT...
Bool_t HasStatusBar() const override
Returns kTRUE if web canvas has status bar.
void Close() override
Close web canvas - not implemented.
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 ActivateInEditor(TPad *pad, TObject *obj)
Activate object in editor in web browser.
std::vector< WebConn > fWebConn
! connections
Definition TWebCanvas.h:60
PadSignal_t fActivePadChangedSignal
! signal emitted when active pad changed in the canvas
Definition TWebCanvas.h:81
Bool_t GetLongerPolling() const
Definition TWebCanvas.h:190
void ShowWebWindow(const ROOT::Experimental::RWebDisplayArgs &user_args="")
Show canvas in specified place.
UInt_t fClientBits
! latest status bits from client like editor visible or not
Definition TWebCanvas.h:67
std::function< void(TPadWebSnapshot *)> PadPaintingReady_t
Function called when pad painting produced.
Definition TWebCanvas.h:50
Int_t fPaletteDelivery
! colors palette delivery 0:never, 1:once, 2:always, 3:per subpad
Definition TWebCanvas.h:70
Bool_t fProcessingData
! flag used to prevent blocking methods when process data is invoked
Definition TWebCanvas.h:77
Bool_t HasToolTips() const override
Returns kTRUE if tooltips are activated in web canvas.
Bool_t AddToSendQueue(unsigned connid, const std::string &msg)
Add message to send queue for specified connection If connid == 0, message will be add to all connect...
Long64_t fCanvVersion
! actual canvas version, changed with every new Modified() call
Definition TWebCanvas.h:66
bool IsCustomClass(const TClass *cl) const
Checks if class belongs to custom.
void CreateObjectSnapshot(TPadWebSnapshot &master, TPad *pad, TObject *obj, const char *opt, TWebPS *masterps=nullptr)
Creates representation of the object for painting in web browser.
void AddColorsPalette(TPadWebSnapshot &master)
Add special canvas objects like colors list at selected palette.
virtual Bool_t DecodePadOptions(const std::string &)
Decode all pad options, which includes ranges plus objects options.
Bool_t PerformUpdate() override
if canvas or any subpad was modified, scan all primitives in the TCanvas and subpads and convert them...
void CheckDataToSend(unsigned connid=0)
Check if any data should be send to client If connid != 0, only selected connection will be checked.
UpdatedSignal_t fUpdatedSignal
! signal emitted when canvas updated or state is changed
Definition TWebCanvas.h:80
Int_t fJsonComp
! compression factor for messages send to the client
Definition TWebCanvas.h:72
Bool_t IsFirstConn(unsigned connid) const
Definition TWebCanvas.h:108
Bool_t fReadOnly
!< configured display
Definition TWebCanvas.h:64
Bool_t fHasSpecials
! has special objects which may require pad ranges
Definition TWebCanvas.h:65
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.
TWebCanvas(TCanvas *c, const char *name, Int_t x, Int_t y, UInt_t width, UInt_t height, Bool_t readonly=kTRUE)
Constructor.
TPad * ProcessObjectOptions(TWebObjectOptions &item, TPad *pad)
Process data for single primitive Returns object pad if object was modified.
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() ...
UInt_t GetWindowGeometry(Int_t &x, Int_t &y, UInt_t &w, UInt_t &h) override
Returns window geometry including borders and menus.
std::shared_ptr< ROOT::Experimental::RWebWindow > fWindow
Definition TWebCanvas.h:62
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:69
PadClickedSignal_t fPadDblClickedSignal
! signal emitted when simple mouse click performed on the pad
Definition TWebCanvas.h:83
TList fPrimitivesLists
! list of lists of primitives, temporary collected during painting
Definition TWebCanvas.h:68
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 ...
Int_t GetPaletteDelivery() const
Definition TWebCanvas.h:184
TObject * FindPrimitive(const std::string &id, TPad *pad=nullptr, TObjLink **padlnk=nullptr, TPad **objpad=nullptr)
Search of object with given id in list of primitives One could specify pad where search could be star...
Int_t GetStyleDelivery() const
Definition TWebCanvas.h:181
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 SetObjectIDAsPtr(void *ptr)
Use pointer to assign object id - TString::Hash.
void SetSnapshot(Int_t kind, TObject *snapshot, Bool_t owner=kFALSE)
SetUse 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