How to fix flickering bitmap when updating its size accordingly? - page 5

 
Agustinus Biotamalo Lumbantoruan #:

Hey @Nikolai Semko, do you know why I get stack over flow error when use the library?

Thanks

I previously sent code that corrected your errors in working with the CCanvas array.  
You need to work with pointers and the new and delete operators.
CCanvas *canvasObjects[];
 
Agustinus, but I must warn you that you have taken a difficult way. I also tried to go down this way before, but I gave up and did not find a solution that satisfied me in everything. This is a way to create canvas objects tied to price-time. This way has an advantage - there is no lag when scrolling the chart, but a lot of difficulties arise when there are a large number of objects. Perhaps you can find a working scheme for working with an array of such objects, but I have little faith in this due to serious shortcomings in MQ in managing the object table. My recommendation, as has already been said several times in this thread, is to use one canvas for the entire window, and draw all graphic objects in it. The ideal solution would be my iCanvas library, in which one Cavnas object has already been created, which automatically stretches to fit the entire chart. With this library it will be as simple as possible to work with Canvas with maximum productivity.  See this example and this.
The disadvantage of working with a canvas object tied to pixels is that the canvas lags behind the chart when it is scrolled. This problem can be solved radically, while greatly increasing the performance of the canvas, by disabling the native chart and drawing this chart in the same canvas. You need to understand that creating your own canvas chart will take about 1-3 milliseconds, which has an excellent performance margin. The disadvantage of this approach is that it will be difficult to add third-party indicators to such a chart.
 
Agustinus Biotamalo Lumbantoruan #:

Hey @Nikolai Semko, do you know why I get stack over flow error when use the library?

Thanks

#property copyright "Copyright 2023, MetaQuotes Ltd."
#property link      "https://www.mql5.com/en/users/abiotamalo"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1
#include <Canvas\iCanvas_CB.mqh>
#include <Canvas\Canvas.mqh>
CCanvas *canvasObjects[];
int Counter=0;
void OnDeinit(const int r){
   for(int i=0;i<ArraySize(canvasObjects);i++){
         delete canvasObjects[i];  
   }   
   ChartRedraw();        
}
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- create canvas
   int x=0;
   int y=0;
   ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,144),iHigh(Symbol(),PERIOD_CURRENT,144),x,y);
   int x1=0;
   int y1=0;
   ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,97),iLow(Symbol(),PERIOD_CURRENT,97),x1,y1);
   double priceWidth=x1-x;
   double priceHeight=y1-y;
   bool objCreated=false;
   /*
      First canvas object
   */
   if(true)
     {
      ArrayResize(canvasObjects,1);
      canvasObjects[0] = new CCanvas;
      string name="144_97";
      datetime startTime=iTime(Symbol(),PERIOD_CURRENT,50);
      double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,50);        
      objCreated=canvasObjects[0].CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE);
      canvasObjects[0].Erase(ColorToARGB(clrRed, 0));      
      canvasObjects[0].Update();
      Print(canvasObjects[0].ChartObjectName());   
     }
   ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,50),iHigh(Symbol(),PERIOD_CURRENT,50),x,y);
   x1=0;
   y1=0;
   ChartTimePriceToXY(0,0,iTime(Symbol(),PERIOD_CURRENT,8),iLow(Symbol(),PERIOD_CURRENT,8),x1,y1);
   priceWidth=x1-x;
   priceHeight=y1-y;
   objCreated=false;
   /*
      Second Canvas Object
   */
   if(true)
     {
      int size = ArraySize(canvasObjects);
      ArrayResize(canvasObjects,size+1);
      canvasObjects[size] = new CCanvas;
      string name="50_8";
      datetime startTime=iTime(Symbol(),PERIOD_CURRENT,50);
      double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,50);        
      objCreated=canvasObjects[size].CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE);
      canvasObjects[size].Erase(ColorToARGB(clrRed, 0));      
      canvasObjects[size].Update();  
      Print(canvasObjects[size].ChartObjectName()); 
     }    
   return(INIT_SUCCEEDED);
  }

