1043 lines
34 KiB
MQL5
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|