First commit [09/03/2018]
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,347 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| HistogramChart.mqh |
|
||||
//| Copyright 2009-2017, MetaQuotes Software Corp. |
|
||||
//| http://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartCanvas.mqh"
|
||||
#include <Arrays\ArrayObj.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CHistogramChart |
|
||||
//| Usage: generates histogram chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CHistogramChart : public CChartCanvas
|
||||
{
|
||||
private:
|
||||
//--- colors
|
||||
uint m_fill_brush[];
|
||||
//--- adjusted parameters
|
||||
bool m_gradient;
|
||||
uint m_bar_gap;
|
||||
uint m_bar_min_size;
|
||||
uint m_bar_border;
|
||||
//--- data
|
||||
CArrayObj *m_values;
|
||||
|
||||
public:
|
||||
CHistogramChart(void);
|
||||
~CHistogramChart(void);
|
||||
//--- create
|
||||
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE);
|
||||
//--- adjusted parameters
|
||||
void Gradient(const bool flag=true) { m_gradient=flag; }
|
||||
void BarGap(const uint value) { m_bar_gap=value; }
|
||||
void BarMinSize(const uint value) { m_bar_min_size=value; }
|
||||
void BarBorder(const uint value) { m_bar_border=value; }
|
||||
//--- data
|
||||
bool SeriesAdd(const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0);
|
||||
bool SeriesDelete(const uint pos);
|
||||
bool ValueUpdate(const uint series,const uint pos,double value);
|
||||
|
||||
protected:
|
||||
virtual void DrawData(const uint idx);
|
||||
void DrawBar(const int x,const int y,const int w,const int h,const uint clr);
|
||||
void GradientBrush(const int size,const uint fill_clr);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CHistogramChart::CHistogramChart(void) : m_gradient(true),
|
||||
m_bar_gap(3),
|
||||
m_bar_min_size(5),
|
||||
m_bar_border(0)
|
||||
{
|
||||
ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CHistogramChart::~CHistogramChart(void)
|
||||
{
|
||||
if(ArraySize(m_fill_brush)!=0)
|
||||
ArrayFree(m_fill_brush);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create dynamic resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
||||
{
|
||||
//--- create object to store data
|
||||
if((m_values=new CArrayObj)==NULL)
|
||||
return(false);
|
||||
//--- pass responsibility for its destruction to the parent class
|
||||
m_data=m_values;
|
||||
//--- call method of parent class
|
||||
if(!CChartCanvas::Create(name,width,height,clrfmt))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesAdd(const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
//--- add
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Add(arr))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
|
||||
return(false);
|
||||
if(!m_descriptors.Add(descr))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
//--- insert
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Insert(arr,pos))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Insert(descr,pos))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
CArrayDouble *data=m_values.At(pos);
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.AssignArray(value))
|
||||
return(false);
|
||||
if(clr!=0 && !m_colors.Update(pos,clr))
|
||||
return(false);
|
||||
if(descr!=NULL && !m_descriptors.Update(pos,descr))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::SeriesDelete(const uint pos)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total && m_data_total!=0)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(!m_values.Delete(pos))
|
||||
return(false);
|
||||
m_data_total--;
|
||||
if(!m_colors.Delete(pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Delete(pos))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates element in data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CHistogramChart::ValueUpdate(const uint series,const uint pos,double value)
|
||||
{
|
||||
CArrayDouble *data=m_values.At(series);
|
||||
//--- check
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.Update(pos,value))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws histogram |
|
||||
//+------------------------------------------------------------------+
|
||||
void CHistogramChart::DrawData(const uint idx)
|
||||
{
|
||||
double value=0.0;
|
||||
//--- check
|
||||
CArrayDouble *data=m_values.At(idx);
|
||||
if(data==NULL)
|
||||
return;
|
||||
int total=data.Total();
|
||||
if(total==0 || (int)idx>=total)
|
||||
return;
|
||||
//--- calculate
|
||||
int x1=m_data_area.left;
|
||||
int x2=m_data_area.right;
|
||||
int dx=(x2-x1)/total;
|
||||
uint clr=m_colors[idx];
|
||||
uint w=dx/m_data_total;
|
||||
if(w<m_bar_min_size)
|
||||
w=m_bar_min_size;
|
||||
int x=x1+(int)(m_bar_gap+w*idx);
|
||||
//--- set font
|
||||
string fontname;
|
||||
int fontsize=0;
|
||||
uint fontflags=0;
|
||||
uint fontangle=0;
|
||||
if(IS_SHOW_VALUE)
|
||||
{
|
||||
FontGet(fontname,fontsize,fontflags,fontangle);
|
||||
FontSet(fontname,-10*(w-3),fontflags,900);
|
||||
}
|
||||
//--- prepare gradient fill
|
||||
GradientBrush(w,clr);
|
||||
//--- draw
|
||||
for(int i=0;i<total;i++,x+=dx)
|
||||
{
|
||||
int y,h;
|
||||
double val=data[i];
|
||||
if(val==EMPTY_VALUE)
|
||||
continue;
|
||||
if(m_accumulative)
|
||||
value+=val;
|
||||
else
|
||||
value=val;
|
||||
// int val=(int)(value*m_scale_y);
|
||||
if(value>0)
|
||||
{
|
||||
y=(m_y_0-(int)(value*m_scale_y));
|
||||
h=m_y_0-y;
|
||||
}
|
||||
else
|
||||
{
|
||||
y=m_y_0;
|
||||
h=-(int)(value*m_scale_y);
|
||||
}
|
||||
DrawBar(x,y,w,h,clr);
|
||||
//--- draw text of value
|
||||
if(IS_SHOW_VALUE)
|
||||
{
|
||||
string text =DoubleToString(value,2);
|
||||
int width=(int)(TextWidth(text)+w);
|
||||
if(value>0)
|
||||
{
|
||||
if(width>y-m_y_max)
|
||||
TextOut(x+w/2,y+w,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
else
|
||||
TextOut(x+w/2,y-w,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(width>m_y_min-y-h)
|
||||
TextOut(x+w/2,y+h-w,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
else
|
||||
TextOut(x+w/2,y+h+w,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(IS_SHOW_VALUE)
|
||||
FontSet(fontname,fontsize,fontflags,fontangle);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws bar |
|
||||
//+------------------------------------------------------------------+
|
||||
void CHistogramChart::DrawBar(const int x,const int y,const int w,const int h,const uint clr)
|
||||
{
|
||||
//--- draw bar
|
||||
if(!m_gradient || ArraySize(m_fill_brush)<w)
|
||||
FillRectangle(x+1,y+1,w-x-2,h-y-2,clr);
|
||||
else
|
||||
{
|
||||
for(int i=1;i<h;i++)
|
||||
ArrayCopy(m_pixels,m_fill_brush,(y+i)*m_width+x+1,0,w);
|
||||
}
|
||||
//--- draw bar border
|
||||
if(m_bar_border!=0)
|
||||
Rectangle(x,y,x+w-1,y+h-1,m_color_border);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Creates brush for gradient fill |
|
||||
//+------------------------------------------------------------------+
|
||||
void CHistogramChart::GradientBrush(const int size,const uint fill_clr)
|
||||
{
|
||||
//--- to prepare gradient fill, we will use Bresenham's circle algorithm
|
||||
//--- X coordinate - size of the fill,
|
||||
//--- Y coordinate - color brightness
|
||||
if(m_gradient)
|
||||
{
|
||||
//--- adjust gradient radius if necessary
|
||||
int r=size;
|
||||
//--- check
|
||||
if(r<1)
|
||||
return;
|
||||
if(r!=ArrayResize(m_fill_brush,r))
|
||||
return;
|
||||
//--- initialize brush
|
||||
ArrayInitialize(m_fill_brush,m_color_background);
|
||||
//--- variables
|
||||
int f =1-r;
|
||||
int dd_x=1;
|
||||
int dd_y=-2*r;
|
||||
int dx =0;
|
||||
int dy =r;
|
||||
int i1,i2;
|
||||
uint clr,dclr;
|
||||
//---
|
||||
i1=i2=r>>1;
|
||||
if((r&1)==0)
|
||||
i1--;
|
||||
//--- calculate
|
||||
while(dy>=dx)
|
||||
{
|
||||
clr=fill_clr;
|
||||
dclr=GETRGB(XRGB((r-dy)*GETRGBR(clr)/r,(r-dy)*GETRGBG(clr)/r,(r-dy)*GETRGBB(clr)/r));
|
||||
clr-=dclr;
|
||||
m_fill_brush[i1]=clr;
|
||||
m_fill_brush[i2]=clr;
|
||||
//---
|
||||
if(f>=0)
|
||||
{
|
||||
dy--;
|
||||
dd_y+=2;
|
||||
f+=dd_y;
|
||||
}
|
||||
dx++;
|
||||
if(--i1<0)
|
||||
break;
|
||||
i2++;
|
||||
dd_x+=2;
|
||||
f+=dd_x;
|
||||
}
|
||||
}
|
||||
else
|
||||
ArrayFree(m_fill_brush);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,383 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| LineChart.mqh |
|
||||
//| Copyright 2009-2017, MetaQuotes Software Corp. |
|
||||
//| http://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartCanvas.mqh"
|
||||
#include <Arrays\ArrayObj.mqh>
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CLineChart |
|
||||
//| Usage: generates line chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CLineChart : public CChartCanvas
|
||||
{
|
||||
private:
|
||||
//--- data
|
||||
CArrayObj *m_values;
|
||||
//--- adjusted parameters
|
||||
bool m_filled;
|
||||
|
||||
public:
|
||||
CLineChart(void);
|
||||
~CLineChart(void);
|
||||
//--- create
|
||||
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_ARGB_NORMALIZE);
|
||||
//--- adjusted parameters
|
||||
void Filled(const bool flag=true) { m_filled=flag; }
|
||||
//--- set up
|
||||
bool SeriesAdd(const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesInsert(const uint pos,const double &value[],const string descr="",const uint clr=0);
|
||||
bool SeriesUpdate(const uint pos,const double &value[],const string descr=NULL,const uint clr=0);
|
||||
bool SeriesDelete(const uint pos);
|
||||
bool ValueUpdate(const uint series,const uint pos,double value);
|
||||
|
||||
protected:
|
||||
virtual void DrawChart(void);
|
||||
virtual void DrawData(const uint index=0);
|
||||
|
||||
private:
|
||||
double CalcArea(const uint index);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CLineChart::CLineChart(void) : m_filled(false)
|
||||
{
|
||||
ShowFlags(FLAG_SHOW_LEGEND|FLAGS_SHOW_SCALES|FLAG_SHOW_GRID);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CLineChart::~CLineChart(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create dynamic resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
||||
{
|
||||
//--- create object to store data
|
||||
if((m_values=new CArrayObj)==NULL)
|
||||
return(false);
|
||||
//--- pass responsibility for its destruction to the parent class
|
||||
m_data=m_values;
|
||||
//--- call method of parent class
|
||||
if(!CChartCanvas::Create(name,width,height,clrfmt))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesAdd(const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
//--- add
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Add(arr))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
|
||||
return(false);
|
||||
if(!m_descriptors.Add(descr))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesInsert(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==m_max_data)
|
||||
return(false);
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
//--- insert
|
||||
CArrayDouble *arr=new CArrayDouble;
|
||||
if(!m_values.Insert(arr,pos))
|
||||
return(false);
|
||||
if(!arr.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Insert(descr,pos))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesUpdate(const uint pos,const double &value[],const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total)
|
||||
return(false);
|
||||
CArrayDouble *data=m_values.At(pos);
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.AssignArray(value))
|
||||
return(false);
|
||||
if(clr!=0 && !m_colors.Update(pos,clr))
|
||||
return(false);
|
||||
if(descr!=NULL && !m_descriptors.Update(pos,descr))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::SeriesDelete(const uint pos)
|
||||
{
|
||||
//--- check
|
||||
if(pos>=m_data_total && m_data_total!=0)
|
||||
return(false);
|
||||
//--- delete
|
||||
if(!m_values.Delete(pos))
|
||||
return(false);
|
||||
m_data_total--;
|
||||
if(!m_colors.Delete(pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Delete(pos))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates element in data series |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CLineChart::ValueUpdate(const uint series,const uint pos,double value)
|
||||
{
|
||||
CArrayDouble *data=m_values.At(series);
|
||||
//--- check
|
||||
if(data==NULL)
|
||||
return(false);
|
||||
//--- update
|
||||
if(!data.Update(pos,value))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Redraws data |
|
||||
//+------------------------------------------------------------------+
|
||||
void CLineChart::DrawChart(void)
|
||||
{
|
||||
if(m_filled)
|
||||
{
|
||||
//--- calculate areas of filling
|
||||
double s[];
|
||||
ArrayResize(s,m_data_total);
|
||||
ArrayInitialize(s,0);
|
||||
for(uint i=0;i<m_data_total;i++)
|
||||
{
|
||||
CArrayDouble *data=m_values.At(i);
|
||||
if(data==NULL)
|
||||
continue;
|
||||
int total=data.Total();
|
||||
if(total<=1)
|
||||
continue;
|
||||
s[i]=CalcArea(i);
|
||||
}
|
||||
int index=ArrayMaximum(s);
|
||||
while(index!=-1 && s[index]!=0.0)
|
||||
{
|
||||
//--- draw in area descending order
|
||||
DrawData(index);
|
||||
s[index]=0.0;
|
||||
index=ArrayMaximum(s);
|
||||
}
|
||||
}
|
||||
else
|
||||
for(uint i=0;i<m_data_total;i++)
|
||||
DrawData(i);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws lines |
|
||||
//+------------------------------------------------------------------+
|
||||
void CLineChart::DrawData(const uint index)
|
||||
{
|
||||
double value=0.0;
|
||||
//--- check
|
||||
CArrayDouble *data=m_values.At(index);
|
||||
if(data==NULL)
|
||||
return;
|
||||
int total=data.Total();
|
||||
if(total<=1)
|
||||
return;
|
||||
//--- calculate
|
||||
int dx=m_data_area.Width()/(total-1);
|
||||
int x=m_data_area.left+1;
|
||||
int y1=0;
|
||||
int y2=(int)(m_y_0-data[0]*m_scale_y);
|
||||
//--- draw
|
||||
for(int i=1;i<total;i++,x+=dx)
|
||||
{
|
||||
y1=y2;
|
||||
double val=data[i];
|
||||
if(val==EMPTY_VALUE)
|
||||
continue;
|
||||
if(m_accumulative)
|
||||
value+=val;
|
||||
else
|
||||
value=val;
|
||||
y2=(int)(m_y_0-value*m_scale_y);
|
||||
if(m_filled)
|
||||
{
|
||||
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_y_0))
|
||||
{
|
||||
//--- draw two triangles
|
||||
int x3;
|
||||
if(y1>y2)
|
||||
{
|
||||
x3=x+dx*(y1-m_y_0)/(y1-y2);
|
||||
FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]);
|
||||
FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
x3=x+dx*(m_y_0-y1)/(y2-y1);
|
||||
FillTriangle(x,y1,x3,m_y_0,x,m_y_0,(uint)m_colors[index]);
|
||||
FillTriangle(x+dx,y2,x3,m_y_0,x+dx,m_y_0,(uint)m_colors[index]);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(y1<m_y_0 || y2<m_y_0)
|
||||
{
|
||||
if(y1>y2)
|
||||
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
|
||||
if(y1<y2)
|
||||
{
|
||||
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
|
||||
y1=y2;
|
||||
}
|
||||
}
|
||||
if(y1>m_y_0 || y2>m_y_0)
|
||||
{
|
||||
if(y1<y2)
|
||||
FillTriangle(x,y1,x+dx,y2,x+dx,y1,(uint)m_colors[index]);
|
||||
if(y1>y2)
|
||||
{
|
||||
FillTriangle(x,y1,x+dx,y2,x,y2,(uint)m_colors[index]);
|
||||
y1=y2;
|
||||
}
|
||||
}
|
||||
FillRectangle(x,m_y_0,x+dx,y1,(uint)m_colors[index]);
|
||||
}
|
||||
else
|
||||
LineAA(x,y1,x+dx,y2,(uint)m_colors[index],STYLE_SOLID);
|
||||
}
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Area of filling |
|
||||
//+------------------------------------------------------------------+
|
||||
double CLineChart::CalcArea(const uint index)
|
||||
{
|
||||
double area =0;
|
||||
double value=0;
|
||||
int dx =100;
|
||||
//---
|
||||
CArrayDouble *data=m_values.At(index);
|
||||
if(data==NULL)
|
||||
return(0);
|
||||
int total=data.Total();
|
||||
if(total<=1)
|
||||
return(0);
|
||||
int y1=0;
|
||||
int y2=(int)(m_y_0-data[0]*m_scale_y);
|
||||
for(int i=0;i<total;i++)
|
||||
{
|
||||
y1=y2;
|
||||
double val=data[i];
|
||||
if(val==EMPTY_VALUE)
|
||||
continue;
|
||||
if(m_accumulative)
|
||||
value+=val;
|
||||
else
|
||||
value=val;
|
||||
y2=(int)(m_y_0-value*m_scale_y);
|
||||
if((y1>m_y_0 && y2<m_y_0) || (y1<m_y_0 && y2>m_y_0))
|
||||
{
|
||||
//--- line of values crosses the Y axis
|
||||
int x;
|
||||
if(y1>y2)
|
||||
{
|
||||
//--- from the bottom up
|
||||
x=dx*(y1-m_y_0)/(y1-y2);
|
||||
//--- add area of lower triangle
|
||||
area+=x*(y1-m_y_0)/2;
|
||||
//--- add area of upper triangle
|
||||
area+=(dx-x)*(m_y_0-y2)/2;
|
||||
}
|
||||
else
|
||||
{
|
||||
//--- from top down
|
||||
x=dx*(m_y_0-y1)/(y2-y1);
|
||||
//--- add area of upper triangle
|
||||
area+=x*(m_y_0-y1)/2;
|
||||
//--- add area of lower triangle
|
||||
area+=(dx-x)*(y2-m_y_0)/2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(y1<m_y_0 || y2<m_y_0)
|
||||
{
|
||||
//--- both values are greater than zero
|
||||
if(y1>y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y1-y2)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(m_y_0-y2);
|
||||
}
|
||||
if(y1<y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y2-y1)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(m_y_0-y1);
|
||||
}
|
||||
}
|
||||
if(y1>m_y_0 || y2>m_y_0)
|
||||
{
|
||||
//--- both values are less than zero
|
||||
if(y1<y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y2-y1)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(y1-m_y_0);
|
||||
}
|
||||
if(y1>y2)
|
||||
{
|
||||
//--- add area of triangle
|
||||
area+=dx*(y1-y2)/2;
|
||||
//--- add area of rectangle
|
||||
area+=dx*(y2-m_y_0);
|
||||
}
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(area);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
@@ -0,0 +1,414 @@
|
||||
//+------------------------------------------------------------------+
|
||||
//| PieChart.mqh |
|
||||
//| Copyright 2009-2017, MetaQuotes Software Corp. |
|
||||
//| http://www.mql5.com |
|
||||
//+------------------------------------------------------------------+
|
||||
#include "ChartCanvas.mqh"
|
||||
//+------------------------------------------------------------------+
|
||||
//| Class CPieChart |
|
||||
//| Usage: generates pie chart |
|
||||
//+------------------------------------------------------------------+
|
||||
class CPieChart : public CChartCanvas
|
||||
{
|
||||
private:
|
||||
//--- data
|
||||
CArrayDouble *m_values;
|
||||
//--- for draw
|
||||
int m_x0;
|
||||
int m_y0;
|
||||
int m_r;
|
||||
|
||||
public:
|
||||
CPieChart(void);
|
||||
~CPieChart(void);
|
||||
//--- create
|
||||
virtual bool Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt=COLOR_FORMAT_XRGB_NOALPHA);
|
||||
//--- data
|
||||
bool SeriesSet(const double &value[],const string &text[],const uint &clr[]);
|
||||
bool ValueAdd(const double value,const string descr="",const uint clr=0);
|
||||
bool ValueInsert(const uint pos,const double value,const string descr="",const uint clr=0);
|
||||
bool ValueUpdate(const uint pos,const double value,const string descr=NULL,const uint clr=0);
|
||||
bool ValueDelete(const uint pos);
|
||||
|
||||
protected:
|
||||
virtual void DrawChart(void);
|
||||
void DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr);
|
||||
string LabelMake(const string text,const double value,const bool to_left);
|
||||
};
|
||||
//+------------------------------------------------------------------+
|
||||
//| Constructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPieChart::CPieChart(void)
|
||||
{
|
||||
uint flags=FLAG_SHOW_LEGEND|FLAG_SHOW_DESCRIPTORS|FLAG_SHOW_VALUE|FLAG_SHOW_PERCENT;
|
||||
AllowedShowFlags(flags);
|
||||
ShowFlags(flags);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Destructor |
|
||||
//+------------------------------------------------------------------+
|
||||
CPieChart::~CPieChart(void)
|
||||
{
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Create dynamic resource |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::Create(const string name,const int width,const int height,ENUM_COLOR_FORMAT clrfmt)
|
||||
{
|
||||
//--- create object to store data
|
||||
if((m_values=new CArrayDouble)==NULL)
|
||||
return(false);
|
||||
//--- pass responsibility for its destruction to the parent class
|
||||
m_data=m_values;
|
||||
//--- call method of parent class
|
||||
if(!CChartCanvas::Create(name,width,height,clrfmt))
|
||||
return(false);
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Sets displayed parameters |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::SeriesSet(const double &value[],const string &text[],const uint &clr[])
|
||||
{
|
||||
//--- !!! user is responsible for correct filling of arrays !!!
|
||||
//--- check
|
||||
if(m_values==NULL)
|
||||
return(false);
|
||||
//--- set
|
||||
if(!m_values.AssignArray(value))
|
||||
return(false);
|
||||
if(!m_descriptors.AssignArray(text))
|
||||
return(false);
|
||||
if(!m_colors.AssignArray(clr))
|
||||
return(false);
|
||||
m_data_total=m_values.Total();
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Adds displayed parameter (to the end) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueAdd(const double value,const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if((value<=0))
|
||||
return(false);
|
||||
//--- add
|
||||
if(!m_values.Add(value))
|
||||
return(false);
|
||||
if(!m_descriptors.Add(descr))
|
||||
return(false);
|
||||
if(!m_colors.Add((clr==0) ? GetDefaultColor(m_data_total) : clr))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Inserts displayed parameter (to specified position) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueInsert(const uint pos,const double value,const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if((value<=0))
|
||||
return(false);
|
||||
//--- insert
|
||||
if(!m_values.Insert(value,pos))
|
||||
return(false);
|
||||
if(!m_descriptors.Insert(descr,pos))
|
||||
return(false);
|
||||
if(!m_colors.Insert((clr==0) ? GetDefaultColor(m_data_total) : clr,pos))
|
||||
return(false);
|
||||
m_data_total++;
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Updates displayed parameter (in specified position) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueUpdate(const uint pos,const double value,const string descr,const uint clr)
|
||||
{
|
||||
//--- check
|
||||
if((value<=0))
|
||||
return(false);
|
||||
//--- update
|
||||
if(!m_values.Update(pos,value))
|
||||
return(false);
|
||||
if(descr!=NULL && !m_descriptors.Update(pos,descr))
|
||||
return(false);
|
||||
if(clr!=0 && !m_colors.Update(pos,clr))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Deletes displayed parameter (from specified position) |
|
||||
//+------------------------------------------------------------------+
|
||||
bool CPieChart::ValueDelete(const uint pos)
|
||||
{
|
||||
//--- delete
|
||||
if(!m_values.Delete(pos))
|
||||
return(false);
|
||||
m_data_total--;
|
||||
if(!m_descriptors.Delete(pos))
|
||||
return(false);
|
||||
if(!m_colors.Delete(pos))
|
||||
return(false);
|
||||
//--- redraw
|
||||
Redraw();
|
||||
//--- succeed
|
||||
return(true);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draws |
|
||||
//+------------------------------------------------------------------+
|
||||
void CPieChart::DrawChart(void)
|
||||
{
|
||||
//--- check
|
||||
if(m_data_total==0)
|
||||
return;
|
||||
//--- variables
|
||||
string text="";
|
||||
double angle=M_PI*(m_data_offset%360)/180;
|
||||
int width,height;
|
||||
int dw=0;
|
||||
int dh=0;
|
||||
int index;
|
||||
CPoint p0[];
|
||||
CPoint p1[];
|
||||
//--- calculate geometry
|
||||
width =(m_data_area.Width()<<3)/10;
|
||||
height=(m_data_area.Height()<<3)/10;
|
||||
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
dw=(int)m_max_value_width;
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
dw=TextWidth("100.00%");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
dw=(int)m_max_value_width+TextWidth(" ()");
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
dw=TextWidth(" (100.00%)");
|
||||
}
|
||||
dw+=(int)m_max_descr_width;
|
||||
}
|
||||
}
|
||||
//--- pie chart will always be round
|
||||
width -=2*dw+10;
|
||||
height-=20;
|
||||
m_x0=m_data_area.left+(m_data_area.Width()>>1);
|
||||
m_y0=m_data_area.top+(m_data_area.Height()>>1);
|
||||
m_r =(((width>height) ? height : width)>>1);
|
||||
//--- draw pie chart
|
||||
if(ArrayResize(p0,m_data_total+1)==-1)
|
||||
return;
|
||||
if(m_data_total==1)
|
||||
{
|
||||
FillCircle(m_x0,m_y0,m_r,m_colors[0]);
|
||||
Circle(m_x0,m_y0,m_r,m_color_border);
|
||||
}
|
||||
else
|
||||
{
|
||||
Circle(m_x0,m_y0,m_r,m_color_border);
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
{
|
||||
index=m_index[i];
|
||||
double val=m_values[index];
|
||||
double d_a=2*M_PI*val/m_sum;
|
||||
DrawPie(angle,angle+d_a,i,p0,m_colors[index]);
|
||||
angle+=d_a;
|
||||
angle=MathMod(angle,2*M_PI);
|
||||
}
|
||||
if(m_data_total!=m_index_size)
|
||||
DrawPie(angle,angle+2*M_PI*m_others/m_sum,m_index_size,p0,COLOR2RGB(clrBlack));
|
||||
for(uint i=0;i<=m_index_size;i++)
|
||||
Line(m_x0,m_y0,p0[i].x,p0[i].y,m_color_border);
|
||||
Circle(m_x0,m_y0,m_r,m_color_border);
|
||||
}
|
||||
//--- draw descriptors
|
||||
angle=M_PI*(m_data_offset%360)/180;
|
||||
int r1=(int)round(1.1*m_r);
|
||||
if(ArrayResize(p1,m_data_total)==-1)
|
||||
return;
|
||||
//--- calculations
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
{
|
||||
index=m_index[i];
|
||||
angle+=M_PI*m_values[index]/m_sum;
|
||||
//--- lines
|
||||
p0[i].x=m_x0+(int)round(m_r*cos(angle));
|
||||
p0[i].y=m_y0-(int)round(m_r*sin(angle));
|
||||
p1[i].x=m_x0+(int)round(r1*cos(angle));
|
||||
p1[i].y=m_y0-(int)round(r1*sin(angle));
|
||||
angle+=M_PI*m_values[index]/m_sum;
|
||||
}
|
||||
if(m_data_total!=m_index_size)
|
||||
{
|
||||
index=(int)m_data_total-1;
|
||||
angle+=M_PI*m_others/m_sum;
|
||||
p0[index].x=m_x0+(int)round(m_r*cos(angle));
|
||||
p0[index].y=m_y0-(int)round(m_r*sin(angle));
|
||||
p1[index].x=m_x0+(int)round(r1*cos(angle));
|
||||
p1[index].y=m_y0-(int)round(r1*sin(angle));
|
||||
}
|
||||
int x,y;
|
||||
//--- draw descriptors to the left
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
if(p0[i].x<m_x0)
|
||||
{
|
||||
x=p1[i].x-10;
|
||||
y=p1[i].y;
|
||||
index=m_index[i];
|
||||
text=LabelMake(m_descriptors[index],m_values[index],true);
|
||||
if(text!="")
|
||||
{
|
||||
Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border);
|
||||
Line(p1[i].x,p1[i].y,x,y,m_color_border);
|
||||
TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
}
|
||||
}
|
||||
//--- draw descriptors to the right
|
||||
for(uint i=0;i<m_index_size;i++)
|
||||
if(p0[i].x>=m_x0)
|
||||
{
|
||||
x=p1[i].x+10;
|
||||
y=p1[i].y;
|
||||
index=m_index[i];
|
||||
text=LabelMake(m_descriptors[index],m_values[index],false);
|
||||
if(text!="")
|
||||
{
|
||||
Line(p0[i].x,p0[i].y,p1[i].x,p1[i].y,m_color_border);
|
||||
Line(p1[i].x,p1[i].y,x,y,m_color_border);
|
||||
TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
}
|
||||
}
|
||||
if(m_data_total!=m_index_size)
|
||||
{
|
||||
index=(int)m_data_total-1;
|
||||
if(p0[index].x>=m_x0)
|
||||
{
|
||||
x=p1[index].x+10;
|
||||
y=p1[index].y;
|
||||
text=LabelMake("Others",m_others,true);
|
||||
TextOut(x+5,y,text,m_color_text,TA_LEFT|TA_VCENTER);
|
||||
}
|
||||
else
|
||||
{
|
||||
x=p1[index].x-10;
|
||||
y=p1[index].y;
|
||||
text=LabelMake("Others",m_others,false);
|
||||
TextOut(x-5,y,text,m_color_text,TA_RIGHT|TA_VCENTER);
|
||||
}
|
||||
if(text!="")
|
||||
{
|
||||
Line(p0[index].x,p0[index].y,p1[index].x,p1[index].y,m_color_border);
|
||||
Line(p1[index].x,p1[index].y,x,y,m_color_border);
|
||||
}
|
||||
}
|
||||
ArrayFree(p1);
|
||||
ArrayFree(p0);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Draw pie |
|
||||
//+------------------------------------------------------------------+
|
||||
void CPieChart::DrawPie(double fi3,double fi4,int idx,CPoint &p[],const uint clr)
|
||||
{
|
||||
//--- draw arc
|
||||
Arc(m_x0,m_y0,m_r,m_r,fi3,fi4,p[idx].x,p[idx].y,p[idx+1].x,p[idx+1].y,clr);
|
||||
//--- variables
|
||||
int x3=p[idx].x;
|
||||
int y3=p[idx].y;
|
||||
int x4=p[idx+1].x;
|
||||
int y4=p[idx+1].y;
|
||||
//--- draw radii
|
||||
if(idx==0)
|
||||
Line(m_x0,m_y0,x3,y3,clr);
|
||||
if(idx!=m_data_total-1)
|
||||
Line(m_x0,m_y0,x4,y4,clr);
|
||||
//--- fill
|
||||
double fi=(fi3+fi4)/2;
|
||||
int xf=m_x0+(int)(0.99*m_r*cos(fi));
|
||||
int yf=m_y0-(int)(0.99*m_r*sin(fi));
|
||||
Fill(xf,yf,clr);
|
||||
//--- for small pie
|
||||
if(fi4-fi3<=M_PI_4)
|
||||
Line(m_x0,m_y0,xf,yf,clr);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
//| Make label for pie |
|
||||
//+------------------------------------------------------------------+
|
||||
string CPieChart::LabelMake(const string text,const double value,const bool to_left)
|
||||
{
|
||||
string label="";
|
||||
//---
|
||||
if(to_left)
|
||||
{
|
||||
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
label=DoubleToString(value,2);
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label=DoubleToString(100*value/m_sum,2)+"%";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
label=text;
|
||||
if(IS_SHOW_VALUE)
|
||||
label+=" ("+DoubleToString(value,2)+")";
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label+=" ("+DoubleToString(100*value/m_sum,2)+"%)";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_LEGEND || !IS_SHOW_DESCRIPTORS)
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
label=DoubleToString(value,2);
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label=DoubleToString(100*value/m_sum,2)+"%";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_VALUE)
|
||||
label="("+DoubleToString(value,2)+") ";
|
||||
else
|
||||
{
|
||||
if(IS_SHOW_PERCENT)
|
||||
label="("+DoubleToString(100*value/m_sum,2)+"%) ";
|
||||
}
|
||||
label+=text;
|
||||
}
|
||||
}
|
||||
//---
|
||||
return(label);
|
||||
}
|
||||
//+------------------------------------------------------------------+
|
||||
Reference in New Issue
Block a user