//+------------------------------------------------------------------+ //| HistogramChart.mqh | //| Copyright 2000-2025, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #include "ChartCanvas.mqh" #include //+------------------------------------------------------------------+ //| Class CHistogramChart | //| Usage: generates histogram chart | //+------------------------------------------------------------------+ class CHistogramChart : public CChartCanvas { private: //--- colors uint m_fill_brush[]; //--- adjusted parameters bool m_gradient; uint m_bar_gap; uint m_bar_min_size; uint m_bar_border; //--- data CArrayObj *m_values; public: CHistogramChart(void); ~CHistogramChart(void); //--- create virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE); //--- adjusted parameters void Gradient(const bool flag=true) { m_gradient=flag; } void BarGap(const uint value) { m_bar_gap=value; } void BarMinSize(const uint value) { m_bar_min_size=value; } void BarBorder(const uint value) { m_bar_border=value; } //--- data bool SeriesAdd(const double &value[],const string descr="",const uint clr=0); bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0); bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0); bool SeriesDelete(const uint pos); bool ValueUpdate(const uint series,const uint pos,double value); protected: virtual void DrawData(const uint idx); void DrawBar(const int x,const int y,const int w,const int h,const uint clr); void GradientBrush(const int size,const uint fill_clr); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CHistogramChart::CHistogramChart(void) : m_gradient(true), m_bar_gap(3), m_bar_min_size(5), m_bar_border(0) { ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID); } //+------------------------------------------------------------------+ //| Destructor | //+------------------------------------------------------------------+ CHistogramChart::~CHistogramChart(void) { if(ArraySize(m_fill_brush)!=0) ArrayFree(m_fill_brush); } //+------------------------------------------------------------------+ //| Create dynamic resource | //+------------------------------------------------------------------+ bool CHistogramChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt) { //--- create object to store data if((m_values=new CArrayObj)==NULL) return(false); //--- pass responsibility for its destruction to the parent class m_data=m_values; //--- call method of parent class if(!CChartCanvas::Create(name,width,height,clrfmt)) return(false); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Adds data series | //+------------------------------------------------------------------+ bool CHistogramChart::SeriesAdd(const double &value[],const string descr,const uint clr) { //--- check if(m_data_total==m_max_data) return(false); //--- add CArrayDouble *arr=new CArrayDouble; if(!m_values.Add(arr)) return(false); if(!arr.AssignArray(value)) return(false); if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr)) return(false); if(!m_descriptors.Add(descr)) return(false); m_data_total++; //--- redraw Redraw(); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Inserts data series | //+------------------------------------------------------------------+ bool CHistogramChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr) { //--- check if(m_data_total==m_max_data) return(false); if(pos>=m_data_total) return(false); //--- insert CArrayDouble *arr=new CArrayDouble; if(!m_values.Insert(arr,pos)) return(false); if(!arr.AssignArray(value)) return(false); if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos)) return(false); if(!m_descriptors.Insert(descr,pos)) return(false); m_data_total++; //--- redraw Redraw(); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Updates data series | //+------------------------------------------------------------------+ bool CHistogramChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr) { //--- check if(pos>=m_data_total) return(false); CArrayDouble *data=m_values.At(pos); if(data==NULL) return(false); //--- update if(!data.AssignArray(value)) return(false); if(clr!=0 && !m_colors.Update(pos,clr)) return(false); if(descr!=NULL && !m_descriptors.Update(pos,descr)) return(false); //--- redraw Redraw(); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Deletes data series | //+------------------------------------------------------------------+ bool CHistogramChart::SeriesDelete(const uint pos) { //--- check if(pos>=m_data_total && m_data_total!=0) return(false); //--- delete if(!m_values.Delete(pos)) return(false); m_data_total--; if(!m_colors.Delete(pos)) return(false); if(!m_descriptors.Delete(pos)) return(false); //--- redraw Redraw(); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Updates element in data series | //+------------------------------------------------------------------+ bool CHistogramChart::ValueUpdate(const uint series,const uint pos,double value) { CArrayDouble *data=m_values.At(series); //--- check if(data==NULL) return(false); //--- update if(!data.Update(pos,value)) return(false); //--- redraw Redraw(); //--- succeed return(true); } //+------------------------------------------------------------------+ //| Draws histogram | //+------------------------------------------------------------------+ void CHistogramChart::DrawData(const uint idx) { double value=0.0; //--- check CArrayDouble *data=m_values.At(idx); if(data==NULL) return; int total=data.Total(); if(total==0 || (int)idx>=total) return; //--- calculate int x1=m_data_area.left; int x2=m_data_area.right; int dx=(x2-x1)/total; uint clr=m_colors[idx]; uint w=dx/m_data_total; if(w0) { y=(m_y_0-(int)(value*m_scale_y)); h=m_y_0-y; } else { y=m_y_0; h=-(int)(value*m_scale_y); } DrawBar(x,y,w,h,clr); //--- draw text of value if(IS_SHOW_VALUE) { string text =DoubleToString(value,2); int width=(int)(TextWidth(text)+w); if(value>0) { if(width>y-m_y_max) TextOut(x+w/2,y+w,text,m_color_text,TA_RIGHT|TA_VCENTER); else TextOut(x+w/2,y-w,text,m_color_text,TA_LEFT|TA_VCENTER); } else { if(width>m_y_min-y-h) TextOut(x+w/2,y+h-w,text,m_color_text,TA_LEFT|TA_VCENTER); else TextOut(x+w/2,y+h+w,text,m_color_text,TA_RIGHT|TA_VCENTER); } } } if(IS_SHOW_VALUE) FontSet(fontname,fontsize,fontflags,fontangle); } //+------------------------------------------------------------------+ //| Draws bar | //+------------------------------------------------------------------+ void CHistogramChart::DrawBar(const int x,const int y,const int w,const int h,const uint clr) { //--- draw bar if(!m_gradient || ArraySize(m_fill_brush)>1; if((r&1)==0) i1--; //--- calculate while(dy>=dx) { clr=fill_clr; dclr=GETRGB(XRGB((r-dy)*GETRGBR(clr)/r,(r-dy)*GETRGBG(clr)/r,(r-dy)*GETRGBB(clr)/r)); clr-=dclr; m_fill_brush[i1]=clr; m_fill_brush[i2]=clr; //--- if(f>=0) { dy--; dd_y+=2; f+=dd_y; } dx++; if(--i1<0) break; i2++; dd_x+=2; f+=dd_x; } } else ArrayFree(m_fill_brush); } //+------------------------------------------------------------------+