mql-for-begginers/Include/Canvas/Charts/ChartCanvas.mqh
2025-07-22 18:30:17 +03:00

1043 lines
34 KiB
MQL5

//+------------------------------------------------------------------+
//| ChartCanvas.mqh |
//| Copyright 2000-2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#include "..\Canvas.mqh"
#include <Arrays\ArrayInt.mqh>
#include <Arrays\ArrayUInt.mqh>
#include <Arrays\ArrayDouble.mqh>
#include <Arrays\ArrayString.mqh>
//--- enumerations
enum ENUM_SHOW_FLAGS
{
FLAG_SHOW_NONE =0,
FLAG_SHOW_LEGEND =1,
FLAG_SHOW_SCALE_LEFT =2,
FLAG_SHOW_SCALE_RIGHT =4,
FLAG_SHOW_SCALE_TOP =8,
FLAG_SHOW_SCALE_BOTTOM=16,
FLAG_SHOW_GRID =32,
FLAG_SHOW_DESCRIPTORS =64,
FLAG_SHOW_VALUE =128,
FLAG_SHOW_PERCENT =256,
FLAGS_SHOW_SCALES =(FLAG_SHOW_SCALE_LEFT+FLAG_SHOW_SCALE_RIGHT+
FLAG_SHOW_SCALE_TOP+FLAG_SHOW_SCALE_BOTTOM),
FLAGS_SHOW_ALL =(FLAG_SHOW_LEGEND+FLAGS_SHOW_SCALES+FLAG_SHOW_GRID+
FLAG_SHOW_DESCRIPTORS+FLAG_SHOW_VALUE+FLAG_SHOW_PERCENT)
};
enum ENUM_ALIGNMENT
{
ALIGNMENT_LEFT = 1, // align by left border
ALIGNMENT_TOP = 2, // align by top border
ALIGNMENT_RIGHT = 4, // align by right border
ALIGNMENT_BOTTOM = 8 // align by bottom border
};
//--- macro
#define IS_SHOW_LEGEND ((m_show_flags&FLAG_SHOW_LEGEND) !=0)
#define IS_SHOW_SCALES ((m_show_flags&FLAGS_SHOW_SCALES) !=0)
#define IS_SHOW_SCALE_LEFT ((m_show_flags&FLAG_SHOW_SCALE_LEFT) !=0)
#define IS_SHOW_SCALE_RIGHT ((m_show_flags&FLAG_SHOW_SCALE_RIGHT) !=0)
#define IS_SHOW_SCALE_TOP ((m_show_flags&FLAG_SHOW_SCALE_TOP) !=0)
#define IS_SHOW_SCALE_BOTTOM ((m_show_flags&FLAG_SHOW_SCALE_BOTTOM)!=0)
#define IS_SHOW_GRID ((m_show_flags&FLAG_SHOW_GRID) !=0)
#define IS_SHOW_DESCRIPTORS ((m_show_flags&FLAG_SHOW_DESCRIPTORS) !=0)
#define IS_SHOW_VALUE ((m_show_flags&FLAG_SHOW_VALUE) !=0)
#define IS_SHOW_PERCENT ((m_show_flags&FLAG_SHOW_PERCENT) !=0)
//+------------------------------------------------------------------+
//| Class CChartCanvas |
//| Usage: base class for graphical charts |
//+------------------------------------------------------------------+
class CChartCanvas : public CCanvas
{
protected:
//--- colors
uint m_color_background;
uint m_color_border;
uint m_color_text;
uint m_color_grid;
//--- adjusted parameters
uint m_max_data;
uint m_max_descr_len;
uint m_allowed_show_flags;
uint m_show_flags;
ENUM_ALIGNMENT m_legend_alignment;
uint m_threshold_drawing;
bool m_accumulative;
//--- parameters for scales and grid
double m_v_scale_min;
double m_v_scale_max;
uint m_num_grid;
int m_scale_digits;
//--- data
int m_data_offset;
uint m_data_total;
CArray *m_data;
CArrayUInt m_colors;
CArrayString m_descriptors;
//---
CArrayInt m_index;
uint m_index_size;
double m_sum;
double m_others;
uint m_max_descr_width;
uint m_max_value_width;
//--- variables
CRect m_data_area;
//--- variables for scaling and scales
double m_scale_x;
int m_x_min;
int m_x_0;
int m_x_max;
int m_dx_grid;
double m_scale_y;
int m_y_min;
int m_y_0;
int m_y_max;
int m_dy_grid;
string m_scale_text[];
public:
CChartCanvas(void);
~CChartCanvas(void);
//--- create
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
//--- colors
uint ColorBackground(void) const { return(m_color_background); }
void ColorBackground(const uint value);
uint ColorBorder(void) const { return(m_color_border); }
void ColorBorder(const uint value);
uint ColorText(void) const { return(m_color_text); }
void ColorText(const uint value);
uint ColorGrid(void) const { return(m_color_grid); }
void ColorGrid(const uint value) { m_color_grid=value; }
//--- adjusted parameters
uint MaxData(void) const { return(m_max_data); }
void MaxData(const uint value);
uint MaxDescrLen(void) const { return(m_max_descr_len); }
void MaxDescrLen(const uint value);
//--- show flags
void AllowedShowFlags(const uint flags);
uint ShowFlags(void) const { return(m_show_flags); }
void ShowFlags(const uint flags);
bool IsShowLegend(void) const { return(IS_SHOW_LEGEND); }
bool IsShowScaleLeft(void) const { return(IS_SHOW_SCALE_LEFT); }
bool IsShowScaleRight(void) const { return(IS_SHOW_SCALE_RIGHT); }
bool IsShowScaleTop(void) const { return(IS_SHOW_SCALE_TOP); }
bool IsShowScaleBottom(void) const { return(IS_SHOW_SCALE_BOTTOM); }
bool IsShowGrid(void) const { return(IS_SHOW_GRID); }
bool IsShowDescriptors(void) const { return(IS_SHOW_DESCRIPTORS); }
bool IsShowPercent(void) const { return(IS_SHOW_PERCENT); }
void ShowLegend(const bool flag=true);
void ShowScaleLeft(const bool flag=true);
void ShowScaleRight(const bool flag=true);
void ShowScaleTop(const bool flag=true);
void ShowScaleBottom(const bool flag=true);
void ShowGrid(const bool flag=true);
void ShowDescriptors(const bool flag=true);
void ShowValue(const bool flag=true);
void ShowPercent(const bool flag=true);
void LegendAlignment(const ENUM_ALIGNMENT value);
void Accumulative(const bool flag=true);
//--- for scales and grid
double VScaleMin(void) const { return(m_v_scale_min); }
void VScaleMin(const double value);
double VScaleMax(void) const { return(m_v_scale_max); }
void VScaleMax(const double value);
uint NumGrid(void) const { return(m_num_grid); }
void NumGrid(const uint value);
void VScaleParams(const double max,const double min,const uint grid);
//--- state
int DataOffset(void) const { return(m_data_offset); }
void DataOffset(const int value);
//--- data
uint DataTotal(void) const { return(m_data_total); }
bool DescriptorUpdate(const uint pos,const string descr);
bool ColorUpdate(const uint pos,const uint clr);
protected:
virtual void ValuesCheck(void);
virtual void Redraw(void);
virtual void DrawBackground(void);
virtual void DrawLegend(void);
int DrawLegendVertical(const int w,const int h);
int DrawLegendHorizontal(const int w,const int h);
virtual void CalcScales(void);
virtual void DrawScales(void);
virtual int DrawScaleLeft(const bool draw=true);
virtual int DrawScaleRight(const bool draw=true);
virtual int DrawScaleTop(const bool draw=true);
virtual int DrawScaleBottom(const bool draw=true);
virtual void DrawGrid(void);
virtual void DrawDescriptors(void) {}
virtual void DrawChart(void);
virtual void DrawData(const uint idx=0) {}
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CChartCanvas::CChartCanvas(void) : m_color_background(XRGB(0xFF,0xFF,0xFF)),
m_color_border(XRGB(0x9F,0x9F,0x9F)),
m_color_text(XRGB(0x3F,0x3F,0x3F)),
m_color_grid(XRGB(0xCF,0xCF,0xCF)),
m_max_data(10),
m_max_descr_len(10),
m_allowed_show_flags(FLAGS_SHOW_ALL),
m_show_flags(FLAG_SHOW_NONE),
m_legend_alignment(ALIGNMENT_BOTTOM),
m_threshold_drawing(2),
m_accumulative(false),
m_data_offset(0),
m_data_total(0),
m_data(NULL),
m_v_scale_min(0.0),
m_v_scale_max(10.0),
m_num_grid(5),
m_scale_digits(0)
{
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CChartCanvas::~CChartCanvas(void)
{
if(m_data!=NULL)
delete m_data;
}
//+------------------------------------------------------------------+
//| Create dynamic resource |
//+------------------------------------------------------------------+
bool CChartCanvas::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
{
//--- call method of parent class
if(!CCanvas::Create(name,width,height,clrfmt))
return(false);
//--- set font
FontSet("Tahoma",-100);
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Sets background color |
//+------------------------------------------------------------------+
void CChartCanvas::ColorBackground(const uint value)
{
m_color_background=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets border color |
//+------------------------------------------------------------------+
void CChartCanvas::ColorBorder(const uint value)
{
m_color_border=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets text color |
//+------------------------------------------------------------------+
void CChartCanvas::ColorText(const uint value)
{
m_color_text=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets maximum amount of data |
//+------------------------------------------------------------------+
void CChartCanvas::MaxData(const uint value)
{
//--- check
if((value==0) || (m_data_total==value))
return;
//--- save
m_max_data=value;
if(m_data_total>m_max_data)
{
m_data_total=value;
m_colors.Resize(value);
m_descriptors.Resize(value);
}
}
//+------------------------------------------------------------------+
//| Sets maximum length of descriptor |
//+------------------------------------------------------------------+
void CChartCanvas::MaxDescrLen(const uint value)
{
m_max_descr_len=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets allowed visibility flags |
//+------------------------------------------------------------------+
void CChartCanvas::AllowedShowFlags(const uint flags)
{
m_allowed_show_flags=flags;
m_show_flags&=m_allowed_show_flags;
}
//+------------------------------------------------------------------+
//| Sets visibility flags |
//+------------------------------------------------------------------+
void CChartCanvas::ShowFlags(const uint flags)
{
m_show_flags=flags&m_allowed_show_flags;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets visibility flag for "legend" |
//+------------------------------------------------------------------+
void CChartCanvas::ShowLegend(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_LEGEND)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_LEGEND;
else
m_show_flags&=~FLAG_SHOW_LEGEND;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for left scale |
//+------------------------------------------------------------------+
void CChartCanvas::ShowScaleLeft(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_SCALE_LEFT)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_SCALE_LEFT;
else
m_show_flags&=~FLAG_SHOW_SCALE_LEFT;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for right scale |
//+------------------------------------------------------------------+
void CChartCanvas::ShowScaleRight(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_SCALE_RIGHT)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_SCALE_RIGHT;
else
m_show_flags&=~FLAG_SHOW_SCALE_RIGHT;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for top scale |
//+------------------------------------------------------------------+
void CChartCanvas::ShowScaleTop(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_SCALE_TOP)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_SCALE_TOP;
else
m_show_flags&=~FLAG_SHOW_SCALE_TOP;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for bottom scale |
//+------------------------------------------------------------------+
void CChartCanvas::ShowScaleBottom(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_SCALE_BOTTOM)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_SCALE_BOTTOM;
else
m_show_flags&=~FLAG_SHOW_SCALE_BOTTOM;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for grid |
//+------------------------------------------------------------------+
void CChartCanvas::ShowGrid(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_GRID)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_GRID;
else
m_show_flags&=~FLAG_SHOW_GRID;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for descriptors |
//+------------------------------------------------------------------+
void CChartCanvas::ShowDescriptors(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_DESCRIPTORS)!=0)
{
if(flag)
m_show_flags|=FLAG_SHOW_DESCRIPTORS;
else
m_show_flags&=~FLAG_SHOW_DESCRIPTORS;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for value |
//+------------------------------------------------------------------+
void CChartCanvas::ShowValue(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_VALUE)!=0)
{
if(flag)
{
m_show_flags|=FLAG_SHOW_VALUE;
m_show_flags&=~FLAG_SHOW_PERCENT;
}
else
m_show_flags&=~FLAG_SHOW_VALUE;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets visibility flag for percentage |
//+------------------------------------------------------------------+
void CChartCanvas::ShowPercent(const bool flag)
{
if((m_allowed_show_flags&FLAG_SHOW_PERCENT)!=0)
{
if(flag)
{
m_show_flags|=FLAG_SHOW_PERCENT;
m_show_flags&=~FLAG_SHOW_VALUE;
}
else
m_show_flags&=~FLAG_SHOW_PERCENT;
//--- redraw
if(m_data_total>0)
Redraw();
}
}
//+------------------------------------------------------------------+
//| Sets legend alignment |
//+------------------------------------------------------------------+
void CChartCanvas::LegendAlignment(const ENUM_ALIGNMENT value)
{
m_legend_alignment=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets accumulative flag |
//+------------------------------------------------------------------+
void CChartCanvas::Accumulative(const bool flag=true)
{
m_accumulative=flag;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets lower limit for vertical scale |
//+------------------------------------------------------------------+
void CChartCanvas::VScaleMin(const double value)
{
//--- check
if(value==m_v_scale_max)
return;
//--- save
m_v_scale_min=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets upper limit for vertical scale |
//+------------------------------------------------------------------+
void CChartCanvas::VScaleMax(const double value)
{
if(value==m_v_scale_min)
return;
//--- save
m_v_scale_max=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets number of vertical scale divisions |
//+------------------------------------------------------------------+
void CChartCanvas::NumGrid(const uint value)
{
//--- check
if(value==0)
return;
//--- save
m_num_grid=value;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets parameters for vertical scale |
//+------------------------------------------------------------------+
void CChartCanvas::VScaleParams(const double max,const double min,const uint grid)
{
//--- check
if(grid==0)
return;
if(max<=min)
return;
//--- save
m_v_scale_max=max;
m_v_scale_min=min;
m_num_grid =grid;
//--- redraw
if(m_data_total>0)
Redraw();
}
//+------------------------------------------------------------------+
//| Sets data offset |
//+------------------------------------------------------------------+
void CChartCanvas::DataOffset(const int value)
{
m_data_offset=value;
//--- redraw
Redraw();
}
//+------------------------------------------------------------------+
//| Updates parameter descriptor only (in specified position) |
//+------------------------------------------------------------------+
bool CChartCanvas::DescriptorUpdate(const uint pos,const string descr)
{
//--- update
if(descr!=NULL && !m_descriptors.Update(pos,descr))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Updates parameter color only (in specified position) |
//+------------------------------------------------------------------+
bool CChartCanvas::ColorUpdate(const uint pos,const uint clr)
{
//--- update
if(clr!=0 && !m_colors.Update(pos,clr))
return(false);
//--- redraw
Redraw();
//--- succeed
return(true);
}
//+------------------------------------------------------------------+
//| Checks values for insignificance |
//+------------------------------------------------------------------+
void CChartCanvas::ValuesCheck(void)
{
string text;
int w,h;
//--- clear
m_max_value_width=0;
m_sum =0;
m_others =0;
m_index_size =0;
m_index.Clear();
//--- check
if(m_data==NULL)
return;
if(m_data.Type()==TYPE_DOUBLE)
{
//--- single-series chart
//--- calculate sum of all values
for(uint i=0;i<m_data_total;i++)
m_sum+=((CArrayDouble*)m_data)[i];
//--- find insignificant values
for(uint i=0;i<m_data_total;i++)
{
double value=((CArrayDouble*)m_data)[i];
//--- insignificant value is less than drawing threshold value
if(value/m_sum<0.01*m_threshold_drawing)
{
//--- move insignificant value to 'others' group
m_others+=value;
}
else
{
//--- populate index for all significant values
m_index.Add(i);
text=DoubleToString(value,2);
TextSize(text,w,h);
if(m_max_value_width<(uint)w)
m_max_value_width=(uint)w;
}
}
text=DoubleToString(m_others,2);
TextSize(text,w,h);
if(m_max_value_width<(uint)w)
m_max_value_width=(uint)w;
m_index_size=m_index.Total();
}
else
{
//--- multi-series chart
//--- populate index for uniformity
for(uint i=0;i<m_data_total;i++)
m_index.Add(i);
m_index_size=m_data_total;
}
}
//+------------------------------------------------------------------+
//| Redraws chart |
//+------------------------------------------------------------------+
void CChartCanvas::Redraw(void)
{
int gap=m_fontsize/(-10);
m_data_area.SetBound(gap,gap,m_width-gap,m_height-gap);
//--- values check
ValuesCheck();
//--- draw background
DrawBackground();
//--- draw auxiliary elements
if(IS_SHOW_LEGEND)
DrawLegend();
if(IS_SHOW_SCALES)
DrawScales();
if(IS_SHOW_GRID)
DrawGrid();
if(IS_SHOW_DESCRIPTORS)
DrawDescriptors();
//--- draw data
DrawChart();
//--- fix changes
Update();
}
//+------------------------------------------------------------------+
//| Redraws background |
//+------------------------------------------------------------------+
void CChartCanvas::DrawBackground(void)
{
Erase(m_color_background);
Rectangle(0,0,m_width-1,m_height-1,m_color_border);
}
//+------------------------------------------------------------------+
//| Redraws "legend" |
//+------------------------------------------------------------------+
void CChartCanvas::DrawLegend(void)
{
//--- check
if(m_data_total==0)
return;
//--- variables
string text="A";
int max_len=0;
int w,h;
//--- set font
FontAngleSet(0);
//--- calculate
if(m_data_total==m_index_size)
{
for(uint i=0;i<m_data_total;i++)
{
w=StringLen(m_descriptors[i]);
if(max_len<w)
{
max_len=w;
text=m_descriptors[i];
}
}
}
else
{
for(uint i=0;i<m_index_size;i++)
{
int index=m_index[i];
w=StringLen(m_descriptors[index]);
if(max_len<w)
{
max_len=w;
text=m_descriptors[index];
}
}
w=StringLen("Others");
if(max_len<w)
{
max_len=w;
text="Others";
}
}
if(max_len==0)
return;
TextSize(" - "+text,w,h);
m_max_descr_width=(uint)w;
w=w+3*h;
//--- check flag
if(!IS_SHOW_LEGEND)
return;
//--- draw
switch(m_legend_alignment)
{
case ALIGNMENT_LEFT:
m_data_area.left+=DrawLegendVertical(w,h);
break;
case ALIGNMENT_RIGHT:
m_data_area.right-=DrawLegendVertical(w,h);
break;
case ALIGNMENT_TOP:
m_data_area.top+=DrawLegendHorizontal(w,h);
break;
case ALIGNMENT_BOTTOM:
m_data_area.bottom-=DrawLegendHorizontal(w,h);
break;
}
}
//+------------------------------------------------------------------+
//| Draw vertical "legend" |
//+------------------------------------------------------------------+
int CChartCanvas::DrawLegendVertical(const int w,const int h)
{
int width =m_data_area.Width();
int height=m_data_area.Height();
int rows =(int)m_index_size;
int cols =1;
int dy =(int)(1.5*h);
//--- calculate
while(dy*rows>m_height)
{
cols++;
rows=(int)m_index_size/cols;
if((int)m_index_size%cols!=0)
rows++;
}
//--- draw
int x0=(m_legend_alignment==ALIGNMENT_RIGHT) ? width-w*cols+h : h;
int x=0;
int y =-h/2;
int i;
if(m_data_total==m_index_size)
{
for(i=0;i<(int)m_data_total;i++,x+=w)
{
if(i%cols==0)
{
x=x0;
y+=dy;
}
FillRectangle(x,y,x+h,y+h,(uint)m_colors[i]);
TextOut(x+h,y," - "+m_descriptors[i],m_color_text);
}
}
else
{
for(i=0;i<(int)m_index_size;i++,x+=w)
{
int index=m_index[i];
if(i%cols==0)
{
x=x0;
y+=dy;
}
FillRectangle(x,y,x+h,y+h,(uint)m_colors[index]);
TextOut(x+h,y," - "+m_descriptors[index],m_color_text);
}
if(i%cols==0)
{
x=x0;
y+=dy;
}
FillRectangle(x,y,x+h,y+h,COLOR2RGB(clrBlack));
TextOut(x+h,y," - Others",m_color_text);
}
//--- width
return(w*cols);
}
//+------------------------------------------------------------------+
//| Draw horizontal "legend" |
//+------------------------------------------------------------------+
int CChartCanvas::DrawLegendHorizontal(const int w,const int h)
{
int width =m_data_area.Width();
int height=m_data_area.Height();
int rows =1;
int cols =(int)m_index_size;
//--- calculate
while(w*cols>m_width)
{
rows++;
cols=(int)m_index_size/rows;
if((int)m_index_size%rows!=0)
cols++;
}
//--- draw
int dx=width/(cols+1);
int x =dx-w/2+h;
int dy=(int)(1.5*h);
int y =(m_legend_alignment==ALIGNMENT_BOTTOM) ? height-dy*(rows+1) : -h/2;
int i;
if(m_data_total==m_index_size)
{
for(i=0;i<(int)m_data_total;i++,x+=dx)
{
if(i%cols==0)
{
x=dx-w/2+h;
y+=dy;
}
FillRectangle(x,y,x+h,y+h,(uint)m_colors[i]);
TextOut(x+h,y," - "+m_descriptors[i],m_color_text);
}
}
else
{
for(i=0;i<(int)m_index_size;i++,x+=dx)
{
int index=m_index[i];
if(i%cols==0)
{
x=dx-w/2+h;
y+=dy;
}
FillRectangle(x,y,x+h,y+h,(uint)m_colors[index]);
TextOut(x+h,y," - "+m_descriptors[index],m_color_text);
}
if(i%cols==0)
{
x=dx-w/2+h;
y+=dy;
}
FillRectangle(x,y,x+h,y+h,COLOR2RGB(clrBlack));
TextOut(x+h,y," - Others",m_color_text);
}
//--- height
return(dy*(rows+1));
}
//+------------------------------------------------------------------+
//| Calculates coordinates of scales |
//+------------------------------------------------------------------+
void CChartCanvas::CalcScales(void)
{
int width =m_data_area.Width();
int height=m_data_area.Height();
//--- limits
m_y_max=m_data_area.top+DrawScaleTop(false);
m_y_min=m_data_area.bottom-DrawScaleBottom(false);
//--- additional
m_dy_grid=(int)((m_y_min-m_y_max)/m_num_grid);
m_y_max+=(int)(((m_y_min-m_y_max)-m_dy_grid*m_num_grid)/2);
m_y_min=(int)(m_y_max+m_dy_grid*m_num_grid);
//--- normalize
if(m_v_scale_min>=0.0)
m_y_0=m_y_min;
else
{
if(m_v_scale_max<=0.0)
m_y_0=m_y_max;
else
m_y_0=(int)(m_y_max+(m_y_min-m_y_max)*m_v_scale_max/(m_v_scale_max-m_v_scale_min));
}
//--- scale
m_scale_y=(m_v_scale_max!=m_v_scale_min) ? (m_y_min-m_y_max)/(m_v_scale_max-m_v_scale_min) : 1;
//--- labels on scale
if(ArraySize(m_scale_text)!=m_num_grid+1 && ArrayResize(m_scale_text,m_num_grid+1)==-1)
return;
double val=m_v_scale_min;
double dval=(m_v_scale_max-m_v_scale_min)/m_num_grid;
for(uint i=0;i<=m_num_grid;i++,val+=dval)
m_scale_text[i]=DoubleToString(val,m_scale_digits);
}
//+------------------------------------------------------------------+
//| Redraws scales |
//+------------------------------------------------------------------+
void CChartCanvas::DrawScales(void)
{
//--- recalculate
CalcScales();
//--- redraw scales
if(IS_SHOW_SCALE_LEFT)
DrawScaleLeft();
if(IS_SHOW_SCALE_RIGHT)
DrawScaleRight();
if(IS_SHOW_SCALE_TOP)
DrawScaleTop();
if(IS_SHOW_SCALE_BOTTOM)
DrawScaleBottom();
}
//+------------------------------------------------------------------+
//| Redraws left scale |
//+------------------------------------------------------------------+
int CChartCanvas::DrawScaleLeft(const bool draw)
{
//--- check flag
if(!IS_SHOW_SCALE_LEFT)
return(0);
//--- variables
int x1=m_data_area.left;
int x2;
int y=m_y_min;
//--- calculate scale width
int size=0;
for(uint i=0;i<=m_num_grid;i++)
{
if(size<TextWidth(m_scale_text[i]))
size=TextWidth(m_scale_text[i]);
}
//--- add indent and graduation mark (for now 5 pixels)
size+=5+5;
//--- draw
if(draw)
{
x2=x1+size;
x1=x2-5;
//--- draw line
Line(x2,y,x2,m_y_max,m_color_text);
//--- set font
FontAngleSet(0);
//--- draw text
for(uint i=0;i<=m_num_grid;i++,y-=m_dy_grid)
{
Line(x1,y,x2,y,m_color_text);
if((int)i<ArraySize(m_scale_text))
TextOut(x1-5,y,m_scale_text[i],m_color_text,TA_RIGHT|TA_VCENTER);
}
//--- adjust data area
m_data_area.left+=size;
}
//--- return width
return(size);
}
//+------------------------------------------------------------------+
//| Redraws right scale |
//+------------------------------------------------------------------+
int CChartCanvas::DrawScaleRight(const bool draw)
{
//--- check flag
if(!IS_SHOW_SCALE_RIGHT)
return(0);
//--- variables
int x1;
int x2=m_data_area.right;
int y =m_y_min;
//--- calculate scale width
int size=0;
for(uint i=0;i<=m_num_grid;i++)
{
if(size<TextWidth(m_scale_text[i]))
size=TextWidth(m_scale_text[i]);
}
//--- add indent and graduation mark (for now 5 pixels)
size+=5+5;
//--- draw
if(draw)
{
x1=x2-size;
x2=x1+5;
//--- draw line
Line(x1,y,x1,m_y_max,m_color_text);
//--- set font
FontAngleSet(0);
//--- draw text
for(uint i=0;i<=m_num_grid;i++,y-=m_dy_grid)
{
Line(x1,y,x2,y,m_color_text);
if((int)i<ArraySize(m_scale_text))
TextOut(x2+5,y,m_scale_text[i],m_color_text,TA_LEFT|TA_VCENTER);
}
//--- adjust data area
m_data_area.right-=size;
}
//--- return widht
return(size);
}
//+------------------------------------------------------------------+
//| Redraws top scale |
//+------------------------------------------------------------------+
int CChartCanvas::DrawScaleTop(const bool draw)
{
int size=0;
//--- check flag
if(!IS_SHOW_SCALE_TOP)
return(0);
//--- draw
if(draw)
{
//--- draw line
Line(m_data_area.left,m_y_max,m_data_area.right,m_y_max,m_color_text);
}
//--- return height
return(size);
}
//+------------------------------------------------------------------+
//| Redraws bottom scale |
//+------------------------------------------------------------------+
int CChartCanvas::DrawScaleBottom(const bool draw)
{
int size=0;
//--- check flag
if(!IS_SHOW_SCALE_BOTTOM)
return(0);
//--- draw
if(draw)
{
//--- draw line
Line(m_data_area.left,m_y_min,m_data_area.right,m_y_min,m_color_text);
}
//--- return height
return(size);
}
//+------------------------------------------------------------------+
//| Redraws grid |
//+------------------------------------------------------------------+
void CChartCanvas::DrawGrid(void)
{
//--- check flag
if(!IS_SHOW_GRID)
return;
//--- variables
int x1=m_data_area.left;
int x2=m_data_area.right;
int y =m_y_min;
//--- draw
uint j=m_num_grid-((IS_SHOW_SCALE_TOP) ? 1 : 0);
if(IS_SHOW_SCALE_BOTTOM)
{
y-=m_dy_grid;
j--;
}
for(uint i=0;i<=j;i++,y-=m_dy_grid)
LineAA(x1,y,x2,y,m_color_grid,STYLE_DASH);
}
//+------------------------------------------------------------------+
//| Redraws data |
//+------------------------------------------------------------------+
void CChartCanvas::DrawChart(void)
{
for(uint i=0;i<m_data_total;i++)
DrawData(i);
}
//+------------------------------------------------------------------+