//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {
   return rates_total;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  { 
   if(id==CHARTEVENT_CHART_CHANGE)
     {
      int size = ArraySize(canvasObjects);
      for(int i=0;i<size;i++){
         string name=canvasObjects[i].ChartObjectName();
         if (name==NULL) break;
         string split[];
         StringSplit(name,StringGetCharacter("_",0),split);
         int startIndex=(int)split[0];
         int endIndex=(int)split[1];
         int x=(int)_X((double)startIndex);
         int y=(int)_Y(iHigh(Symbol(),PERIOD_CURRENT,startIndex));
         datetime startTime=iTime(Symbol(),PERIOD_CURRENT,startIndex);
         double startignPoint=iHigh(Symbol(),PERIOD_CURRENT,startIndex);         
         int x1=(int)_X((double)endIndex);
         int y1=(int)_Y(iLow(Symbol(),PERIOD_CURRENT,endIndex));
         double priceWidth=x1-x;
         double priceHeight=y1-y;  
         double fillRectangleSize=priceHeight/3;
         //bool objCreated=canvasObjects[i].CreateBitmap(name,startTime,startignPoint,x1-x,y1-y,COLOR_FORMAT_ARGB_NORMALIZE);
         ObjectSetInteger(canvasObjects[i].m_chart_id,canvasObjects[i].m_objname,OBJPROP_TIME,startTime);
         ObjectSetDouble(canvasObjects[i].m_chart_id,canvasObjects[i].m_objname,OBJPROP_PRICE,startignPoint);
         canvasObjects[i].Resize(x1-x,y1-y);
         if(i==0)
            canvasObjects[i].FillRectangle(0,0,(int)priceWidth,(int)fillRectangleSize,ColorToARGB(clrRed, 50));
         if(i==1)
            canvasObjects[i].FillRectangle(0,0,(int)(priceWidth*0.33),(int)fillRectangleSize,ColorToARGB(clrRed, 50));
         if(i==0)//Just width variation
            canvasObjects[i].FillRectangle(0,(int)fillRectangleSize,(int)(priceWidth*0.5),(int)fillRectangleSize*2,ColorToARGB(clrGreen, 50));
         else
            canvasObjects[i].FillRectangle(0,(int)fillRectangleSize,(int)(priceWidth*0.2),(int)fillRectangleSize*2,ColorToARGB(clrGreen, 50));
         canvasObjects[i].FillRectangle(0,(int)fillRectangleSize*2,(int)priceWidth,(int)fillRectangleSize*3,ColorToARGB(clrBlue, 50));
         //c.Resize(priceWidth*0.1,fillRectangleSize*0.1);
         canvasObjects[i].Update();     
      }   
     }
  }    

Using strings to pass parameters is very unwise from a performance point of view. Create an additional array of structures for the parameters.

 
Nikolai Semko #:
Agustinus, but I must warn you that you have taken a difficult way. I also tried to go down this way before, but I gave up and did not find a solution that satisfied me in everything. This is a way to create canvas objects tied to price-time. This way has an advantage - there is no lag when scrolling the chart, but a lot of difficulties arise when there are a large number of objects. Perhaps you can find a working scheme for working with an array of such objects, but I have little faith in this due to serious shortcomings in MQ in managing the object table. My recommendation, as has already been said several times in this thread, is to use one canvas for the entire window, and draw all graphic objects in it. The ideal solution would be my iCanvas library, in which one Cavnas object has already been created, which automatically stretches to fit the entire chart. With this library it will be as simple as possible to work with Canvas with maximum productivity.  See this example and this.
The disadvantage of working with a canvas object tied to pixels is that the canvas lags behind the chart when it is scrolled. This problem can be solved radically, while greatly increasing the performance of the canvas, by disabling the native chart and drawing this chart in the same canvas. You need to understand that creating your own canvas chart will take about 1-3 milliseconds, which has an excellent performance margin. The disadvantage of this approach is that it will be difficult to add third-party indicators to such a chart.

I made a mistake. Frame formation (without Erase()and Update()) takes not 1-3 milliseconds, but 0.02-0.3 milliseconds, depending on the scale.

2023.10.10 17:57:11.706 CanvasBar (EURUSD,H4)   0.216 milliseconds
2023.10.10 17:57:11.739 CanvasBar (EURUSD,H4)   0.210 milliseconds
2023.10.10 17:57:14.456 CanvasBar (EURUSD,H4)   0.202 milliseconds
2023.10.10 17:57:14.545 CanvasBar (EURUSD,H4)   0.148 milliseconds
2023.10.10 17:57:14.546 CanvasBar (EURUSD,H4)   0.095 milliseconds
2023.10.10 17:57:14.582 CanvasBar (EURUSD,H4)   0.149 milliseconds
2023.10.10 17:57:14.597 CanvasBar (EURUSD,H4)   0.116 milliseconds
2023.10.10 17:57:23.296 CanvasBar (EURUSD,H4)   0.066 milliseconds
2023.10.10 17:57:23.531 CanvasBar (EURUSD,H4)   0.043 milliseconds
2023.10.10 17:57:23.717 CanvasBar (EURUSD,H4)   0.031 milliseconds
2023.10.10 17:57:27.221 CanvasBar (EURUSD,H4)   0.022 milliseconds
2023.10.10 17:57:27.247 CanvasBar (EURUSD,H4)   0.027 milliseconds
2023.10.10 17:57:28.375 CanvasBar (EURUSD,H4)   0.042 milliseconds
2023.10.10 17:57:30.663 CanvasBar (EURUSD,H4)   0.037 milliseconds
2023.10.10 17:57:34.624 CanvasBar (EURUSD,H4)   0.066 milliseconds
Files:
CanvasBar.mq5  7 kb
 
Nikolai Semko #:

I made a mistake. Frame formation (without Erase()and Update()) takes not 1-3 milliseconds, but 0.02-0.3 milliseconds, depending on the scale.

Wow, thank you so much for your support & help. I will consider your advise using a single canvas and update the object inside the canvas.