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 "TButton.h"
22#include "TFrame.h"
23#include "TPaveText.h"
24#include "TPaveStats.h"
25#include "TText.h"
26#include "TROOT.h"
27#include "TClass.h"
28#include "TColor.h"
29#include "TObjArray.h"
30#include "TArrayI.h"
31#include "TList.h"
32#include "TH1.h"
33#include "THStack.h"
34#include "TMultiGraph.h"
35#include "TEnv.h"
36#include "TError.h"
37#include "TGraph.h"
38#include "TBufferJSON.h"
39#include "TBase64.h"
40#include "TAtt3D.h"
41#include "TView.h"
42#include "TExec.h"
43#include "TVirtualX.h"
44#include "TMath.h"
45
46#include <cstdio>
47#include <cstring>
48#include <fstream>
49#include <iostream>
50#include <memory>
51#include <sstream>
52
53/** \class TWebCanvas
54\ingroup webgui6
55
56Basic TCanvasImp ABI implementation for Web-based GUI
57Provides painting of main ROOT6 classes in web browsers
58
59*/
60
61using namespace std::string_literals;
62
63////////////////////////////////////////////////////////////////////////////////
64/// Constructor
65
68{
69 fReadOnly = readonly;
70 fStyleDelivery = gEnv->GetValue("WebGui.StyleDelivery", 1);
71 fPaletteDelivery = gEnv->GetValue("WebGui.PaletteDelivery", 1);
72 fPrimitivesMerge = gEnv->GetValue("WebGui.PrimitivesMerge", 100);
74}
75
76////////////////////////////////////////////////////////////////////////////////
77/// Initialize window for the web canvas
78/// At this place canvas is not yet register to the list of canvases - one cannot call RWebWindow::Show()
79
81{
82 return 111222333; // should not be used at all
83}
84
85////////////////////////////////////////////////////////////////////////////////
86/// Creates web-based pad painter
87
89{
90 return new TWebPadPainter();
91}
92
93////////////////////////////////////////////////////////////////////////////////
94/// Returns kTRUE when object is fully supported on JSROOT side
95/// In ROOT7 Paint function will just return appropriate flag that object can be displayed on JSROOT side
96
98{
99 if (!obj)
100 return kTRUE;
101
102 static const struct {
103 const char *name{nullptr};
104 bool with_derived{false};
105 bool reduse_by_many{false};
106 } supported_classes[] = {{"TH1", true},
107 {"TF1", true},
108 {"TGraph", true},
109 {"TFrame"},
110 {"THStack"},
111 {"TMultiGraph"},
112 {"TGraphPolargram", true},
113 {"TPave", true},
114 {"TGaxis"},
115 {"TPave", true},
116 {"TArrow"},
117 {"TBox", false, true}, // can be handled via TWebPainter, disable for large number of primitives (like in greyscale.C)
118 {"TWbox"}, // some extra calls which cannot be handled via TWebPainter
119 {"TLine", false, true}, // can be handler via TWebPainter, disable for large number of primitives (like in greyscale.C)
120 {"TText"},
121 {"TLatex"},
122 {"TMathText"},
123 {"TMarker"},
124 {"TPolyMarker"},
125 // {"TPolyLine", false, true}, // can be handled via TWebPainter, simplify colors handling
126 {"TPolyMarker3D"},
127 {"TPolyLine3D"},
128 {"TGraphTime"},
129 {"TGraph2D"},
130 {"TGraph2DErrors"},
131 {"TGraphTime"},
132 {"TASImage"},
133 {"TRatioPlot"},
134 {"TSpline"},
135 {"TSpline3"},
136 {"TSpline5"},
137 {"TGeoManager"},
138 {"TGeoVolume"},
139 {}};
140
141 // fast check of class name
142 for (int i = 0; supported_classes[i].name != nullptr; ++i)
143 if ((!many_primitives || !supported_classes[i].reduse_by_many) && (strcmp(supported_classes[i].name, obj->ClassName()) == 0))
144 return kTRUE;
145
146 // now check inheritance only for configured classes
147 for (int i = 0; supported_classes[i].name != nullptr; ++i)
148 if (supported_classes[i].with_derived && (!many_primitives || !supported_classes[i].reduse_by_many))
149 if (obj->InheritsFrom(supported_classes[i].name))
150 return kTRUE;
151
152 return IsCustomClass(obj->IsA());
153}
154
155//////////////////////////////////////////////////////////////////////////////////////////////////
156/// Configures custom script for canvas.
157/// If started from "load:" or "assert:" prefix will be loaded with JSROOT.AssertPrerequisites function
158/// Script should implement custom user classes, which transferred as is to client
159/// In the script draw handler for appropriate classes would be assigned
160
161void TWebCanvas::SetCustomScripts(const std::string &src)
162{
164}
165
166//////////////////////////////////////////////////////////////////////////////////////////////////
167/// Assign custom class
168
169void TWebCanvas::AddCustomClass(const std::string &clname, bool with_derived)
170{
171 if (with_derived)
172 fCustomClasses.emplace_back("+"s + clname);
173 else
174 fCustomClasses.emplace_back(clname);
175}
176
177//////////////////////////////////////////////////////////////////////////////////////////////////
178/// Checks if class belongs to custom
179
181{
182 for (auto &name : fCustomClasses) {
183 if (name[0] == '+') {
184 if (cl->InheritsFrom(name.substr(1).c_str()))
185 return true;
186 } else if (name.compare(cl->GetName()) == 0) {
187 return true;
188 }
189 }
190 return false;
191}
192
193//////////////////////////////////////////////////////////////////////////////////////////////////
194/// Creates representation of the object for painting in web browser
195
196void TWebCanvas::CreateObjectSnapshot(TPadWebSnapshot &master, TPad *pad, TObject *obj, const char *opt, TWebPS *masterps)
197{
198 if (IsJSSupportedClass(obj, masterps != nullptr)) {
199 master.NewPrimitive(obj, opt).SetSnapshot(TWebSnapshot::kObject, obj);
200 return;
201 }
202
203 // painter is not necessary for batch canvas, but keep configuring it for a while
204 auto *painter = dynamic_cast<TWebPadPainter *>(Canvas()->GetCanvasPainter());
205
206 TView *view = nullptr;
207 auto savepad = gPad;
208
209 pad->cd();
210
211 if (obj->InheritsFrom(TAtt3D::Class()) && !pad->GetView()) {
212 pad->GetViewer3D("pad");
213 view = TView::CreateView(1, 0, 0); // Cartesian view by default
214 pad->SetView(view);
215
216 // Set view to perform first auto-range (scaling) pass
217 view->SetAutoRange(kTRUE);
218 }
219
220 TVirtualPS *saveps = gVirtualPS;
221
222 TWebPS ps;
223 gVirtualPS = masterps ? masterps : &ps;
224 if (painter)
225 painter->SetPainting(ps.GetPainting());
226
227 // calling Paint function for the object
228 obj->Paint(opt);
229
230 if (view) {
231 view->SetAutoRange(kFALSE);
232 // call 3D paint once again to make real drawing
233 obj->Paint(opt);
234 pad->SetView(nullptr);
235 }
236
237 if (painter)
238 painter->SetPainting(nullptr);
239
240 gVirtualPS = saveps;
241 if (savepad)
242 savepad->cd();
243
244 // if there are master PS, do not create separate entries
245 if (!masterps && !ps.IsEmptyPainting())
247}
248
249//////////////////////////////////////////////////////////////////////////////////////////////////
250/// Calculate hash function for all colors and palette
251
253{
254 UInt_t hash = 0;
255
256 TObjArray *colors = (TObjArray *)gROOT->GetListOfColors();
257
258 if (colors) {
259 for (Int_t n = 0; n <= colors->GetLast(); ++n)
260 if (colors->At(n))
261 hash += TString::Hash(colors->At(n), TColor::Class()->Size());
262 }
263
265
266 hash += TString::Hash(pal.GetArray(), pal.GetSize() * sizeof(Int_t));
267
268 return hash;
269}
270
271
272//////////////////////////////////////////////////////////////////////////////////////////////////
273/// Add special canvas objects like colors list at selected palette
274
276{
277 TObjArray *colors = (TObjArray *)gROOT->GetListOfColors();
278
279 if (!colors)
280 return;
281
282 //Int_t cnt = 0;
283 //for (Int_t n = 0; n <= colors->GetLast(); ++n)
284 // if (colors->At(n))
285 // cnt++;
286 //if (cnt <= 598)
287 // return; // normally there are 598 colors defined
288
290
291 auto *listofcols = new TWebPainting;
292 for (Int_t n = 0; n <= colors->GetLast(); ++n)
293 if (colors->At(n))
294 listofcols->AddColor(n, (TColor *)colors->At(n));
295
296 // store palette in the buffer
297 auto *tgt = listofcols->Reserve(pal.GetSize());
298 for (Int_t i = 0; i < pal.GetSize(); i++)
299 tgt[i] = pal[i];
300 listofcols->FixSize();
301
302 master.NewSpecials().SetSnapshot(TWebSnapshot::kColors, listofcols, kTRUE);
303}
304
305//////////////////////////////////////////////////////////////////////////////////////////////////
306/// Create snapshot for pad and all primitives
307/// Callback function is used to create JSON in the middle of data processing -
308/// when all misc objects removed from canvas list of primitives or histogram list of functions
309/// After that objects are moved back to their places
310
312{
313 auto &pad_status = fPadsStatus[pad];
314
315 // send primitives if version 0 or actual pad version grater than already send version
316 bool process_primitives = (version == 0) || (pad_status.fVersion > version);
317
318 if (paddata.IsSetObjectIds()) {
319 paddata.SetActive(pad == gPad);
320 paddata.SetObjectIDAsPtr(pad);
321 }
322 paddata.SetSnapshot(TWebSnapshot::kSubPad, pad); // add ref to the pad
323 paddata.SetWithoutPrimitives(!process_primitives);
324
325 // check style changes every time when creating canvas snapshot
326 if (resfunc && (GetStyleDelivery() > 0)) {
327
329 auto hash = TString::Hash(gStyle, TStyle::Class()->Size());
330 if ((hash != fStyleHash) || (fStyleVersion == 0)) {
331 fStyleHash = hash;
333 }
334 }
335
336 if (fStyleVersion > version)
338 }
339
340 TList *primitives = pad->GetListOfPrimitives();
341
342 if (primitives) fPrimitivesLists.Add(primitives); // add list of primitives
343
344 TWebPS masterps;
345 bool usemaster = primitives ? (primitives->GetSize() > fPrimitivesMerge) : false;
346
347 TIter iter(primitives);
348 TObject *obj = nullptr;
349 TFrame *frame = nullptr;
350 TPaveText *title = nullptr;
351 bool need_frame = false, has_histo = false;
352 std::string need_title;
353
354 while (process_primitives && ((obj = iter()) != nullptr)) {
355 TString opt = iter.GetOption();
356 opt.ToUpper();
357
358 if (obj->InheritsFrom(THStack::Class())) {
359 // workaround for THStack, create extra components before sending to client
360 auto hs = static_cast<THStack *>(obj);
361 TVirtualPad::TContext ctxt(pad, kFALSE);
362 hs->BuildPrimitives(iter.GetOption());
363 has_histo = true;
364 } else if (obj->InheritsFrom(TMultiGraph::Class())) {
365 // workaround for TMultiGraph
366 if (opt.Contains("A")) {
367 auto mg = static_cast<TMultiGraph *>(obj);
369 mg->GetHistogram(); // force creation of histogram without any drawings
370 has_histo = true;
371 }
372 } else if (obj->InheritsFrom(TFrame::Class())) {
373 frame = static_cast<TFrame *>(obj);
374 } else if (obj->InheritsFrom(TH1::Class())) {
375 need_frame = true;
376 has_histo = true;
377 if (!obj->TestBit(TH1::kNoTitle) && !opt.Contains("SAME") && (strlen(obj->GetTitle()) > 0))
378 need_title = obj->GetTitle();
379 } else if (obj->InheritsFrom(TGraph::Class())) {
380 if (opt.Contains("A")) {
381 need_frame = true;
382 if (!has_histo && (strlen(obj->GetTitle()) > 0))
383 need_title = obj->GetTitle();
384 }
385 } else if (obj->InheritsFrom(TPaveText::Class())) {
386 if (strcmp(obj->GetName(), "title") == 0)
387 title = static_cast<TPaveText *>(obj);
388 }
389 }
390
391 if (need_frame && !frame && primitives && CanCreateObject("TFrame")) {
392 frame = pad->GetFrame();
393 if(frame)
394 primitives->AddFirst(frame);
395 }
396
397 if (!need_title.empty() && gStyle->GetOptTitle()) {
398 if (title) {
399 auto line0 = title->GetLine(0);
400 if (line0 && !IsReadOnly()) line0->SetTitle(need_title.c_str());
401 } else if (primitives && CanCreateObject("TPaveText")) {
402 title = new TPaveText(0, 0, 0, 0, "blNDC");
405 title->SetName("title");
408 title->SetTextFont(gStyle->GetTitleFont(""));
409 if (gStyle->GetTitleFont("") % 10 > 2)
411 title->AddText(need_title.c_str());
412 title->SetBit(kCanDelete);
413 primitives->Add(title);
414 }
415 }
416
417 auto flush_master = [&]() {
418 if (!usemaster || masterps.IsEmptyPainting()) return;
419
421 masterps.CreatePainting(); // create for next operations
422 };
423
424 iter.Reset();
425
426 bool first_obj = true;
427
428 if (process_primitives)
429 pad_status._has_specials = false;
430
431 while ((obj = iter()) != nullptr) {
432 if (obj->InheritsFrom(TPad::Class())) {
433 flush_master();
434 CreatePadSnapshot(paddata.NewSubPad(), (TPad *)obj, version, nullptr);
435 } else if (!process_primitives) {
436 continue;
437 } else if (obj->InheritsFrom(TH1::Class())) {
438 flush_master();
439
440 TH1 *hist = (TH1 *)obj;
441 TIter fiter(hist->GetListOfFunctions());
442 TObject *fobj = nullptr;
443 TPaveStats *stats = nullptr;
444 TObject *palette = nullptr;
445
446 hist->BufferEmpty();
447
448 while ((fobj = fiter()) != nullptr) {
449 if (fobj->InheritsFrom(TPaveStats::Class()))
450 stats = dynamic_cast<TPaveStats *> (fobj);
451 else if (fobj->InheritsFrom("TPaletteAxis"))
452 palette = fobj;
453 }
454
455 if (!stats && first_obj && (gStyle->GetOptStat() > 0) && CanCreateObject("TPaveStats")) {
456 stats = new TPaveStats(
459 gStyle->GetStatX(),
460 gStyle->GetStatY(), "brNDC");
461
462 stats->SetParent(hist);
463 // do not set optfit and optstat, they calling pad->Update,
464 // values correctly set already in TPaveStats constructor
465 // stats->SetOptFit(gStyle->GetOptFit());
466 // stats->SetOptStat(gStyle->GetOptStat());
470 stats->SetTextFont(gStyle->GetStatFont());
471 if (gStyle->GetStatFont()%10 > 2)
475 stats->SetName("stats");
476
478 stats->SetTextAlign(12);
479 stats->SetBit(kCanDelete);
480 stats->SetBit(kMustCleanup);
481
482 hist->GetListOfFunctions()->Add(stats);
483 }
484
485 TString hopt = iter.GetOption();
486
487 if (!palette && CanCreateObject("TPaletteAxis") && (hist->GetDimension() > 1) &&
488 (hopt.Index("colz", 0, TString::kIgnoreCase) != kNPOS)) {
489 std::stringstream exec;
490 exec << "new TPaletteAxis(0,0,0,0, (TH1*)" << std::hex << std::showbase << (size_t)hist << ");";
491 palette = (TObject *)gROOT->ProcessLine(exec.str().c_str());
492 if (palette)
493 hist->GetListOfFunctions()->AddFirst(palette);
494 }
495
496 if (title && first_obj) hopt.Append(";;use_pad_title");
497
498 // if (stats) hopt.Append(";;use_pad_stats");
499
500 if (palette) hopt.Append(";;use_pad_palette");
501
502 paddata.NewPrimitive(obj, hopt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
503
504 // do not extract objects from list of functions - stats and func need to be handled together with hist
505 //
506 // fiter.Reset();
507 // while ((fobj = fiter()) != nullptr)
508 // CreateObjectSnapshot(paddata, pad, fobj, fiter.GetOption());
509
510 // fPrimitivesLists.Add(hist->GetListOfFunctions());
511
512 first_obj = false;
513 } else if (obj->InheritsFrom(TGraph::Class())) {
514 flush_master();
515
516 TGraph *gr = (TGraph *)obj;
517 auto funcs = gr->GetListOfFunctions();
518
519 TIter fiter(funcs);
520 TObject *fobj = nullptr;
521 TPaveStats *stats = nullptr;
522
523 while ((fobj = fiter()) != nullptr) {
524 if (fobj->InheritsFrom(TPaveStats::Class()))
525 stats = dynamic_cast<TPaveStats *> (fobj);
526 }
527
528 // ensure histogram exists on server to draw it properly on clients side
529 if (!IsReadOnly() && first_obj)
530 gr->GetHistogram();
531
532 TString gropt = iter.GetOption();
533 if (title && first_obj) gropt.Append(";;use_pad_title");
534 if (stats) gropt.Append(";;use_pad_stats");
535
536 paddata.NewPrimitive(obj, gropt.Data()).SetSnapshot(TWebSnapshot::kObject, obj);
537
538 fiter.Reset();
539 while ((fobj = fiter()) != nullptr)
540 CreateObjectSnapshot(paddata, pad, fobj, fiter.GetOption());
541
542 if (funcs)
544 first_obj = false;
545 } else if (IsJSSupportedClass(obj, usemaster)) {
546 flush_master();
547 paddata.NewPrimitive(obj, iter.GetOption()).SetSnapshot(TWebSnapshot::kObject, obj);
548 } else {
549 CreateObjectSnapshot(paddata, pad, obj, iter.GetOption(), usemaster ? &masterps : nullptr);
550 pad_status._has_specials = true;
551 }
552 }
553
554 flush_master();
555
556 bool provide_colors = false;
557
558 if ((GetPaletteDelivery() > 2) || ((GetPaletteDelivery() == 2) && resfunc)) {
559 // provide colors: either for each subpad (> 2) or only for canvas (== 2)
560 provide_colors = process_primitives;
561 } else if ((GetPaletteDelivery() == 1) && resfunc) {
562 // check that colors really changing, using hash
563
565 auto hash = CalculateColorsHash();
566 if ((hash != fColorsHash) || (fColorsVersion == 0)) {
567 fColorsHash = hash;
569 }
570 }
571
572 provide_colors = fColorsVersion > version;
573 }
574
575 // add colors after painting is performed - new colors may be generated only during painting
576 if (provide_colors)
577 AddColorsPalette(paddata);
578
579 if (!resfunc)
580 return;
581
582 // now move all primitives and functions into separate list to perform I/O
583
584 TList save_lst;
585 TIter diter(&fPrimitivesLists);
586 TList *dlst = nullptr;
587 while ((dlst = (TList *)diter()) != nullptr) {
588 TIter fiter(dlst);
589 while ((obj = fiter()) != nullptr)
590 save_lst.Add(obj, fiter.GetOption());
591 save_lst.Add(dlst); // add list itself to have marker
592 dlst->Clear("nodelete");
593 }
594
595 // execute function to prevent storing of colors with custom TCanvas streamer
596 // TODO: Olivier - we need to change logic here!
598
599 // invoke callback for master painting
600 resfunc(&paddata);
601
602 TIter siter(&save_lst);
603 diter.Reset();
604 while ((dlst = (TList *)diter()) != nullptr) {
605 while ((obj = siter()) != nullptr) {
606 if (obj == dlst)
607 break;
608 dlst->Add(obj, siter.GetOption());
609 }
610 }
611
612 save_lst.Clear("nodelete");
613
614 fPrimitivesLists.Clear("nodelete");
615}
616
617//////////////////////////////////////////////////////////////////////////////////////////////////
618/// Add message to send queue for specified connection
619/// If connid == 0, message will be add to all connections
620/// Return kFALSE if queue is full or connection is not exists
621
622Bool_t TWebCanvas::AddToSendQueue(unsigned connid, const std::string &msg)
623{
624 Bool_t res = false;
625 for (auto &conn : fWebConn) {
626 if ((conn.fConnId == connid) || (connid == 0)) {
627 conn.fSend.emplace(msg);
628 res = kTRUE;
629 }
630 }
631 return res;
632}
633
634
635//////////////////////////////////////////////////////////////////////////////////////////////////
636/// Check if any data should be send to client
637/// If connid != 0, only selected connection will be checked
638
639void TWebCanvas::CheckDataToSend(unsigned connid)
640{
641 if (!Canvas() || !fWindow)
642 return;
643
644 for (auto &conn : fWebConn) {
645 if (connid && (conn.fConnId != connid))
646 continue;
647
648 // check if direct data sending is possible
649 if (!fWindow->CanSend(conn.fConnId, true))
650 continue;
651
652 std::string buf;
653
654 if ((conn.fCheckedVersion < fCanvVersion) && (conn.fSendVersion == conn.fDrawVersion)) {
655
656 buf = "SNAP6:"s + std::to_string(fCanvVersion) + ":"s;
657
659
660 // scripts send only when canvas drawn for the first time
661 if (!conn.fSendVersion)
663
664 holder.SetHighlightConnect(Canvas()->HasConnection("Highlighted(TVirtualPad*,TObject*,Int_t,Int_t)"));
665
666 CreatePadSnapshot(holder, Canvas(), conn.fSendVersion, [&buf, &conn, this](TPadWebSnapshot *snap) {
667 auto json = TBufferJSON::ToJSON(snap, fJsonComp);
668 auto hash = json.Hash();
669 if (conn.fLastSendHash && (conn.fLastSendHash == hash) && conn.fSendVersion) {
670 // prevent looping when same data send many times
671 buf.clear();
672 } else {
673 buf.append(json.Data());
674 conn.fLastSendHash = hash;
675 }
676 });
677
678 conn.fCheckedVersion = fCanvVersion;
679
680 conn.fSendVersion = fCanvVersion;
681
682 if (buf.empty())
683 conn.fDrawVersion = fCanvVersion;
684
685 } else if (!conn.fSend.empty()) {
686
687 std::swap(buf, conn.fSend.front());
688 conn.fSend.pop();
689
690 }
691
692 if (!buf.empty())
693 fWindow->Send(conn.fConnId, buf);
694 }
695}
696
697//////////////////////////////////////////////////////////////////////////////////////////
698/// Close web canvas - not implemented
699
701{
702}
703
704//////////////////////////////////////////////////////////////////////////////////////////
705/// Show canvas in specified place.
706/// If parameter args not specified, default ROOT web display will be used
707
709{
710 if (!fWindow) {
712
713 fWindow->SetConnLimit(0); // configure connections limit
714
715 fWindow->SetDefaultPage("file:rootui5sys/canv/canvas6.html");
716
717 fWindow->SetCallBacks(
718 // connection
719 [this](unsigned connid) {
720 fWebConn.emplace_back(connid);
721 CheckDataToSend(connid);
722 },
723 // data
724 [this](unsigned connid, const std::string &arg) {
725 ProcessData(connid, arg);
726 CheckDataToSend(connid);
727 },
728 // disconnect
729 [this](unsigned connid) {
730 unsigned indx = 0;
731 for (auto &c : fWebConn) {
732 if (c.fConnId == connid) {
733 fWebConn.erase(fWebConn.begin() + indx);
734 break;
735 }
736 indx++;
737 }
738 });
739 }
740
741 auto w = Canvas()->GetWw(), h = Canvas()->GetWh();
742
743 if ((w > 10) && (w < 50000) && (h > 10) && (h < 30000))
744 fWindow->SetGeometry(w + 6, h + 22);
745
750
751 fWindow->Show(args);
752}
753
754//////////////////////////////////////////////////////////////////////////////////////////
755/// Show canvas in browser window
756
758{
759 if (gROOT->IsWebDisplayBatch())
760 return;
761
763 args.SetWidgetKind("TCanvas");
764 ShowWebWindow(args);
765}
766
767//////////////////////////////////////////////////////////////////////////////////////////
768/// Function used to send command to browser to toggle menu, toolbar, editors, ...
769
770void TWebCanvas::ShowCmd(const std::string &arg, Bool_t show)
771{
772 if (AddToSendQueue(0, "SHOW:"s + arg + (show ? ":1"s : ":0"s)))
774}
775
776//////////////////////////////////////////////////////////////////////////////////////////
777/// Activate object in editor in web browser
778
780{
781 if (!pad || !obj) return;
782
783 UInt_t hash = TString::Hash(&obj, sizeof(obj));
784
785 if (AddToSendQueue(0, "EDIT:"s + std::to_string(hash)))
787}
788
789//////////////////////////////////////////////////////////////////////////////////////////
790/// Returns kTRUE if web canvas has graphical editor
791
793{
794 return (fClientBits & TCanvas::kShowEditor) != 0;
795}
796
797//////////////////////////////////////////////////////////////////////////////////////////
798/// Returns kTRUE if web canvas has menu bar
799
801{
802 return (fClientBits & TCanvas::kMenuBar) != 0;
803}
804
805//////////////////////////////////////////////////////////////////////////////////////////
806/// Returns kTRUE if web canvas has status bar
807
809{
811}
812
813//////////////////////////////////////////////////////////////////////////////////////////
814/// Returns kTRUE if tooltips are activated in web canvas
815
817{
818 return (fClientBits & TCanvas::kShowToolTips) != 0;
819}
820
821//////////////////////////////////////////////////////////////////////////////////////////
822/// Assign clients bits
823
825{
826 fClientBits = bits;
831}
832
833//////////////////////////////////////////////////////////////////////////////////////////////////
834/// Decode all pad options, which includes ranges plus objects options
835
836Bool_t TWebCanvas::DecodePadOptions(const std::string &msg, bool process_execs)
837{
838 if (IsReadOnly() || msg.empty())
839 return kFALSE;
840
841 auto arr = TBufferJSON::FromJSON<std::vector<TWebPadOptions>>(msg);
842
843 if (!arr)
844 return kFALSE;
845
846 Bool_t need_update = kFALSE;
847
848 TPad *pad_with_execs = nullptr;
849 TExec *hist_exec = nullptr;
850
851 for (unsigned n = 0; n < arr->size(); ++n) {
852 auto &r = arr->at(n);
853 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(r.snapid));
854
855 if (!pad)
856 continue;
857
858 if (pad == Canvas()) {
859 AssignStatusBits(r.bits);
860 Canvas()->fCw = r.cw;
861 Canvas()->fCh = r.ch;
862 }
863
864 if (r.active && (pad != gPad)) gPad = pad;
865
866 if ((pad->GetTickx() != r.tickx) || (pad->GetTicky() != r.ticky))
867 pad->SetTicks(r.tickx, r.ticky);
868 if ((pad->GetGridx() != (r.gridx > 0)) || (pad->GetGridy() != (r.gridy > 0)))
869 pad->SetGrid(r.gridx, r.gridy);
870 pad->fLogx = r.logx;
871 pad->fLogy = r.logy;
872 pad->fLogz = r.logz;
873
874 pad->SetLeftMargin(r.mleft);
875 pad->SetRightMargin(r.mright);
876 pad->SetTopMargin(r.mtop);
877 pad->SetBottomMargin(r.mbottom);
878
879 if (r.ranges) {
880 // avoid call of original methods, set members directly
881 // pad->Range(r.px1, r.py1, r.px2, r.py2);
882 // pad->RangeAxis(r.ux1, r.uy1, r.ux2, r.uy2);
883
884 pad->fX1 = r.px1;
885 pad->fX2 = r.px2;
886 pad->fY1 = r.py1;
887 pad->fY2 = r.py2;
888
889 pad->fUxmin = r.ux1;
890 pad->fUxmax = r.ux2;
891 pad->fUymin = r.uy1;
892 pad->fUymax = r.uy2;
893 }
894
895 // pad->SetPad(r.mleft, r.mbottom, 1-r.mright, 1-r.mtop);
896
897 pad->fAbsXlowNDC = r.xlow;
898 pad->fAbsYlowNDC = r.ylow;
899 pad->fAbsWNDC = r.xup - r.xlow;
900 pad->fAbsHNDC = r.yup - r.ylow;
901
902 if (pad == Canvas()) {
903 pad->fXlowNDC = r.xlow;
904 pad->fYlowNDC = r.ylow;
905 pad->fXUpNDC = r.xup;
906 pad->fYUpNDC = r.yup;
907 pad->fWNDC = r.xup - r.xlow;
908 pad->fHNDC = r.yup - r.ylow;
909 } else {
910 auto mother = pad->GetMother();
911 if (mother->GetAbsWNDC() > 0. && mother->GetAbsHNDC() > 0.) {
912 pad->fXlowNDC = (r.xlow - mother->GetAbsXlowNDC()) / mother->GetAbsWNDC();
913 pad->fYlowNDC = (r.ylow - mother->GetAbsYlowNDC()) / mother->GetAbsHNDC();
914 pad->fXUpNDC = (r.xup - mother->GetAbsXlowNDC()) / mother->GetAbsWNDC();
915 pad->fYUpNDC = (r.yup - mother->GetAbsYlowNDC()) / mother->GetAbsHNDC();
916 pad->fWNDC = (r.xup - r.xlow) / mother->GetAbsWNDC();
917 pad->fHNDC = (r.yup - r.ylow) / mother->GetAbsHNDC();
918 }
919 }
920
921 // copy of code from TPad::ResizePad()
922
923 Double_t pxlow = r.xlow * r.cw;
924 Double_t pylow = (1-r.ylow) * r.ch;
925 Double_t pxrange = (r.xup - r.xlow) * r.cw;
926 Double_t pyrange = -1*(r.yup - r.ylow) * r.ch;
927
928 Double_t rounding = 0.00005;
929 Double_t xrange = r.px2 - r.px1;
930 Double_t yrange = r.py2 - r.py1;
931
932 if ((xrange != 0.) && (pxrange != 0)) {
933 // Linear X axis
934 pad->fXtoAbsPixelk = rounding + pxlow - pxrange*r.px1/xrange; //origin at left
935 pad->fXtoPixelk = rounding + -pxrange*r.px1/xrange;
936 pad->fXtoPixel = pxrange/xrange;
937 pad->fAbsPixeltoXk = r.px1 - pxlow*xrange/pxrange;
938 pad->fPixeltoXk = r.px1;
939 pad->fPixeltoX = xrange/pxrange;
940 }
941
942 if ((yrange != 0.) && (pyrange != 0.)) {
943 // Linear Y axis
944 pad->fYtoAbsPixelk = rounding + pylow - pyrange*r.py1/yrange; //origin at top
945 pad->fYtoPixelk = rounding + -pyrange - pyrange*r.py1/yrange;
946 pad->fYtoPixel = pyrange/yrange;
947 pad->fAbsPixeltoYk = r.py1 - pylow*yrange/pyrange;
948 pad->fPixeltoYk = r.py1;
949 pad->fPixeltoY = yrange/pyrange;
950 }
951
953
954 TObjLink *objlnk = nullptr;
955
956 TH1 *hist = static_cast<TH1 *>(FindPrimitive("histogram", 1, pad, &objlnk));
957
958 if (hist) {
959
960 TObject *hist_holder = objlnk ? objlnk->GetObject() : nullptr;
961 if (hist_holder == hist)
962 hist_holder = nullptr;
963
964 Bool_t no_entries = hist->GetEntries();
965
966 Double_t hmin = 0., hmax = 0.;
967
968 if (r.zx1 == r.zx2)
969 hist->GetXaxis()->SetRange(0,0);
970 else
971 hist->GetXaxis()->SetRangeUser(r.zx1, r.zx2);
972
973 if (hist->GetDimension() == 1) {
974 hmin = r.zy1;
975 hmax = r.zy2;
976 if ((hmin == hmax) && !no_entries) {
977 // if there are no zooming on Y and histogram has no entries, hmin/hmax should be set to full range
978 hmin = pad->fLogy ? TMath::Power(pad->fLogy < 2 ? 10 : pad->fLogy, r.uy1) : r.uy1;
979 hmax = pad->fLogy ? TMath::Power(pad->fLogy < 2 ? 10 : pad->fLogy, r.uy2) : r.uy2;
980 }
981 } else if (r.zy1 == r.zy2) {
982 hist->GetYaxis()->SetRange(0., 0.);
983 } else {
984 hist->GetYaxis()->SetRangeUser(r.zy1, r.zy2);
985 }
986
987 if (hist->GetDimension() == 2) {
988 hmin = r.zz1;
989 hmax = r.zz2;
990 if ((hmin == hmax) && !no_entries) {
991 // z scale is not transformed
992 hmin = r.uz1;
993 hmax = r.uz2;
994 }
995 } else if (hist->GetDimension() == 3) {
996 if (r.zz1 == r.zz2) {
997 hist->GetZaxis()->SetRange(0., 0.);
998 } else {
999 hist->GetZaxis()->SetRangeUser(r.zz1, r.zz2);
1000 }
1001 }
1002
1003 if (hmin == hmax)
1004 hmin = hmax = -1111;
1005
1006 if (!hist_holder) {
1007 hist->SetMinimum(hmin);
1008 hist->SetMaximum(hmax);
1009 } else {
1010 auto SetMember = [hist_holder](const char *name, Double_t value) {
1011 auto offset = hist_holder->IsA()->GetDataMemberOffset(name);
1012 if (offset > 0)
1013 *((Double_t *)((char*) hist_holder + offset)) = value;
1014 else
1015 ::Error("SetMember", "Cannot find %s data member in %s", name, hist_holder->ClassName());
1016 };
1017
1018 // directly set min/max in classes like THStack, TGraph, TMultiGraph
1019 SetMember("fMinimum", hmin);
1020 SetMember("fMaximum", hmax);
1021 }
1022
1023 TIter next(hist->GetListOfFunctions());
1024 while (auto fobj = next())
1025 if (!hist_exec && fobj->InheritsFrom(TExec::Class())) {
1026 hist_exec = (TExec *) fobj;
1027 need_update = kTRUE;
1028 }
1029 }
1030
1031 std::map<std::string, int> idmap;
1032
1033 for (auto &item : r.primitives) {
1034 auto iter = idmap.find(item.snapid);
1035 int idcnt = 1;
1036 if (iter == idmap.end())
1037 idmap[item.snapid] = 1;
1038 else
1039 idcnt = ++iter->second;
1040
1041 ProcessObjectOptions(item, pad, idcnt);
1042 }
1043
1044 // without special objects no need for explicit update of the pad
1045 if (fPadsStatus[pad]._has_specials) {
1046 pad->Modified(kTRUE);
1047 need_update = kTRUE;
1048 }
1049
1050 if (process_execs && (gPad == pad))
1051 pad_with_execs = pad;
1052 }
1053
1054 ProcessExecs(pad_with_execs, hist_exec);
1055
1056 if (fUpdatedSignal) fUpdatedSignal(); // invoke signal
1057
1058 return need_update;
1059}
1060
1061//////////////////////////////////////////////////////////////////////////////////////////////////
1062/// Process TExec objects in the pad
1063
1065{
1066 auto execs = pad ? pad->GetListOfExecs() : nullptr;
1067
1068 if ((!execs || !execs->GetSize()) && !extra)
1069 return;
1070
1071 auto saveps = gVirtualPS;
1072 TWebPS ps;
1073 gVirtualPS = &ps;
1074
1075 auto savex = gVirtualX;
1076 TVirtualX x;
1077 gVirtualX = &x;
1078
1079 TIter next(execs);
1080 while (auto obj = next()) {
1081 auto exec = dynamic_cast<TExec *>(obj);
1082 if (exec)
1083 exec->Exec();
1084 }
1085
1086 if (extra)
1087 extra->Exec();
1088
1089 gVirtualPS = saveps;
1090 gVirtualX = savex;
1091}
1092
1093//////////////////////////////////////////////////////////////////////////////////////////
1094/// Handle data from web browser
1095/// Returns kFALSE if message was not processed
1096
1097Bool_t TWebCanvas::ProcessData(unsigned connid, const std::string &arg)
1098{
1099 if (arg.empty())
1100 return kTRUE;
1101
1102 // try to identify connection for given WS request
1103 unsigned indx = 0;
1104 for (auto &c : fWebConn) {
1105 if (c.fConnId == connid) break;
1106 indx++;
1107 }
1108 if (indx >= fWebConn.size())
1109 return kTRUE;
1110
1111 struct FlagGuard {
1112 Bool_t &flag;
1113 FlagGuard(Bool_t &_flag) : flag(_flag) { flag = true; }
1114 ~FlagGuard() { flag = false; }
1115 };
1116
1117 FlagGuard guard(fProcessingData);
1118
1119 const char *cdata = arg.c_str();
1120
1121 if (arg == "KEEPALIVE") {
1122 // do nothing
1123
1124 } else if (arg == "QUIT") {
1125
1126 // use window manager to correctly terminate http server
1127 fWindow->TerminateROOT();
1128
1129 } else if (arg.compare(0, 7, "READY6:") == 0) {
1130
1131 // this is reply on drawing of ROOT6 snapshot
1132 // it confirms when drawing of specific canvas version is completed
1133
1134 cdata += 7;
1135
1136 const char *separ = strchr(cdata, ':');
1137 if (!separ) {
1138 fWebConn[indx].fDrawVersion = std::stoll(cdata);
1139 } else {
1140 fWebConn[indx].fDrawVersion = std::stoll(std::string(cdata, separ - cdata));
1141 if ((indx == 0) && !IsReadOnly())
1142 if (DecodePadOptions(separ+1, false)) {
1145 }
1146 }
1147
1148 } else if (arg == "RELOAD") {
1149
1150 // trigger reload of canvas data
1151 fWebConn[indx].reset();
1152
1153 } else if (arg.compare(0, 5, "SAVE:") == 0) {
1154
1155 // save image produced by the client side - like png or svg
1156 const char *img = cdata + 5;
1157
1158 const char *separ = strchr(img, ':');
1159 if (separ) {
1160 TString filename(img, separ - img);
1161 img = separ + 1;
1162
1163 std::ofstream ofs(filename.Data());
1164
1165 if (filename.Index(".svg") != kNPOS) {
1166 // ofs << "<?xml version=\"1.0\" standalone=\"no\"?>";
1167 ofs << img;
1168 } else {
1169 TString binary = TBase64::Decode(img);
1170 ofs.write(binary.Data(), binary.Length());
1171 }
1172 ofs.close();
1173
1174 Info("ProcessData", "File %s has been created", filename.Data());
1175 }
1176
1177 } else if (arg.compare(0, 8, "PRODUCE:") == 0) {
1178
1179 // create ROOT, PDF, ... files using native ROOT functionality
1180 Canvas()->Print(arg.c_str() + 8);
1181
1182 } else if (arg.compare(0, 9, "OPTIONS6:") == 0) {
1183
1184 if ((indx == 0) && !IsReadOnly())
1185 if (DecodePadOptions(arg.substr(9), true)) {
1186
1189 }
1190
1191 } else if (arg.compare(0, 11, "STATUSBITS:") == 0) {
1192
1193 if (indx == 0) {
1194 AssignStatusBits(std::stoul(arg.substr(11)));
1195 if (fUpdatedSignal) fUpdatedSignal(); // invoke signal
1196 }
1197 } else if (arg.compare(0, 10, "HIGHLIGHT:") == 0) {
1198 if (indx == 0) {
1199 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(10));
1200 if (!arr || (arr->size() != 4)) {
1201 Error("ProcessData", "Wrong arguments count %d in highlight message", (int)(arr ? arr->size() : -1));
1202 } else {
1203 auto pad = dynamic_cast<TVirtualPad *>(FindPrimitive(arr->at(0)));
1204 auto obj = FindPrimitive(arr->at(1));
1205 int argx = std::stoi(arr->at(2));
1206 int argy = std::stoi(arr->at(3));
1207 if (pad && obj) {
1208 Canvas()->Highlighted(pad, obj, argx, argy);
1210 }
1211 }
1212 }
1213 } else if (IsReadOnly()) {
1214
1215 // all following messages are not allowed in readonly mode
1216 return kFALSE;
1217
1218 } else if (arg.compare(0, 6, "EVENT:") == 0) {
1219 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(6));
1220 if (!arr || (arr->size() != 5)) {
1221 Error("ProcessData", "Wrong arguments count %d in event message", (int)(arr ? arr->size() : -1));
1222 } else {
1223 auto pad = dynamic_cast<TPad *>(FindPrimitive(arr->at(0)));
1224 std::string kind = arr->at(1);
1225 int event = -1;
1226 if (kind == "move"s) event = kMouseMotion;
1227 int argx = std::stoi(arr->at(2));
1228 int argy = std::stoi(arr->at(3));
1229 auto selobj = FindPrimitive(arr->at(4));
1230
1231 if ((event >= 0) && pad && (pad == gPad)) {
1232 Canvas()->fEvent = event;
1233 Canvas()->fEventX = argx;
1234 Canvas()->fEventY = argy;
1235
1236 Canvas()->fSelected = selobj;
1237
1238 ProcessExecs(pad);
1239 }
1240 }
1241
1242 } else if (arg.compare(0, 8, "GETMENU:") == 0) {
1243
1244 TObject *obj = FindPrimitive(arg.substr(8));
1245 if (!obj)
1246 obj = Canvas();
1247
1248 TWebMenuItems items(arg.c_str() + 8);
1249 items.PopulateObjectMenu(obj, obj->IsA());
1250 std::string buf = "MENU:";
1251 buf.append(TBufferJSON::ToJSON(&items, 103).Data());
1252
1253 AddToSendQueue(connid, buf);
1254
1255 } else if (arg.compare(0, 8, "PRIMIT6:") == 0) {
1256
1257 if (IsFirstConn(connid) && !IsReadOnly()) { // only first connection can modify object
1258
1259 auto opt = TBufferJSON::FromJSON<TWebObjectOptions>(arg.c_str() + 8);
1260
1261 if (opt) {
1262 TPad *modpad = ProcessObjectOptions(*opt, nullptr);
1263
1264 // indicate that pad was modified
1265 if (modpad)
1266 modpad->Modified();
1267 }
1268 }
1269
1270 } else if (arg.compare(0, 11, "PADCLICKED:") == 0) {
1271
1272 auto click = TBufferJSON::FromJSON<TWebPadClick>(arg.c_str() + 11);
1273
1274 if (click && IsFirstConn(connid) && !IsReadOnly()) {
1275
1276 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(click->padid));
1277
1278 if (pad && pad->InheritsFrom(TButton::Class())) {
1279 auto btn = (TButton *) pad;
1280 const char *mthd = btn->GetMethod();
1281 if (mthd && *mthd) {
1282 TVirtualPad::TContext ctxt(gROOT->GetSelectedPad(), kTRUE, kTRUE);
1283 gROOT->ProcessLine(mthd);
1284 }
1285 return kTRUE;
1286 }
1287
1288 if (pad && (pad != gPad)) {
1289 gPad = pad;
1293 }
1294
1295 if (!click->objid.empty()) {
1296 auto selobj = FindPrimitive(click->objid);
1297 Canvas()->SetClickSelected(selobj);
1298 Canvas()->fSelected = selobj;
1299 if (pad && selobj && fObjSelectSignal)
1300 fObjSelectSignal(pad, selobj);
1301 }
1302
1303 if ((click->x >= 0) && (click->y >= 0)) {
1304 Canvas()->fEvent = click->dbl ? kButton1Double : kButton1Up;
1305 Canvas()->fEventX = click->x;
1306 Canvas()->fEventY = click->y;
1307 if (click->dbl && fPadDblClickedSignal)
1308 fPadDblClickedSignal(pad, click->x, click->y);
1309 else if (!click->dbl && fPadClickedSignal)
1310 fPadClickedSignal(pad, click->x, click->y);
1311 }
1312
1313 ProcessExecs(pad);
1314 }
1315
1316 } else if (arg.compare(0, 8, "OBJEXEC:") == 0) {
1317
1318 auto buf = arg.substr(8);
1319 auto pos = buf.find(":");
1320
1321 if ((pos > 0) && IsFirstConn(connid) && !IsReadOnly()) { // only first client can execute commands
1322 auto sid = buf.substr(0, pos);
1323 buf.erase(0, pos + 1);
1324
1325 TObjLink *lnk = nullptr;
1326 TPad *objpad = nullptr;
1327
1328 TObject *obj = FindPrimitive(sid, 1, nullptr, &lnk, &objpad);
1329 if (obj && !buf.empty()) {
1330
1331 while (!buf.empty()) {
1332 std::string sub = buf;
1333 pos = buf.find(";;");
1334 if (pos == std::string::npos) {
1335 sub = buf;
1336 buf.clear();
1337 } else {
1338 sub = buf.substr(0,pos);
1339 buf = buf.substr(pos+2);
1340 }
1341 if (sub.empty()) continue;
1342
1343 std::stringstream exec;
1344 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj << ")->" << sub << ";";
1345 Info("ProcessData", "Obj %s Execute %s", obj->GetName(), exec.str().c_str());
1346 gROOT->ProcessLine(exec.str().c_str());
1347 }
1348
1349 if (objpad)
1350 objpad->Modified();
1351 else
1352 Canvas()->Modified();
1353
1355 }
1356 }
1357
1358 } else if (arg.compare(0, 12, "EXECANDSEND:") == 0) {
1359
1360 // execute method and send data, used by drawing projections
1361
1362 std::string buf = arg.substr(12);
1363 std::string reply;
1364 TObject *obj = nullptr;
1365
1366 auto pos = buf.find(":");
1367
1368 if ((pos > 0) && IsFirstConn(connid) && !IsReadOnly()) {
1369 // only first client can execute commands
1370 reply = buf.substr(0, pos);
1371 buf.erase(0, pos + 1);
1372 pos = buf.find(":");
1373 if (pos > 0) {
1374 auto sid = buf.substr(0, pos);
1375 buf.erase(0, pos + 1);
1376 obj = FindPrimitive(sid);
1377 }
1378 }
1379
1380 if (obj && !buf.empty() && !reply.empty()) {
1381 std::stringstream exec;
1382 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase << (size_t)obj
1383 << ")->" << buf << ";";
1384 if (gDebug > 1)
1385 Info("ProcessData", "Obj %s Exec %s", obj->GetName(), exec.str().c_str());
1386
1387 auto res = gROOT->ProcessLine(exec.str().c_str());
1388 TObject *resobj = (TObject *)(res);
1389 if (resobj) {
1390 std::string send = reply;
1391 send.append(":");
1392 send.append(TBufferJSON::ToJSON(resobj, 23).Data());
1393 AddToSendQueue(connid, send);
1394 if (reply[0] == 'D')
1395 delete resobj; // delete object if first symbol in reply is D
1396 }
1397 }
1398
1399 } else if (arg.compare(0, 6, "CLEAR:") == 0) {
1400 std::string snapid = arg.substr(6);
1401
1402 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(snapid));
1403
1404 if (pad) {
1405 pad->Clear();
1406 pad->Modified();
1407 PerformUpdate();
1408 } else {
1409 printf("Not found pad with id %s\n", snapid.c_str());
1410 }
1411 } else if (arg.compare(0, 7, "DIVIDE:") == 0) {
1412 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(7));
1413 if (arr && arr->size() == 2) {
1414 TPad *pad = dynamic_cast<TPad *>(FindPrimitive(arr->at(0)));
1415 int nn = 0, n1 = 0, n2 = 0;
1416
1417 std::string divide = arr->at(1);
1418 auto p = divide.find('x');
1419 if (p == std::string::npos)
1420 p = divide.find('X');
1421
1422 if (p != std::string::npos) {
1423 n1 = std::stoi(divide.substr(0,p));
1424 n2 = std::stoi(divide.substr(p+1));
1425 } else {
1426 nn = std::stoi(divide);
1427 }
1428
1429 if (pad && ((nn > 1) || (n1*n2 > 1))) {
1430 pad->Clear();
1431 pad->Modified();
1432 if (nn > 1)
1433 pad->DivideSquare(nn);
1434 else
1435 pad->Divide(n1, n2);
1436 pad->cd(1);
1437 PerformUpdate();
1438 }
1439 }
1440
1441 } else if (arg.compare(0, 8, "DRAWOPT:") == 0) {
1442 auto arr = TBufferJSON::FromJSON<std::vector<std::string>>(arg.substr(8));
1443 if (arr && arr->size() == 2) {
1444 TObjLink *objlnk = nullptr;
1445 FindPrimitive(arr->at(0), 1, nullptr, &objlnk);
1446 if (objlnk)
1447 objlnk->SetOption(arr->at(1).c_str());
1448 }
1449
1450 } else if (arg == "INTERRUPT"s) {
1451 gROOT->SetInterrupt();
1452 } else {
1453 // unknown message, probably should be processed by other implementation
1454 return kFALSE;
1455 }
1456
1457 return kTRUE;
1458}
1459
1460//////////////////////////////////////////////////////////////////////////////////////////
1461/// Returns true if any pad in the canvas were modified
1462/// Reset modified flags, increment canvas version (if inc_version is true)
1463
1465{
1466 if (fPadsStatus.find(pad) == fPadsStatus.end())
1467 fPadsStatus[pad] = PadStatus{0, true, true};
1468
1469 auto &entry = fPadsStatus[pad];
1470 entry._detected = true;
1471 if (pad->IsModified()) {
1472 pad->Modified(kFALSE);
1473 entry._modified = true;
1474 }
1475
1476 TIter iter(pad->GetListOfPrimitives());
1477 while (auto obj = iter()) {
1478 if (obj->InheritsFrom(TPad::Class()))
1479 CheckPadModified(static_cast<TPad *>(obj));
1480 }
1481}
1482
1483//////////////////////////////////////////////////////////////////////////////////////////
1484/// Check if any pad on the canvas was modified
1485/// If yes, increment version of correspondent pad
1486
1487void TWebCanvas::CheckCanvasModified(bool force_modified)
1488{
1489 // clear temporary flags
1490 for (auto &entry : fPadsStatus) {
1491 entry.second._detected = false;
1492 entry.second._modified = force_modified;
1493 }
1494
1495 // scan sub-pads
1497
1498 // remove no-longer existing pads
1499 bool is_any_modified = false;
1500 for(auto iter = fPadsStatus.begin(); iter != fPadsStatus.end(); ) {
1501 if (iter->second._modified)
1502 is_any_modified = true;
1503 if (!iter->second._detected)
1504 fPadsStatus.erase(iter++);
1505 else
1506 iter++;
1507 }
1508
1509 // if any pad modified, increment canvas version and set version of modified pads
1510 if (is_any_modified) {
1511 fCanvVersion++;
1512 for(auto &entry : fPadsStatus)
1513 if (entry.second._modified)
1514 entry.second.fVersion = fCanvVersion;
1515 }
1516}
1517
1518
1519//////////////////////////////////////////////////////////////////////////////////////////
1520/// Returns window geometry including borders and menus
1521
1523{
1524 x = 0;
1525 y = 0;
1526 w = Canvas()->GetWw() + 4;
1527 h = Canvas()->GetWh() + 28;
1528 return 0;
1529}
1530
1531
1532//////////////////////////////////////////////////////////////////////////////////////////
1533/// if canvas or any subpad was modified,
1534/// scan all primitives in the TCanvas and subpads and convert them into
1535/// the structure which will be delivered to JSROOT client
1536
1538{
1539 if (!fWindow)
1540 return kTRUE;
1541
1543
1545
1546 if (!fProcessingData && !IsAsyncMode())
1548
1549 return kTRUE;
1550}
1551
1552//////////////////////////////////////////////////////////////////////////////////////////
1553/// Increment canvas version and force sending data to client - do not wait for reply
1554
1556{
1557 if (!fWindow)
1558 return;
1559
1560 CheckCanvasModified(true);
1561
1563}
1564
1565//////////////////////////////////////////////////////////////////////////////////////////
1566/// Wait when specified version of canvas was painted and confirmed by browser
1567
1569{
1570 if (!fWindow)
1571 return kTRUE;
1572
1573 // simple polling loop until specified version delivered to the clients
1574 // first 500 loops done without sleep, then with 1ms sleep and last 500 with 100 ms sleep
1575
1576 long cnt = 0, cnt_limit = GetLongerPolling() ? 5500 : 1500;
1577
1578 if (gDebug > 2)
1579 Info("WaitWhenCanvasPainted", "version %ld", (long)ver);
1580
1581 while (cnt++ < cnt_limit) {
1582
1583 if (!fWindow->HasConnection(0, false)) {
1584 if (gDebug > 2)
1585 Info("WaitWhenCanvasPainted", "no connections - abort");
1586 return kFALSE; // wait ~1 min if no new connection established
1587 }
1588
1589 if ((fWebConn.size() > 0) && (fWebConn.front().fDrawVersion >= ver)) {
1590 if (gDebug > 2)
1591 Info("WaitWhenCanvasPainted", "ver %ld got painted", (long)ver);
1592 return kTRUE;
1593 }
1594
1596 if (cnt > 500)
1597 gSystem->Sleep((cnt < cnt_limit - 500) ? 1 : 100); // increase sleep interval when do very often
1598 }
1599
1600 if (gDebug > 2)
1601 Info("WaitWhenCanvasPainted", "timeout");
1602
1603 return kFALSE;
1604}
1605
1607{
1608 TString res;
1609 if (!pad)
1610 return res;
1611
1612 TCanvas *c = dynamic_cast<TCanvas *>(pad);
1613 if (c) {
1614 res = CreateCanvasJSON(c, json_compression);
1615 } else {
1616 auto imp = std::make_unique<TWebCanvas>(pad->GetCanvas(), pad->GetName(), 0, 0, 1000, 500);
1617
1618 TPadWebSnapshot holder(true, false); // readonly, no ids
1619
1620 imp->CreatePadSnapshot(holder, pad, 0, [&res, json_compression](TPadWebSnapshot *snap) {
1621 res = TBufferJSON::ToJSON(snap, json_compression);
1622 });
1623 }
1624
1625 return res;
1626}
1627
1628//////////////////////////////////////////////////////////////////////////////////////////
1629/// Create JSON painting output for given canvas
1630/// Produce JSON can be used for offline drawing with JSROOT
1631
1633{
1634 TString res;
1635
1636 if (!c)
1637 return res;
1638
1639 {
1640 auto imp = std::make_unique<TWebCanvas>(c, c->GetName(), 0, 0, 1000, 500);
1641
1642 TCanvasWebSnapshot holder(true, false); // readonly, no ids
1643
1644 imp->CreatePadSnapshot(holder, c, 0, [&res, json_compression](TPadWebSnapshot *snap) {
1645 res = TBufferJSON::ToJSON(snap, json_compression);
1646 });
1647 }
1648
1649 return res;
1650}
1651
1652//////////////////////////////////////////////////////////////////////////////////////////
1653/// Create JSON painting output for given canvas and store into the file
1654/// See TBufferJSON::ExportToFile() method for more details
1655
1657{
1658 Int_t res = 0;
1659
1660 if (!c)
1661 return res;
1662
1663 {
1664 auto imp = std::make_unique<TWebCanvas>(c, c->GetName(), 0, 0, 1000, 500);
1665
1666 TCanvasWebSnapshot holder(true, false); // readonly, no ids
1667
1668 imp->CreatePadSnapshot(holder, c, 0, [&res, filename, option](TPadWebSnapshot *snap) {
1670 });
1671 }
1672
1673 return res;
1674}
1675
1676//////////////////////////////////////////////////////////////////////////////////////////
1677/// Create image using batch (headless) capability of Chrome or Firefox browsers
1678/// Supported png, jpeg, svg, pdf formats
1679
1680bool TWebCanvas::ProduceImage(TPad *pad, const char *fileName, Int_t width, Int_t height)
1681{
1682 if (!pad)
1683 return false;
1684
1686 if (!json.Length())
1687 return false;
1688
1689 return ROOT::Experimental::RWebDisplayHandle::ProduceImage(fileName, json.Data(), width ? width : pad->GetWw(), height ? height : pad->GetWh());
1690}
1691
1692//////////////////////////////////////////////////////////////////////////////////////////
1693/// Process data for single primitive
1694/// Returns object pad if object was modified
1695
1697{
1698 TObjLink *lnk = nullptr;
1699 TPad *objpad = nullptr;
1700 TObject *obj = FindPrimitive(item.snapid, idcnt, pad, &lnk, &objpad);
1701
1702 if (item.fcust.compare("exec") == 0) {
1703 auto pos = item.opt.find("(");
1704 if (obj && (pos != std::string::npos) && obj->IsA()->GetMethodAllAny(item.opt.substr(0,pos).c_str())) {
1705 std::stringstream exec;
1706 exec << "((" << obj->ClassName() << " *) " << std::hex << std::showbase
1707 << (size_t)obj << ")->" << item.opt << ";";
1708 Info("ProcessObjectOptions", "Obj %s Execute %s", obj->GetName(), exec.str().c_str());
1709 gROOT->ProcessLine(exec.str().c_str());
1710 } else {
1711 Error("ProcessObjectOptions", "Fail to execute %s for object %p %s", item.opt.c_str(), obj, obj ? obj->ClassName() : "---");
1712 objpad = nullptr;
1713 }
1714 return objpad;
1715 }
1716
1717 bool modified = false;
1718
1719 if (obj && lnk) {
1720 auto pos = item.opt.find(";;use_"); // special coding of extra options
1721 if (pos != std::string::npos) item.opt.resize(pos);
1722
1723 if (gDebug > 1)
1724 Info("ProcessObjectOptions", "Set draw option %s for object %s %s", item.opt.c_str(),
1725 obj->ClassName(), obj->GetName());
1726
1727 lnk->SetOption(item.opt.c_str());
1728
1729 modified = true;
1730 }
1731
1732 if (item.fcust.compare("frame") == 0) {
1733 if (obj && obj->InheritsFrom(TFrame::Class())) {
1734 TFrame *frame = static_cast<TFrame *>(obj);
1735 if (item.fopt.size() >= 4) {
1736 frame->SetX1(item.fopt[0]);
1737 frame->SetY1(item.fopt[1]);
1738 frame->SetX2(item.fopt[2]);
1739 frame->SetY2(item.fopt[3]);
1740 modified = true;
1741 }
1742 }
1743 } else if (item.fcust.compare("pave") == 0) {
1744 if (obj && obj->InheritsFrom(TPave::Class())) {
1745 TPave *pave = static_cast<TPave *>(obj);
1746 if ((item.fopt.size() >= 4) && objpad) {
1747 TVirtualPad::TContext ctxt(objpad, kFALSE);
1748
1749 // first time need to overcome init problem
1750 pave->ConvertNDCtoPad();
1751
1752 pave->SetX1NDC(item.fopt[0]);
1753 pave->SetY1NDC(item.fopt[1]);
1754 pave->SetX2NDC(item.fopt[2]);
1755 pave->SetY2NDC(item.fopt[3]);
1756 modified = true;
1757
1758 pave->ConvertNDCtoPad();
1759 }
1760 }
1761 }
1762
1763 return modified ? objpad : nullptr;
1764}
1765
1766//////////////////////////////////////////////////////////////////////////////////////////////////
1767/// Search of object with given id in list of primitives
1768/// One could specify pad where search could be start
1769/// Also if object is in list of primitives, one could ask for entry link for such object,
1770/// This can allow to change draw option
1771
1772TObject *TWebCanvas::FindPrimitive(const std::string &sid, int idcnt, TPad *pad, TObjLink **objlnk, TPad **objpad)
1773{
1774 if (sid.empty() || (sid == "0"s))
1775 return nullptr;
1776
1777 if (!pad)
1778 pad = Canvas();
1779
1780 std::string kind;
1781 auto separ = sid.find("#");
1782 long unsigned id = 0;
1783 bool search_hist = false;
1784
1785 if (sid == "histogram") {
1786 search_hist = true;
1787 } else if (separ == std::string::npos) {
1788 id = std::stoul(sid);
1789 } else {
1790 kind = sid.substr(separ + 1);
1791 id = std::stoul(sid.substr(0, separ));
1792 }
1793
1794 if (!search_hist && TString::Hash(&pad, sizeof(pad)) == id)
1795 return pad;
1796
1797 auto getHistogram = [](TObject *obj) -> TH1* {
1798 auto offset = obj->IsA()->GetDataMemberOffset("fHistogram");
1799 if (offset > 0)
1800 return *((TH1 **)((char*) obj + offset));
1801 ::Error("getHistogram", "Cannot access fHistogram data member in %s", obj->ClassName());
1802 return nullptr;
1803 };
1804
1805 for (auto lnk = pad->GetListOfPrimitives()->FirstLink(); lnk != nullptr; lnk = lnk->Next()) {
1806 TObject *obj = lnk->GetObject();
1807 if (!obj) continue;
1808
1809 TString opt = lnk->GetOption();
1810 opt.ToUpper();
1811
1812 TH1 *h1 = obj->InheritsFrom(TH1::Class()) ? static_cast<TH1 *>(obj) : nullptr;
1813 TGraph *gr = obj->InheritsFrom(TGraph::Class()) ? static_cast<TGraph *>(obj) : nullptr;
1814 TMultiGraph *mg = obj->InheritsFrom(TMultiGraph::Class()) ? static_cast<TMultiGraph *>(obj) : nullptr;
1815 THStack *hs = obj->InheritsFrom(THStack::Class()) ? static_cast<THStack *>(obj) : nullptr;
1816
1817 if (search_hist) {
1818 if (objlnk)
1819 *objlnk = lnk;
1820
1821 if (h1)
1822 return h1;
1823 if (gr)
1824 return getHistogram(gr);
1825 if (mg && opt.Contains("A"))
1826 return getHistogram(mg);
1827 if (hs)
1828 return getHistogram(hs);
1829
1830 if (objlnk)
1831 *objlnk = nullptr;
1832
1833 continue;
1834 }
1835
1836 if ((TString::Hash(&obj, sizeof(obj)) == id) && (--idcnt <= 0)) {
1837 if (objpad)
1838 *objpad = pad;
1839
1840 if (kind.find("hist") == 0) {
1841 if (gr)
1842 obj = h1 = getHistogram(gr);
1843 else if (mg)
1844 obj = h1 = getHistogram(mg);
1845 else if (hs)
1846 obj = h1 = getHistogram(hs);
1847
1848 kind.erase(0,4);
1849 if (!kind.empty() && (kind[0]=='#')) kind.erase(0,1);
1850 objlnk = nullptr;
1851 }
1852
1853 if (h1 && (kind == "x"))
1854 return h1->GetXaxis();
1855 if (h1 && (kind == "y"))
1856 return h1->GetYaxis();
1857 if (h1 && (kind == "z"))
1858 return h1->GetZaxis();
1859
1860 if ((h1 || gr) && !kind.empty() && (kind.compare(0,5,"func_") == 0)) {
1861 auto funcname = kind.substr(5);
1863 return col ? col->FindObject(funcname.c_str()) : nullptr;
1864 }
1865
1866 if (!kind.empty() && (kind.compare(0,7,"member_") == 0)) {
1867 auto member = kind.substr(7);
1868 auto offset = obj->IsA() ? obj->IsA()->GetDataMemberOffset(member.c_str()) : 0;
1869 if (offset > 0) {
1870 TObject **mobj = (TObject **)((char*) obj + offset);
1871 return *mobj;
1872 }
1873 return nullptr;
1874 }
1875
1876 if (objlnk)
1877 *objlnk = lnk;
1878 return obj;
1879 }
1880
1881 if (h1 || gr) {
1883 TObject *fobj = nullptr;
1884 while ((fobj = fiter()) != nullptr)
1885 if (TString::Hash(&fobj, sizeof(fobj)) == id) {
1886 if (objpad)
1887 *objpad = pad;
1888 return fobj;
1889 }
1890 } else if (obj->InheritsFrom(TPad::Class())) {
1891 obj = FindPrimitive(sid, idcnt, (TPad *)obj, objlnk, objpad);
1892 if (objpad && !*objpad)
1893 *objpad = pad;
1894 if (obj)
1895 return obj;
1896 }
1897 }
1898
1899 return nullptr;
1900}
1901
1902//////////////////////////////////////////////////////////////////////////////////////////////////
1903/// Static method to create TWebCanvas instance
1904/// Used by plugin manager
1905
1907{
1908 Bool_t readonly = gEnv->GetValue("WebGui.FullCanvas", (Int_t) 1) == 0;
1909
1910 return new TWebCanvas(c, name, x, y, width, height, readonly);
1911}
1912
@ 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
constexpr Bool_t kFALSE
Definition RtypesCore.h:101
constexpr Ssiz_t kNPOS
Definition RtypesCore.h:124
long long Long64_t
Definition RtypesCore.h:80
constexpr Bool_t kTRUE
Definition RtypesCore.h:100
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:230
void Error(const char *location, const char *msgfmt,...)
Use this function in case an error occurred.
Definition TError.cxx:197
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 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 id
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:369
@ kMustCleanup
Definition TObject.h:370
Int_t gDebug
Definition TROOT.cxx:585
#define gROOT
Definition TROOT.h:405
R__EXTERN TStyle * gStyle
Definition TStyle.h:414
R__EXTERN TSystem * gSystem
Definition TSystem.h:560
R__EXTERN TVirtualPS * gVirtualPS
Definition TVirtualPS.h:81
#define gPad
#define gVirtualX
Definition TVirtualX.h:338
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, const char *batch_file=nullptr)
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
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
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:978
virtual void SetRange(Int_t first=0, Int_t last=0)
Set the viewing range for the axis using bin numbers.
Definition TAxis.cxx:952
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: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
@ 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 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
void SetClickSelectedPad(TPad *pad)
Definition TCanvas.h:208
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:2571
Int_t fEventY
! Last Y mouse position in canvas
Definition TCanvas.h:47
TObject * fSelected
! Currently selected object
Definition TCanvas.h:49
UInt_t fCh
Height of the canvas along Y (pixels)
Definition TCanvas.h:44
void SetClickSelected(TObject *obj)
Definition TCanvas.h:206
UInt_t GetWw() const override
Definition TCanvas.h:162
UInt_t GetWh() const override
Definition TCanvas.h:163
virtual void Highlighted(TVirtualPad *pad, TObject *obj, Int_t x, Int_t y)
Emit Highlighted() signal.
Definition TCanvas.cxx:1600
Int_t fEvent
! Type of current or last handled event
Definition TCanvas.h:45
@ kShowToolTips
Definition TCanvas.h:96
@ kShowEventStatus
Definition TCanvas.h:88
@ kMenuBar
Definition TCanvas.h:90
@ kShowEditor
Definition TCanvas.h:92
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
Collection abstract base class.
Definition TCollection.h:65
TObject * FindObject(const char *name) const override
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:1462
static TClass * Class()
static Bool_t DefinedColors()
Static function returning kTRUE if some new colors have been defined after initialisation or since th...
Definition TColor.cxx:1480
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()
Define a Frame.
Definition TFrame.h:19
static TClass * Class()
A TGraph is an object made of two arrays X and Y with npoints each.
Definition TGraph.h:41
static TClass * Class()
TList * GetListOfFunctions() const
Definition TGraph.h:123
TH1F * GetHistogram() const
Returns a pointer to the histogram used to draw the axis Takes into account the two following cases.
Definition TGraph.cxx:1401
TH1 is the base class of all histogram classes in ROOT.
Definition TH1.h:58
TAxis * GetZaxis()
Definition TH1.h:324
static TClass * Class()
virtual Int_t GetDimension() const
Definition TH1.h:281
@ kNoTitle
Don't draw the histogram title.
Definition TH1.h:168
TAxis * GetXaxis()
Definition TH1.h:322
virtual void SetMaximum(Double_t maximum=-1111)
Definition TH1.h:400
TAxis * GetYaxis()
Definition TH1.h:323
virtual void SetMinimum(Double_t minimum=-1111)
Definition TH1.h:401
virtual Double_t GetEntries() const
Return the current number of entries.
Definition TH1.cxx:4419
TList * GetListOfFunctions() const
Definition TH1.h:242
virtual Int_t BufferEmpty(Int_t action=0)
Fill histogram with all entries in the buffer.
Definition TH1.cxx:1387
The Histogram stack class.
Definition THStack.h:38
static TClass * Class()
Option_t * GetOption() const
void Reset()
A doubly linked list.
Definition TList.h:38
void Clear(Option_t *option="") override
Remove all objects from the list.
Definition TList.cxx:402
void Add(TObject *obj) override
Definition TList.h:81
virtual TObjLink * FirstLink() const
Definition TList.h:102
void AddFirst(TObject *obj) override
Add object at the beginning of the list.
Definition TList.cxx:100
A TMultiGraph is a collection of TGraph (or derived) objects.
Definition TMultiGraph.h:34
static TClass * Class()
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
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:439
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:207
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:774
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:525
virtual const char * GetTitle() const
Returns title of object.
Definition TObject.cxx:483
virtual TClass * IsA() const
Definition TObject.h:245
virtual void Paint(Option_t *option="")
This method must be overridden if a class wants to paint itself.
Definition TObject.cxx:601
TPadWebSnapshot & NewSubPad()
Create new entry for subpad.
TWebSnapshot & NewSpecials()
Create new entry in list of primitives in the front.
void SetWithoutPrimitives(bool on=true)
void SetActive(bool on=true)
TWebSnapshot & NewPrimitive(TObject *obj=nullptr, const std::string &opt="")
Create new entry in list of primitives.
bool IsSetObjectIds() const
The most important graphics class in the ROOT system.
Definition TPad.h:28
Int_t GetTicky() const override
Definition TPad.h:237
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:1245
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:6029
TVirtualViewer3D * GetViewer3D(Option_t *type="") override
Create/obtain handle to 3D viewer.
Definition TPad.cxx:6981
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:330
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:244
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:1153
Double_t fXtoPixel
xpixel = fXtoPixelk + fXtoPixel*xworld
Definition TPad.h:43
Bool_t GetGridx() const override
Definition TPad.h:233
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
UInt_t GetWw() const override
Get Ww.
Definition TPad.cxx:2732
Double_t fX1
X of lower X coordinate.
Definition TPad.h:36
TList * GetListOfPrimitives() const override
Definition TPad.h:243
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:272
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:626
Int_t GetTickx() const override
Definition TPad.h:236
Double_t fUymax
Maximum value on the Y axis.
Definition TPad.h:77
void Modified(Bool_t flag=1) override
Definition TPad.h:417
TVirtualPad * GetMother() const override
Definition TPad.h:257
TView * GetView() const override
Definition TPad.h:252
Bool_t GetGridy() const override
Definition TPad.h:234
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:5865
Int_t fLogx
(=0 if X linear scale, =1 if log scale)
Definition TPad.h:91
UInt_t GetWh() const override
Get Wh.
Definition TPad.cxx:2724
TCanvas * GetCanvas() const override
Definition TPad.h:260
Double_t fXUpNDC
Definition TPad.h:64
TVirtualPad * cd(Int_t subpadnumber=0) override
Set Current pad.
Definition TPad.cxx:597
void Print(const char *filename="") const override
This method is equivalent to SaveAs("filename"). See TPad::SaveAs for details.
Definition TPad.cxx:4660
TFrame * GetFrame() override
Get frame.
Definition TPad.cxx:2831
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
void SetTicks(Int_t valuex=1, Int_t valuey=1) override
Definition TPad.h:350
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:258
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()
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
static TClass * Class()
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:139
Ssiz_t Length() const
Definition TString.h:421
const char * Data() const
Definition TString.h:380
@ kIgnoreCase
Definition TString.h:279
void ToUpper()
Change string to upper case.
Definition TString.cxx:1183
UInt_t Hash(ECaseCompare cmp=kExact) const
Return hash value.
Definition TString.cxx:670
TString & Append(const char *cs)
Definition TString.h:576
Bool_t Contains(const char *pat, ECaseCompare cmp=kExact) const
Definition TString.h:636
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:237
Color_t GetStatTextColor() const
Definition TStyle.h:250
Int_t GetOptTitle() const
Definition TStyle.h:238
Float_t GetStatFontSize() const
Definition TStyle.h:253
Float_t GetStatX() const
Definition TStyle.h:256
Style_t GetTitleFont(Option_t *axis="X") const
Return title font.
Definition TStyle.cxx:1165
Float_t GetStatY() const
Definition TStyle.h:257
Color_t GetTitleFillColor() const
Definition TStyle.h:263
Style_t GetTitleStyle() const
Definition TStyle.h:265
Color_t GetStatColor() const
Definition TStyle.h:249
Float_t GetStatH() const
Definition TStyle.h:259
static TClass * Class()
Width_t GetTitleBorderSize() const
Definition TStyle.h:267
Width_t GetStatBorderSize() const
Definition TStyle.h:251
Color_t GetTitleTextColor() const
Definition TStyle.h:264
Style_t GetStatStyle() const
Definition TStyle.h:254
Float_t GetStatW() const
Definition TStyle.h:258
const char * GetFitFormat() const
Definition TStyle.h:192
const char * GetStatFormat() const
Definition TStyle.h:255
Style_t GetStatFont() const
Definition TStyle.h:252
Float_t GetTitleFontSize() const
Definition TStyle.h:266
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
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
Basic TCanvasImp ABI implementation for Web-based GUI Provides painting of main ROOT6 classes in web ...
Definition TWebCanvas.h:34
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.
void AddCustomClass(const std::string &clname, bool with_derived=false)
Assign custom class.
UInt_t fColorsHash
! last hash of colors/palette
Definition TWebCanvas.h:99
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:98
std::string fCustomScripts
! custom JavaScript code or URL on JavaScript files to load before start drawing
Definition TWebCanvas.h:90
virtual Bool_t IsReadOnly() const
Definition TWebCanvas.h:159
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 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:105
PadClickedSignal_t fPadClickedSignal
! signal emitted when simple mouse click performed on the pad
Definition TWebCanvas.h:103
void SetLongerPolling(Bool_t on)
Definition TWebCanvas.h:215
UInt_t fStyleHash
! last hash of gStyle
Definition TWebCanvas.h:97
virtual Bool_t CanCreateObject(const std::string &)
Definition TWebCanvas.h:143
Int_t fPrimitivesMerge
! number of PS primitives, which will be merged together
Definition TWebCanvas.h:88
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:91
static TString CreatePadJSON(TPad *pad, Int_t json_compression=0)
Bool_t IsAsyncMode() const
Definition TWebCanvas.h:224
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...
UInt_t CalculateColorsHash()
Calculate hash function for all colors and palette.
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 CheckPadModified(TPad *pad)
Returns true if any pad in the canvas were modified Reset modified flags, increment canvas version (i...
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:76
PadSignal_t fActivePadChangedSignal
! signal emitted when active pad changed in the canvas
Definition TWebCanvas.h:102
Bool_t GetLongerPolling() const
Definition TWebCanvas.h:216
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:84
std::function< void(TPadWebSnapshot *)> PadPaintingReady_t
Function called when pad painting produced.
Definition TWebCanvas.h:52
Int_t fPaletteDelivery
! colors palette delivery 0:never, 1:once, 2:always, 3:per subpad
Definition TWebCanvas.h:87
Bool_t fProcessingData
! flag used to prevent blocking methods when process data is invoked
Definition TWebCanvas.h:94
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:83
bool IsCustomClass(const TClass *cl) const
Checks if class belongs to custom.
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.
void AddColorsPalette(TPadWebSnapshot &master)
Add special canvas objects like colors list at selected palette.
void CheckCanvasModified(bool force_modified=false)
Check if any pad on the canvas was modified If yes, increment version of correspondent pad.
Long64_t fStyleVersion
! current gStyle object version, checked every time when new snapshot created
Definition TWebCanvas.h:96
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:101
Int_t fJsonComp
! compression factor for messages send to the client
Definition TWebCanvas.h:89
Bool_t IsFirstConn(unsigned connid) const
Definition TWebCanvas.h:133
Bool_t fReadOnly
!< configured display
Definition TWebCanvas.h:82
std::map< TPad *, PadStatus > fPadsStatus
! map of pads in canvas and their status flags
Definition TWebCanvas.h:78
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.
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:80
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.
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:86
PadClickedSignal_t fPadDblClickedSignal
! signal emitted when simple mouse click performed on the pad
Definition TWebCanvas.h:104
void ProcessExecs(TPad *pad, TExec *extra=nullptr)
Process TExec objects in the pad.
TList fPrimitivesLists
! list of lists of primitives, temporary collected during painting
Definition TWebCanvas.h:85
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 ...
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:210
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...
Int_t GetStyleDelivery() const
Definition TWebCanvas.h:207
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.
@ kStyle
gStyle object
@ kObject
object itself
@ kSVG
list of SVG primitives
@ kSubPad
subpad
@ kColors
list of ROOT colors + palette
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
LongDouble_t Power(LongDouble_t x, LongDouble_t y)
Returns x raised to the power y.
Definition TMath.h:719
bool _detected
! if pad was detected during last scan
Definition TWebCanvas.h:71