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);
| |||
}
| |||
//+------------------------------------------------------------------+
|