diff --git a/core/base/v7/inc/ROOT/TDrawable.hxx b/core/base/v7/inc/ROOT/TDrawable.hxx
index 9e64f532748e4132a49649f5222cf9719d3582de..7a3a69192edd72a1278c526b2dc0cba8cfbdb390 100644
--- a/core/base/v7/inc/ROOT/TDrawable.hxx
+++ b/core/base/v7/inc/ROOT/TDrawable.hxx
@@ -19,6 +19,9 @@
 
 namespace ROOT {
 namespace Experimental {
+
+class TCanvas;
+
 namespace Internal {
 
 class TVirtualCanvasPainter;
@@ -31,7 +34,6 @@ class TDrawable {
 public:
   virtual ~TDrawable();
 
-  /// Paint the object
   virtual void Paint(TVirtualCanvasPainter& onCanv) = 0;
 };
 
diff --git a/graf2d/gpad/CMakeLists.txt b/graf2d/gpad/CMakeLists.txt
index 3b830c0a05991a05feedfd8d158bbc142eeecc68..84a14c5ff0bbc068754ab15a5dfe6aba5a2eed0c 100644
--- a/graf2d/gpad/CMakeLists.txt
+++ b/graf2d/gpad/CMakeLists.txt
@@ -3,11 +3,12 @@
 # @author Pere Mato, CERN
 ############################################################################
 
-ROOT_GENERATE_DICTIONARY(G__Gpad *.h MODULE Gpad LINKDEF LinkDef.h OPTIONS "-writeEmptyRootPCM")
-
 if(root7)
     set(root7src v7/src/)
+    ROOT_GLOB_HEADERS(Gpad_v7_dict_headers ${CMAKE_CURRENT_SOURCE_DIR}/v7/inc/ROOT/T*.hxx)
 endif()
 
+ROOT_GENERATE_DICTIONARY(G__Gpad *.h ${Gpad_v7_dict_headers} MODULE Gpad LINKDEF LinkDef.h OPTIONS "-writeEmptyRootPCM")
+
 ROOT_LINKER_LIBRARY(Gpad *.cxx ${root7src} G__Gpad.cxx DEPENDENCIES Graf Hist)
 ROOT_INSTALL_HEADERS()
diff --git a/graf2d/gpad/inc/LinkDef.h b/graf2d/gpad/inc/LinkDef.h
index eb6d25849948d38977d1a0dfe7ca74915d839e8d..fc13cde13c36bd34238b618247f264e3e258c679 100644
--- a/graf2d/gpad/inc/LinkDef.h
+++ b/graf2d/gpad/inc/LinkDef.h
@@ -33,4 +33,12 @@
 #pragma link C++ class TPadPainter;
 #pragma link C++ class TRatioPlot+;
 
+#ifdef ROOT7_TDisplayItem
+#pragma link C++ class ROOT::Experimental::TDisplayItem+;
+#pragma link C++ class std::vector<ROOT::Experimental::TDisplayItem*>+;
+#pragma link C++ class ROOT::Experimental::TPadDisplayItem+;
+#pragma link C++ class ROOT::Experimental::TUniqueDisplayItem<TPad>+;
+#pragma link C++ class ROOT::Experimental::TOrdinaryDisplayItem<TH1>+;
+#endif
+
 #endif
diff --git a/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx b/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx
index cf9cd07404c63590130c2ec70e1636ae222723b4..70aaad9dfc2356ea6909ecc6fea7cd75ce29eec2 100644
--- a/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx
+++ b/graf2d/gpad/v7/inc/ROOT/TCanvas.hxx
@@ -26,6 +26,10 @@
 namespace ROOT {
 namespace Experimental {
 
+namespace Internal {
+class TCanvasSharedPtrMaker;
+}
+
 /** \class ROOT::Experimental::TCanvas
   Graphic container for `TDrawable`-s.
   Access is through TCanvasPtr.
@@ -35,13 +39,16 @@ class TCanvas {
 public:
   using Primitives_t = std::vector<std::unique_ptr<Internal::TDrawable>>;
 
-private:
+ private:
   /// Content of the pad.
   Primitives_t fPrimitives;
 
   /// Title of the canvas.
   std::string fTitle;
 
+  /// If canvas modified.
+  bool fModified;
+
   /// The painter of this canvas, bootstrapping the graphics connection.
   /// Unmapped canvases (those that never had `Draw()` invoked) might not have
   /// a painter.
@@ -110,12 +117,17 @@ public:
   /// Remove an object from the list of primitives.
   //TODO: void Wipe();
 
+   void Modified() { fModified = true; }
+
   /// Actually display the canvas.
   void Show() {
     fPainter = Internal::TVirtualCanvasPainter::Create(*this);
   }
 
-  /// Get the canvas's title.
+  /// update drawing
+  void Update();
+
+   /// Get the canvas's title.
   const std::string& GetTitle() const { return fTitle; }
 
   /// Set the canvas's title.
diff --git a/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx b/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx
index d1329b6f15f936abbf362f2ae71aae444e2691d7..48d03f95bf3bc3b0fcf754b38c77e57552435d2d 100644
--- a/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx
+++ b/graf2d/gpad/v7/inc/ROOT/TVirtualCanvasPainter.hxx
@@ -17,6 +17,8 @@
 
 #include <memory>
 
+#include "ROOT/TDisplayItem.hxx"
+
 namespace ROOT {
 namespace Experimental {
 class TCanvas;
@@ -42,6 +44,8 @@ protected:
 public:
   /// Default destructor.
   virtual ~TVirtualCanvasPainter();
+  
+  virtual void AddDisplayItem(TDisplayItem *item) = 0;
 
   /// Loads the plugin that implements this class.
   static std::unique_ptr<TVirtualCanvasPainter> Create(const TCanvas& canv);
diff --git a/graf2d/gpad/v7/src/TCanvas.cxx b/graf2d/gpad/v7/src/TCanvas.cxx
index 8158af9e96b2532e34ca4038a5e526d8580eaf50..4a371eb0ae080881e9ff93377a538528426d1c9a 100644
--- a/graf2d/gpad/v7/src/TCanvas.cxx
+++ b/graf2d/gpad/v7/src/TCanvas.cxx
@@ -15,7 +15,13 @@
 
 #include "ROOT/TCanvas.hxx"
 
+#include "ROOT/TDrawable.hxx"
+#include "ROOT/TLogger.hxx"
+
 #include <memory>
+#include <stdio.h>
+#include <string.h>
+
 
 namespace {
 static
@@ -25,12 +31,29 @@ std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>>& GetHeldCanvases() {
 }
 }
 
-
 const std::vector<std::shared_ptr<ROOT::Experimental::TCanvas>> &
 ROOT::Experimental::TCanvas::GetCanvases() {
   return GetHeldCanvases();
 }
 
+
+//void ROOT::Experimental::TCanvas::Paint() {
+//  for (auto&& drw: fPrimitives) {
+//    drw->Paint(*this);
+//  }
+// }
+
+
+void ROOT::Experimental::TCanvas::Update() {
+  // SnapshotList_t lst;
+  // for (auto&& drw: fPrimitives) {
+  //   TSnapshot *snap = drw->CreateSnapshot(*this);
+  //   lst.push_back(std::unique_ptr<TSnapshot>(snap));
+  // }
+}
+
+
+
 std::shared_ptr<ROOT::Experimental::TCanvas>
 ROOT::Experimental::TCanvas::Create(const std::string& title) {
   auto pCanvas = std::make_shared<TCanvas>();
diff --git a/gui/canvaspainter/CMakeLists.txt b/gui/canvaspainter/CMakeLists.txt
index cdece3d85c1e112b3da733592151ffd61dfb1798..fee6f5d4f0c2e34e7049039cf97387530a570f79 100644
--- a/gui/canvaspainter/CMakeLists.txt
+++ b/gui/canvaspainter/CMakeLists.txt
@@ -4,4 +4,4 @@
 
 set(libname ROOTCanvasPainter)
 
-ROOT_LINKER_LIBRARY(${libname} *.cxx v7/src/ DEPENDENCIES Gpad)
+ROOT_LINKER_LIBRARY(${libname} *.cxx v7/src/ DEPENDENCIES Gpad RHTTP)
diff --git a/gui/canvaspainter/v7/src/TCanvasPainter.cxx b/gui/canvaspainter/v7/src/TCanvasPainter.cxx
index b082df213c3681d35c40f45faab2b9c0e022bb06..f6ebc6e457ae1c1d99d97c066192d95bd9247c2d 100644
--- a/gui/canvaspainter/v7/src/TCanvasPainter.cxx
+++ b/gui/canvaspainter/v7/src/TCanvasPainter.cxx
@@ -16,10 +16,21 @@
 #include "ROOT/TVirtualCanvasPainter.hxx"
 #include "ROOT/TCanvas.hxx"
 #include <ROOT/TLogger.hxx>
+#include <ROOT/TDisplayItem.hxx>
 
 #include <memory>
 #include <string>
 #include <vector>
+#include <list>
+
+#include "THttpEngine.h"
+#include "THttpServer.h"
+#include "TSystem.h"
+#include "TList.h"
+#include "TRandom.h"
+#include "TPad.h"
+#include "TROOT.h"
+#include "TBufferJSON.h"
 
 namespace {
 
@@ -27,23 +38,68 @@ namespace {
   Handles TCanvas communication with THttpServer.
   */
 
-class TCanvasPainter: public ROOT::Experimental::Internal::TVirtualCanvasPainter /*, THttpSocketListener*/ {
+class TCanvasPainter: public THttpWSHandler,
+                      public ROOT::Experimental::Internal::TVirtualCanvasPainter /*, THttpSocketListener*/ {
 private:
+
+   struct WebConn {
+      THttpWSEngine  *fHandle;     ///<! websocket handle
+      Bool_t          fReady;
+      UInt_t          fGetMenu;    ///<! object id for menu request
+      Bool_t          fModified;
+      WebConn() : fHandle(0), fReady(kFALSE), fGetMenu(0), fModified(kFALSE) {}
+   };
+
+  typedef std::list<WebConn> WebConnList;
+   
   /// The canvas we are painting. It might go out of existence while painting.
   const ROOT::Experimental::TCanvas& fCanvas;
+  
+   WebConnList     fWebConn;      ///<! connections list
+   ROOT::Experimental::TPadDisplayItem  fDisplayList; ///!< full list of items to display
+
+   static std::string fAddr;
+   static THttpServer *gServer;
+
+
+
   /// Disable copy construction.
   TCanvasPainter(const TCanvasPainter&) = delete;
 
+
   /// Disable assignment.
   TCanvasPainter& operator=(const TCanvasPainter&) = delete;
 
+
+  void CreateHttpServer();
+  void PopupBrowser();
+  void CheckModifiedFlag();
+  std::string CreateSnapshot(const ROOT::Experimental::TCanvas& can);
+
+
   /// Send the canvas primitives to the THttpServer.
-  void SendCanvas();
+  // void SendCanvas();
+
+   virtual Bool_t ProcessWS(THttpCallArg *arg);
+
 
 public:
   /// Create a TVirtualCanvasPainter for the given canvas.
   /// The painter observes it; it needs to know should the TCanvas be deleted.
-  TCanvasPainter(const ROOT::Experimental::TCanvas& canv): fCanvas(canv) {}
+  TCanvasPainter(const std::string &name, const ROOT::Experimental::TCanvas& canv):
+     THttpWSHandler(name.c_str(), "title"),
+     fCanvas(canv), 
+     fWebConn()
+   {
+      CreateHttpServer();
+      gServer->Register("/web7gui", this);
+      PopupBrowser();
+   }
+
+
+   virtual void AddDisplayItem(ROOT::Experimental::TDisplayItem *item) final;
+
+
 
   // void ReactToSocketNews(...) override { SendCanvas(); }
 
@@ -56,7 +112,7 @@ public:
 
     /// Create a new TCanvasPainter to paint the given TCanvas.
     std::unique_ptr<TVirtualCanvasPainter> Create(const ROOT::Experimental::TCanvas& canv) const override {
-      return std::make_unique<TCanvasPainter>(canv);
+      return std::make_unique<TCanvasPainter>("name", canv);
     }
     ~GeneratorImpl() = default;
 
@@ -76,6 +132,8 @@ public:
   };
 };
 
+std::string TCanvasPainter::fAddr = "";
+THttpServer *TCanvasPainter::gServer = 0;
 
 
 /** \class TCanvasPainterReg
@@ -95,9 +153,191 @@ struct TCanvasPainterReg {
 } // unnamed namespace
 
 
+  void TCanvasPainter::CreateHttpServer()
+   {
+      if (gServer) return;
 
-void TCanvasPainter::SendCanvas() {
-  for (auto &&drawable: fCanvas.GetPrimitives()) {
-    drawable->Paint(*this);
-  }
+      // gServer = new THttpServer("http:8080?loopback&websocket_timeout=10000");
+	   const char *port = gSystem->Getenv("WEBGUI_PORT");
+      TString buf;
+	   if (!port) {
+        gRandom->SetSeed(0);
+        buf.Form("%d", (int) (8800 + 1000* gRandom->Rndm(1)));
+        port = buf.Data(); // "8181";
+      }
+	   fAddr = TString::Format("http://localhost:%s", port).Data();
+      gServer = new THttpServer(TString::Format("http:%s?websocket_timeout=10000", port).Data());
+   }
+
+
+   void TCanvasPainter::PopupBrowser()
+   {
+       TString addr, exec;
+
+       addr.Form("%s/web7gui/%s/draw.htm?webcanvas", fAddr.c_str(), GetName());
+
+      if (gSystem->InheritsFrom("TMacOSXSystem"))
+	      exec.Form("open %s", addr.Data());
+      else
+         exec.Form("xdg-open %s &", addr.Data());
+      printf("Exec %s\n", exec.Data());
+
+      gSystem->Exec(exec);
+   }
+
+   Bool_t TCanvasPainter::ProcessWS(THttpCallArg *arg)
+   {
+      if (!arg) return kTRUE;
+
+      // try to identify connection for given WS request
+      WebConn* conn = 0;
+      WebConnList::iterator iter = fWebConn.begin();
+      while (iter != fWebConn.end()) {
+         if (iter->fHandle && (iter->fHandle->GetId() == arg->GetWSId()) && arg->GetWSId()) {
+            conn = &(*iter); break;
+         }
+         ++iter;
+      }
+
+      if (strcmp(arg->GetMethod(),"WS_CONNECT")==0) {
+
+         // accept all requests, in future one could limit number of connections
+         // arg->Set404(); // refuse connection
+         return kTRUE;
+      } 
+
+      if (strcmp(arg->GetMethod(),"WS_READY")==0) {
+          THttpWSEngine* wshandle = dynamic_cast<THttpWSEngine*> (arg->TakeWSHandle());
+
+          if (conn != 0) Error("ProcessWSRequest","WSHandle with given websocket id exists!!!");
+
+          WebConn newconn;
+          newconn.fHandle = wshandle;
+          newconn.fModified = kTRUE;
+
+          fWebConn.push_back(newconn);
+          printf("socket is ready\n");
+
+          return kTRUE;
+      }
+
+      if (strcmp(arg->GetMethod(),"WS_CLOSE")==0) {
+      // connection is closed, one can remove handle
+
+         if (conn && conn->fHandle) {
+            conn->fHandle->ClearHandle();
+            delete conn->fHandle;
+            conn->fHandle = 0;
+         }
+
+         if (conn) fWebConn.erase(iter);
+         return kTRUE;
+      }
+
+      if (strcmp(arg->GetMethod(),"WS_DATA")!=0) {    
+         Error("ProcessWSRequest","WSHandle DATA request expected!");
+         return kFALSE;
+      }
+
+      
+      if (!conn) {
+         Error("ProcessWSRequest","Get websocket data without valid connection - ignore!!!");
+         return kFALSE;
+      }
+
+      if (conn->fHandle->PreviewData(arg)) return kTRUE;
+
+      const char* cdata = (arg->GetPostDataLength()<=0) ? "" : (const char*) arg->GetPostData();     
+
+      if (strncmp(cdata,"READY",5)==0) {
+         conn->fReady = kTRUE;
+         CheckModifiedFlag();
+      } else
+      if (strncmp(cdata, "RREADY:", 7)==0) {
+         conn->fReady = kTRUE;
+         CheckModifiedFlag();
+      } 
+      
+      return kTRUE;
+   }
+
+void TCanvasPainter::CheckModifiedFlag()
+{
+
+   for (WebConnList::iterator citer = fWebConn.begin(); citer != fWebConn.end(); ++citer) {
+      WebConn& conn = *citer;
+
+      if (!conn.fReady || !conn.fHandle) continue;
+
+      TString buf;
+
+      if (conn.fGetMenu) {
+
+         conn.fGetMenu = 0;
+      } else
+       if (conn.fModified) {
+         // buf = "JSON";
+         // buf  += TBufferJSON::ConvertToJSON(Canvas(), 3);
+
+         buf = "SNAP";
+         buf += CreateSnapshot(fCanvas);
+         conn.fModified = kFALSE;
+      }
+
+      if (buf.Length() > 0) {
+         // sending of data can be moved into separate thread - not to block user code
+         conn.fReady = kFALSE;
+         conn.fHandle->SendCharStar(buf.Data());
+      }
+   }
+}
+
+void TCanvasPainter::AddDisplayItem(ROOT::Experimental::TDisplayItem *item)
+{
+   fDisplayList.Add(item);
 }
+
+std::string TCanvasPainter::CreateSnapshot(const ROOT::Experimental::TCanvas& can)
+{
+
+   fDisplayList.Clear();
+
+   fDisplayList.SetObjectIDAsPtr((void*)&can);
+
+   TPad *dummy = new TPad(); // just to keep information we need for different ranges now
+
+   auto *snap = new ROOT::Experimental::TUniqueDisplayItem<TPad>(dummy);
+   snap->SetObjectIDAsPtr((void*)&can);
+   fDisplayList.Add(snap);
+
+   for (auto &&drawable: can.GetPrimitives()) {
+
+      drawable->Paint(*this);
+
+      fDisplayList.Last()->SetObjectIDAsPtr(&(*drawable));
+
+      // ROOT::Experimental::TDisplayItem *sub = drawable->CreateSnapshot(can);
+      // if (!sub) continue;
+      // sub->SetObjectIDAsPtr(&(*drawable));
+      // lst.Add(sub);
+    }
+ 
+   TString res = TBufferJSON::ConvertToJSON(&fDisplayList, gROOT->GetClass("ROOT::Experimental::TPadDisplayItem"));
+  
+
+   fDisplayList.Clear();
+   
+   // printf("JSON %s\n", res.Data());
+
+   return std::string(res.Data());
+}
+
+
+
+
+
+//void TCanvasPainter::SendCanvas() {
+//  for (auto &&drawable: fCanvas.GetPrimitives()) {
+//    drawable->Paint(*this);
+//  }
+//}
diff --git a/hist/hist/inc/LinkDef.h b/hist/hist/inc/LinkDef.h
index ba2a3b6ef0207c59d07cb979bb6ca502f3f77a07..e3c8779d63f61ea48518127ee72437c81f49f3b5 100644
--- a/hist/hist/inc/LinkDef.h
+++ b/hist/hist/inc/LinkDef.h
@@ -354,6 +354,7 @@
 #pragma link C++ class ROOT::Experimental::TAxisEquidistant+;
 #pragma link C++ class ROOT::Experimental::TAxisIrregular+;
 #pragma link C++ class ROOT::Experimental::TAxisBase+;
+#pragma link C++ class ROOT::Experimental::TOrdinarySnapshot<TH1>+;
 #endif
 
 #endif
diff --git a/hist/hist/v7/inc/ROOT/THistDrawable.hxx b/hist/hist/v7/inc/ROOT/THistDrawable.hxx
index aa93f9b442cb43219ee97f2a0c2abb866de442dc..fa59ba9727493e00860bf4438ef78489c4499bc2 100644
--- a/hist/hist/v7/inc/ROOT/THistDrawable.hxx
+++ b/hist/hist/v7/inc/ROOT/THistDrawable.hxx
@@ -67,13 +67,14 @@ protected:
   std::unique_ptr<TH1> fOldHist;
 
 public:
-  TH1* GetOldHist() const { return fOldHist.get(); }
+   TH1* GetOldHist() const { return fOldHist.get(); }
 
    THistDrawableBase();
    THistDrawableBase(THistDrawableBase&&);
    virtual ~THistDrawableBase();
 
    THistDrawableBase& operator=(THistDrawableBase&&);
+  
 };
 
 template <int DIMENSIONS>
@@ -102,6 +103,7 @@ public:
     if (UpdateOldHist())
       THistPainterBase<DIMENSIONS>::GetPainter()->Paint(*this, fOpts, canv);
   }
+
 };
 
 extern template class THistDrawable<1>;
diff --git a/hist/histpainter/v7/src/THistPainter.cxx b/hist/histpainter/v7/src/THistPainter.cxx
index 0c63617e131cb3852edb731befc6c4a7fb4c704c..623304deca3317f31736ca7d0306cd4aece134b7 100644
--- a/hist/histpainter/v7/src/THistPainter.cxx
+++ b/hist/histpainter/v7/src/THistPainter.cxx
@@ -15,6 +15,8 @@
 //#include "ROOT/THistPainter.hxx" see ROOT/THistDrawable.h
 
 #include "ROOT/THistDrawable.hxx"
+#include "ROOT/TVirtualCanvasPainter.hxx"
+#include "ROOT/TDisplayItem.hxx"
 #include "TH1.h"
 
 #include <iostream>
@@ -37,11 +39,17 @@ public:
 class THistPainter2D: public THistPainterBase<2> {
 public:
   void Paint(TDrawable& drw, THistDrawOptions<2> /*opts*/,
-             TVirtualCanvasPainter& /* canv */) final {
+             TVirtualCanvasPainter& canv) final {
     std::cout << "Painting histogram @" << &drw << '\n';
     assert(dynamic_cast<THistDrawable<2>*>(&drw) && "Wrong drawable type");
     THistDrawable<2>& hd = static_cast<THistDrawable<2>&>(drw);
-    hd.GetOldHist()->Paint("BOX");
+
+    ROOT::Experimental::TDisplayItem *res = new TOrdinaryDisplayItem<TH1>(hd.GetOldHist());
+    res->SetOption("col");
+
+    canv.AddDisplayItem(res);
+
+    //hd.GetOldHist()->Paint("BOX");
   }
   virtual ~THistPainter2D() final {}
 };
diff --git a/tutorials/v7/draw.cxx b/tutorials/v7/draw.cxx
index 1d31354a98c8eb743e6bc72e8e89b614b3ac527d..f1c124c6d6bad763a056bb7b37a22a36c263aca5 100644
--- a/tutorials/v7/draw.cxx
+++ b/tutorials/v7/draw.cxx
@@ -44,4 +44,6 @@ void draw() {
   // Create a canvas to be displayed.
   auto canvas = Experimental::TCanvas::Create("Canvas Title");
   canvas->Draw(pHist);
+
+  canvas->Show();
 }