In part 5 of this series of Tutorials I want to talk about 3D Bar Charts.
As usual I will post the code and then explain everything.
ChartKM.h
//ChartKM.h
#ifndef CHARTKM_H_INCLUDED
#define CHARTKM_H_INCLUDED
#include <vector>
#include <cstring>
#include <Windows.h>
#ifndef MSVC
#define CLEARTYPE_QUALITY 5
#define CLEARTYPE_NATURAL_QUALITY 6
#endif
using namespace std;
class chartObject
{
protected:
int Total;
float Units;
float Degrees;
vector<float> Percentage;
float a;
float x2;
float y2;
float ValueItem;
unsigned FreqBar;
float LargestBar;
int szNames;
int szInfo;
int szGroup;
string xName;
string yName;
BOOL vLegend;
string Title;
vector<string> Names;
vector <float> Info;
vector <float> Frequency;
vector <float> b;
vector <COLORREF> colors;
vector <string> GroupName;
vector <string> ItemName;
vector <float> ItemValue;
vector <float> LineValueX;
vector <float> LineValueY;
float LineRangeX;
float LineRangeY;
vector <int> ItemGroup;
public:
//constructor
chartObject();
//destructor
~chartObject();
//Draws Pie Chart
void DrawPie(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor);
//Draws Bar Chart
void DrawBar(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);
//Draws Line Chart
void DrawLine(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);
//Adds Data for Pie Chart
void AddData(string Labels, float Data, COLORREF color);
//Adds Group Data for Bar and Line Charts
void AddGroupData(string nmGroup, COLORREF color);
// Adds Item Data for Bar Charts
void AddItemData(string nmItem, float value, int GroupNo);
// Adds Item Data for Line Charts
void AddLineData(string nmItem, float valueX, float valueY);
// Adds Group and Range Data for Line Charts
void AddRangeData(float RangeX, float RangeY, int GroupNo);
// Gets the Totals for Pie Charts
int GetTotal();
// Gets the frequency for Pie Charts
void GetFrequency();
// Adds a Title to Chart;
void AddTitle(string szTitle);
// Adds a Legend to a Pie Chart
void Legend(BOOL szLegend);
// Add Titles for x and y axis
void SetAxisTitles(string szAxisX, string szAxisY);
// Get Total for Bars
void GetTotalBar();
// Get Amount of Groups for Bars
void GetGroupBar();
// Get Largest Amount Of Item Data for Bars
void GetLargestBar();
};
class chart3D:public chartObject {
public:
void DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor);
void DrawBar3D(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);
};
#endif
ChartKM.cpp
#include <Windows.h>
#include <cmath>
#include <iomanip>
#include <sstream>
#ifdef MSVC
#pragma comment(lib, "libGdi32.a")// link to gdi functions
#endif
#define round(a)(int(a+0.5))
//we need this for windows stuff.
#include "ChartKM.h"
chartObject::chartObject()
{
szNames =0;
szInfo = 0;
Total =0;
Degrees = 0;
Title = "";
a = 0;
x2 = 0;
y2 = 0;
szNames = 0;
szInfo = 0;
vLegend = TRUE;
ValueItem = 0;
Units = 0.0f;
ItemValue.clear();
ItemName.clear();
GroupName.clear();
}
chartObject::~chartObject()
{
}
void chartObject::DrawPie(HDC hdcDst,int x, int y,int szPieX, int szPieY,COLORREF bkcolor)
{
float xr = 0.0f;
float yr = 0.0f;
float Degrees2 =0.0f;
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
HFONT font;
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
SelectObject(hdcDst,pen);
//Draw Circle
Arc(hdcDst, x,y,szPieX+x,szPieY+y,x,y,x,y);
//Draw First Line
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
LineTo(hdcDst,szPieX+x,(szPieY/2)+y);
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
//Gets Totals for Pie Chart
Total = GetTotal();
GetFrequency();
//Draw Lines of arc
float radius = szPieX/2.0f;
float yradius = szPieY/2.0f;
//float y1= 0.0f;
//Draw segments
for(int j = 0; j<szInfo; j++)
{
HBRUSH hbr = CreateSolidBrush(colors[j]);
SelectObject(hdcDst,hbr);
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
Percentage.push_back( Frequency[j]*100 );
a = Frequency[j]*360;
if(j==0)
b.push_back(a);
else
b.push_back(b[j-1]+a);
Degrees= (float)(3.14*b[j])/180;
x2=(((szPieX/2)+x)+radius*cos(Degrees));
y2=(((szPieY/2)+y)-yradius*sin(Degrees));
LineTo(hdcDst,round(x2),round(y2));
//Fill Segments
//Fill Pie
if(j==0)
{
Degrees2 = (float)(3.14*(a/2))/180;
}
else
{
Degrees2= (float)(3.14*(b[j-1]+(a/2)))/180;
}
xr = (((szPieX/2)+x)+(radius/2)*cos(Degrees2));
yr = (((szPieY/2)+y)-(yradius/2)*sin(Degrees2));
SelectObject(hdcDst,hbr);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}
if(Title !="")
{
TextOut(hdcDst,(x+szPieX/2)-(Title.length()*2)-Title.size(),y-24,Title.c_str(),Title.size());
}
if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szPieX+15,y,"Legend",6);
string buffer;
stringstream sbuf;
char buf[20];
float d = 0.0f;
for(int i = 0; i<szNames; i++)
{
buffer = "";
sbuf.clear();
d = Info[i];
// write strings
buffer.append(Names[i]);
buffer.append(" ");
sbuf << d;
sbuf >> buf;
buffer.append(buf);
TextOut(hdcDst,x+szPieX+40,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szPieX+15,y+(25*(i+1)),x+szPieX+28,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szPieX+16;
rc.top = y+(25*(i+1))+1;
rc.right = x+szPieX+28-1;
rc.bottom = y+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);
FillRect(hdcDst,&rc,hbr);
}
}
DeleteObject(pen);
DeleteObject(font);
}
void chartObject::AddData(string Labels, float Data, COLORREF color)
{
Names.push_back(Labels);
szNames = Names.size();
Info.push_back(Data);
szInfo = Info.size();
colors.push_back(color);
}
int chartObject::GetTotal()
{
float Totals=0.0f;
for(int i = 0; i<szInfo; i++)
{
Totals =Totals + Info[i];
}
return (int) (Totals+0.5);
}
void chartObject::GetFrequency()
{
float result;
for(int i = 0; i<szInfo; i++)
{
result = Info[i]/Total;
Frequency.push_back(result) ;
}
return;
}
void chartObject::AddTitle(string szTitle)
{
Title.assign(szTitle);
}
void chartObject::Legend(BOOL szLegend)
{
vLegend = szLegend;
}
void chartObject::AddGroupData(string nmGroup, COLORREF color)
{
GroupName.push_back(nmGroup);
colors.push_back(color);
}
void chartObject::AddItemData(string nmItem, float value, int GroupNo)
{
ItemName.push_back(nmItem);
ItemValue.push_back(value);
ItemGroup.push_back(GroupNo);
}
void chartObject::SetAxisTitles(string szAxisX, string szAxisY)
{
xName.assign(szAxisX);
yName.assign(szAxisY);
}
void chartObject::GetTotalBar()
{
for(unsigned i = 0; i<ItemValue.size(); i++)
{
ValueItem = ValueItem+ItemValue[i];
}
ValueItem = ValueItem / (ItemValue.size()+1);
}
void chartObject::GetGroupBar()
{
FreqBar = GroupName.size();
}
void chartObject::GetLargestBar()
{
LargestBar = ItemValue[0];
for(unsigned i =1; i<ItemValue.size(); i++)
{
if(LargestBar<ItemValue[i])
{
LargestBar = ItemValue[i];
}
}
}
void chartObject::DrawBar(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
SelectObject(hdcDst,pen);
HFONT font;
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
//Draw y axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,x+25+14,y);
//Draw x axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,szBarX+x+25+14,(szBarY)+y);
TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
TextOut(hdcDst,((szBarX-x)/2)-(xName.length()/2),y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
TextOut(hdcDst,x+(25),y+szBarY,"0",1);// Draw a zero at origin
TextOut(hdcDst,((szBarX-x)/2)-(Title.length()/2),y-24,Title.c_str(),Title.length());//Draw Title
//Get Totals for Bar Chart
GetTotalBar();
GetGroupBar();
GetLargestBar();
//Draw Graph
Units = LargestBar/3.0f;
int graph = szBarY/3;
for(int i = 0; i<3; i++)
{
MoveToEx(hdcDst,x+25+14,(graph*i)+y,NULL);
LineTo(hdcDst,x+25+14+szBarX+5,(graph*i)+y);
stringstream number;
number << setprecision(3);
number << (LargestBar-(Units*i));
string num = "";
number >> num;
TextOut(hdcDst,x+25+14+szBarX+7,(graph*i)+y,num.c_str(),num.length());//draw numbers
}
for(unsigned i= 0; i<GroupName.size(); i++)
{
//draw Legend
Rectangle(hdcDst,(x+50-12-1),y+szBarY+42+(25*(i+1)-1),(x+50-12-1+12),y+szBarY+42+(25*(i+1)+12));
RECT rc;
rc.left= (x+50-12);
rc.top = y+szBarY+42+(25*(i+1));
rc.right = (x+50)-2;
rc.bottom = y+szBarY+42+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);
FillRect(hdcDst,&rc,hbr);
TextOut(hdcDst,(x)+(GroupName[i].length()+50),y+szBarY+42+(25*(i+1)),GroupName[i].c_str(),GroupName[i].length());//Drawlabels
}
MoveToEx(hdcDst,x+25+14+szBarX,(y+szBarY),NULL);
LineTo(hdcDst,x+25+14+szBarX,(y+szBarY+15));
MoveToEx(hdcDst,x+25+14+szBarX,y,NULL);
LineTo(hdcDst,x+25+14+szBarX,y+szBarY);
int amt = (ItemValue.size())/(GroupName.size());
int sections = (szBarX)/amt;
int counter = 0;
int count = 0;
// Draw Bar Data
for(unsigned i =0; i<(ItemValue.size()); i=i+GroupName.size())
{
counter = (i/GroupName.size())* sections;
MoveToEx(hdcDst,x+25+14+counter,(y+szBarY),NULL);
LineTo(hdcDst,x+25+14+counter,(y+szBarY+15));
TextOut(hdcDst,(x+25+14+counter)+(ItemName[i].length()),(y+szBarY+15),ItemName[i].c_str(),ItemName[i].length());
for(unsigned j = 0; j<(GroupName.size()); j++)
{
RECT rect;
float result = szBarY-(szBarY*(ItemValue[count]/LargestBar))+y;
rect.bottom = y+szBarY;
rect.right = x+25+14+counter+5+((szBarX/20)*(j+1));
rect.top = (LONG)(result);
rect.left = (x+25+14+counter+5+((szBarX/20)*j));
HBRUSH hbr = CreateSolidBrush(colors[j]);
FillRect(hdcDst,&rect,hbr);
count++;
}
}
DeleteObject(pen);
DeleteObject(font);
}
void chartObject::AddLineData(string nmItem, float valueX, float valueY)
{
ItemName.push_back(nmItem);
LineValueX.push_back(valueX);
LineValueY.push_back(valueY);
}
void chartObject::AddRangeData(float RangeX, float RangeY, int GroupNo)
{
LineRangeX = RangeX;
LineRangeY = RangeY;
ItemGroup.push_back(GroupNo);
}
void chartObject::DrawLine(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
SelectObject(hdcDst,pen);
HFONT font;
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
//Draw y axis
MoveToEx(hdcDst,x+50+14,(szBarY)+y,NULL);
LineTo(hdcDst,x+50+14,y);
//Draw x axis
MoveToEx(hdcDst,x+50+14,(szBarY)+y,NULL);
LineTo(hdcDst,szBarX+x+50+14,(szBarY)+y);
TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
// change font
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
TextOut(hdcDst,((szBarX+x+50)/2)-(xName.length()/2)+50,y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
TextOut(hdcDst,x+(50),y+szBarY,"0",1);// Draw a zero at origin
//Draw Range at top of graph y axis
stringstream ss;
ss << LineRangeY;
string number;
ss >> number;
TextOut(hdcDst,x+50-(number.length()*4),y-4,number.c_str(),number.length());
//Draw Range at top of graph x axis
ss.clear();
ss << LineRangeX;
ss >> number;
TextOut(hdcDst,x+szBarX+50+14-(number.length()*4),y+szBarY+4,number.c_str(),number.length());
// Add Title
TextOut(hdcDst,((szBarX+x+50+14)/2)-((Title.length()*4)/2),y-24,Title.c_str(),Title.length());//Draw Title
// Draw Halfway segment points
MoveToEx(hdcDst, ((szBarX/2)+x+50+14), y+szBarY,NULL);
LineTo(hdcDst, ((szBarX/2)+x+50+14), y+szBarY+4);
ss.clear();
ss << (LineRangeX/2);
ss >> number;
TextOut(hdcDst,(szBarX/2)+50+14+x-((number.length()*4)/2),y+szBarY+6,number.c_str(),number.length());
MoveToEx(hdcDst,x+50+14,y+(szBarY/2),NULL);
LineTo(hdcDst, (x+50+14)-4,y+(szBarY/2));
ss.clear();
ss << (LineRangeY/2);
ss >> number;
TextOut(hdcDst,50+x-((number.length()*4)),y+(szBarY/2),number.c_str(),number.length());
string container;
HPEN pen2;
int x1=x+50+14;
int y1=y+szBarY;
//Start Drawing Data inside loops
for(unsigned k = 0; k < GroupName.size(); k++)
{
container.clear();
container = GroupName[k];
x1=x+50+14;
y1=y+szBarY;
MoveToEx(hdcDst,x1,y1,NULL);
for(unsigned j=0; j<GroupName.size(); j++)
{
if(GroupName[j] == container)
{
pen2 = CreatePen(PS_SOLID,1,colors[j]);
SelectObject(hdcDst, pen2);
}
}
for(unsigned i=0; i<LineValueX.size(); i++)
{
if(ItemName[i] == container)
{
x1= (int)(x+50+14+((LineValueX[i]/LineRangeX)*szBarX));
y1 = (int)(y +szBarY-((LineValueY[i]/LineRangeY)*szBarY));
LineTo(hdcDst,x1,y1);
}
MoveToEx(hdcDst,x1,y1,NULL);
}//End loop i
}//End loop k
HBRUSH hbr = NULL;
//Draw Legend
if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szBarX+15+50,y,"Legend",6);
string buffer;
//float d = 0.0f;
for(unsigned i = 0; i<GroupName.size(); i++)
{
buffer = "";
// write strings
buffer.append(GroupName[i]);
TextOut(hdcDst,x+szBarX+70+15,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szBarX+15+50,y+(25*(i+1)),x+szBarX+28+50,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szBarX+16+50;
rc.top = y+(25*(i+1))+1;
rc.right = x+szBarX+28-1+50;
rc.bottom = y+(25*(i+1)+12)-1;
hbr = CreateSolidBrush(colors[i]);
FillRect(hdcDst,&rc,hbr);
}
}
SelectObject(hdcDst,pen);
DeleteObject(pen);
DeleteObject(pen2);
DeleteObject(font);
DeleteObject(hbr);
}
void chart3D::DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
HFONT font;
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
SelectObject(hdcDst,pen);
//Draw Circle
Arc(hdcDst, x,y,szPieX+x,szPieY+y,x,y,x,y);
//Draw First Line
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
LineTo(hdcDst,szPieX+x,(szPieY/2)+y);
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
//Gets Totals for Pie Chart
Total = GetTotal();
GetFrequency();
//Draw Lines of arc
Arc(hdcDst,x,y,x+szPieX,(int)(y+(szPieY+16)),x,y+(szPieY/2),x+szPieX,y+(szPieY/2));
float radius = szPieX/2.0f;
float xrad = (szPieX+8.0f)/2.0f;
float yradius = (szPieY)/2.0f;
float yrad = (y+szPieY+8.0f)/2.0f;
float xr = 0.0f;
float yr = 0.0f;
float Degrees2 =0.0f;
//Draw segments
for(int j = 0; j<szInfo; j++)
{
COLORREF clr = colors[j];
BYTE R = GetRValue(colors[j]);
BYTE G = GetGValue(colors[j]);
BYTE B = GetBValue(colors[j]);
int Flag =0;
// Get a darker shade of the primary color for the rink
if(R>=G&&R>=B)/>
{
R=R-40;
clr = RGB(R,G,B)/>;
Flag =1;
}
if(G>=R&&G>=B&&Flag==0)
{
G=G-40;
clr = RGB(R,G,B)/>;
Flag=1;
}
if(B>=G&&B>=R&&Flag==0)
{
B=B-40;
clr = RGB(R,G,B)/>;
Flag=1;
}
HBRUSH hbr = CreateSolidBrush(colors[j]);
HBRUSH hbr2 = CreateSolidBrush(clr);
SelectObject(hdcDst,hbr);
MoveToEx(hdcDst,(szPieX/2)+x,(szPieY/2)+y,NULL);
Percentage.push_back( Frequency[j]*100 );
a = Frequency[j]*360;
if(j==0)
b.push_back(a);
else
b.push_back(b[j-1]+a);
Degrees= (float)(3.14*b[j])/180;
x2=(((szPieX/2)+x)+radius*cos(Degrees));
y2=(((szPieY/2)+y)-yradius*sin(Degrees));
float x3 = (((szPieX/2)+x)+xrad*cos(Degrees));
float y3 = (((szPieY/2)+y)-yrad*sin(Degrees));
// draw segment lines
LineTo(hdcDst,round(x2),round(y2));
if(b[j]>180&&b[j]<360)
{
LineTo(hdcDst,round(x3),round(y3));
}
//Fill Pie
if(j==0)
{
Degrees2 = (float)(3.14*(a/2))/180;
}
else
{
Degrees2= (float)(3.14*(b[j-1]+(a/2)))/180;
}
xr = (((szPieX/2)+x)+(radius/2)*cos(Degrees2));
yr = (((szPieY/2)+y)-(yradius/2)*sin(Degrees2));
SelectObject(hdcDst,hbr);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
// Fill Rink
if(b[j]>190&&b[j]<=350)
{
Degrees2 = (float)(3.14*((b[j]-4)))/180;
xr = (((szPieX/2)+x)+(radius)*cos(Degrees2));
yr = (((szPieY/2)+y)-(yrad-8)*sin(Degrees2));
SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}
if(b[j]>350&&b[j]<361)
{
Degrees2 = (float)(3.14*((b[j-1]+6)))/180;
xr = (((szPieX/2)+x)+(radius-2)*cos(Degrees2));
yr = (((szPieY/2)+y)-(yrad)*sin(Degrees2));
SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,(int)round(xr),(int)round(yr),bkcolor);
}
}
if(Title !="")
{
TextOut(hdcDst,(x+szPieX/2)-(Title.length()*2)-Title.size(),y-24,Title.c_str(),Title.size());
}
if(vLegend)
{
//Draw Legend
TextOut(hdcDst,x+szPieX+15,y,"Legend",6);
string buffer;
stringstream sbuf;
char buf[20];
float d = 0.0f;
for(int i = 0; i<szNames; i++)
{
buffer = "";
sbuf.clear();
d = Info[i];
// write strings
buffer.append(Names[i]);
buffer.append(" ");
sbuf << d;
sbuf >> buf;
buffer.append(buf);
TextOut(hdcDst,x+szPieX+40,y+(25*(i+1)),buffer.c_str(),buffer.size());
//Draw Colored Boxes
Rectangle(hdcDst,x+szPieX+15,y+(25*(i+1)),x+szPieX+28,y+(25*(i+1)+12));
RECT rc;
rc.left= x+szPieX+16;
rc.top = y+(25*(i+1))+1;
rc.right = x+szPieX+28-1;
rc.bottom = y+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);
FillRect(hdcDst,&rc,hbr);
}
}
DeleteObject(pen);
DeleteObject(font);
}
void chart3D::DrawBar3D(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
SelectObject(hdcDst,pen);
HFONT font;
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
//Draw y axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,x+25+14,y);
LineTo(hdcDst,x+25+14+10,y-5);
LineTo(hdcDst,szBarX+x+25+14+10,y-5);
LineTo(hdcDst,szBarX+x+25+14+10,(szBarY)+y-10);
MoveToEx(hdcDst,x+25+14+10,y-5,NULL);
LineTo(hdcDst,x+25+14+10,szBarY+y-10);
LineTo(hdcDst,x+25+14,szBarY+y);
//Draw x axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,szBarX+x+25+14,(szBarY)+y);
LineTo(hdcDst,szBarX+x+25+14+10,(szBarY)+y-10);
TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
TextOut(hdcDst,((szBarX-x)/2)-(xName.length()/2),y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
TextOut(hdcDst,x+(25+szBarX+14+10),y+szBarY-5,"0",1);// Draw a zero at origin
TextOut(hdcDst,((szBarX-x)/2)-(Title.length()/2),y-24,Title.c_str(),Title.length());//Draw Title
//Get Totals for Bar Chart
GetTotalBar();
GetGroupBar();
GetLargestBar();
for(unsigned i= 0; i<GroupName.size(); i++)
{
//draw Legend
Rectangle(hdcDst,(x+50-12-1),y+szBarY+42+(25*(i+1)-1),(x+50-12-1+12),y+szBarY+42+(25*(i+1)+12));
RECT rc;
rc.left= (x+50-12);
rc.top = y+szBarY+42+(25*(i+1));
rc.right = (x+50)-2;
rc.bottom = y+szBarY+42+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);
FillRect(hdcDst,&rc,hbr);
TextOut(hdcDst,(x)+(GroupName[i].length()+50),y+szBarY+42+(25*(i+1)),GroupName[i].c_str(),GroupName[i].length());//Drawlabels
}
int amt = (ItemValue.size())/(GroupName.size());
int sections = (szBarX)/amt;
int counter = 0;
int count = 0;
// Draw Bar Data
for(unsigned i =0; i<(ItemValue.size()); i=i+GroupName.size())
{
counter = (i/GroupName.size())* sections;
MoveToEx(hdcDst,x+25+14+counter,(y+szBarY),NULL);
LineTo(hdcDst,x+25+14+counter,(y+szBarY+15));
TextOut(hdcDst,(x+25+14+counter)+(ItemName[i].length()),(y+szBarY+15),ItemName[i].c_str(),ItemName[i].length());
for(unsigned j = 0; j<(GroupName.size()); j++)
{
RECT rect;
COLORREF clr = colors[j];
BYTE R = GetRValue(colors[j]);
BYTE G = GetGValue(colors[j]);
BYTE B = GetBValue(colors[j]);
int Flag =0;
// Get a darker shade of the primary color for the sides
if(R>=G&&R>=B)/>
{
R=R-60;
clr = RGB(R,G,B)/>;
Flag =1;
}
if(G>=R&&G>=B&&Flag==0)
{
G=G-60;
clr = RGB(R,G,B)/>;
Flag=1;
}
if(B>=G&&B>=R&&Flag==0)
{
B=B-60;
clr = RGB(R,G,B)/>;
Flag=1;
}
HBRUSH hbr2 = CreateSolidBrush(clr);
float result = szBarY-(szBarY*(ItemValue[count]/LargestBar))+y;
rect.bottom = y+szBarY;
rect.right = x+25+14+counter+5+((szBarX/20)*(j+1));
rect.top = (LONG)(result);
rect.left = (x+25+14+counter+5+((szBarX/20)*j));
HBRUSH hbr = CreateSolidBrush(colors[j]);
SelectObject(hdcDst,hbr);
FillRect(hdcDst,&rect,hbr);
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),(LONG)(result),NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+10,(LONG)(result)-5);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j))+10,(LONG)(result)-5);
LineTo(hdcDst,(x+25+14+counter+5+((szBarX/20)*j)),(LONG)(result));
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+10,(LONG)(result)-5,NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+10,y+szBarY-5);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),y+szBarY);
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),(LONG)(result),NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j)),(LONG)(result));
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),(LONG)(result),NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),y+szBarY);
// Shade Bars
SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))-1,(LONG)(result)-1,bkcolor);
FloodFill(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+2,(LONG)(result)+2,bkcolor);
FloodFill(hdcDst,x+25+14+counter+5+((szBarX/20)*(j))+9,(LONG)(result)-3,bkcolor);
count++;
}
}
//Draw Graph
COLORREF bkgnd = GetPixel(hdcDst,0,0);
Units = LargestBar/3.0f;
int graph = szBarY/3;
for(int i = 0; i<3; i++)
{
MoveToEx(hdcDst,x+25+14+10,(graph*i)+y-5,NULL);
for(int j=(x+25+14+10); j<=x+25+14+szBarX+15; j++)
{
if(GetPixel(hdcDst,j,(graph*i)+y-5)==bkgnd)
{
SetPixel(hdcDst,j,(graph*i)+y-5,bkcolor);
}
}
stringstream number;
number << setprecision(3);
number << (LargestBar-(Units*i));
string num = "";
number >> num;
TextOut(hdcDst,x+25+14+szBarX+7+10,(graph*i)+y,num.c_str(),num.length());//draw numbers
}
// draw bottom line
for(int j=(x+25+14+10); j<=x+25+14+szBarX+15; j++)
{
if(GetPixel(hdcDst,j,(szBarY+y)-10)==bkgnd)
{
SetPixel(hdcDst,j,(szBarY+y)-10,bkcolor);
}
}
DeleteObject(pen);
DeleteObject(font);
}
First up is ChartKM.h
The only change to our header is in Chart3D
class chart3D:public chartObject {
public:
void DrawPie3D(HDC hdcDst,int x,int y, int szPieX, int szPieY, COLORREF bkcolor);
void DrawBar3D(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor);
};
A new drawing routine DrawBar3D has been added to our chart3D class this of course draws our 3D Bar charts.
I will now go onto ChartKM.cpp and the changes in that.
void chart3D::DrawBar3D(HDC hdcDst,int x, int y, int szBarX, int szBarY, COLORREF bkcolor)
{
HPEN pen = CreatePen(PS_SOLID,1,bkcolor);
SelectObject(hdcDst,pen);
HFONT font;
//Set Background Color for Text
SetBkColor(hdcDst,GetPixel(hdcDst,0,0));
font = CreateFont(14,0,900,900,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
//Draw y axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,x+25+14,y);
LineTo(hdcDst,x+25+14+10,y-5);
LineTo(hdcDst,szBarX+x+25+14+10,y-5);
LineTo(hdcDst,szBarX+x+25+14+10,(szBarY)+y-10);
MoveToEx(hdcDst,x+25+14+10,y-5,NULL);
LineTo(hdcDst,x+25+14+10,szBarY+y-10);
LineTo(hdcDst,x+25+14,szBarY+y);
//Draw x axis
MoveToEx(hdcDst,x+25+14,(szBarY)+y,NULL);
LineTo(hdcDst,szBarX+x+25+14,(szBarY)+y);
LineTo(hdcDst,szBarX+x+25+14+10,(szBarY)+y-10);
TextOut(hdcDst,x,((szBarY+y/2)+(yName.length()/2)),yName.c_str(),yName.length());// Draw y-axis label
font = CreateFont(14,0,0,0,FW_DONTCARE,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS,
CLIP_DEFAULT_PRECIS,CLEARTYPE_QUALITY, VARIABLE_PITCH,TEXT("Arial Bold"));
SelectObject(hdcDst, font);
TextOut(hdcDst,((szBarX-x)/2)-(xName.length()/2),y+szBarY+42,xName.c_str(),xName.length());//Draw x-axis label
TextOut(hdcDst,x+(25+szBarX+14+10),y+szBarY-5,"0",1);// Draw a zero at origin
TextOut(hdcDst,((szBarX-x)/2)-(Title.length()/2),y-24,Title.c_str(),Title.length());//Draw Title
//Get Totals for Bar Chart
GetTotalBar();
GetGroupBar();
GetLargestBar();
for(unsigned i= 0; i<GroupName.size(); i++)
{
//draw Legend
Rectangle(hdcDst,(x+50-12-1),y+szBarY+42+(25*(i+1)-1),(x+50-12-1+12),y+szBarY+42+(25*(i+1)+12));
RECT rc;
rc.left= (x+50-12);
rc.top = y+szBarY+42+(25*(i+1));
rc.right = (x+50)-2;
rc.bottom = y+szBarY+42+(25*(i+1)+12)-1;
HBRUSH hbr = CreateSolidBrush(colors[i]);
FillRect(hdcDst,&rc,hbr);
TextOut(hdcDst,(x)+(GroupName[i].length()+50),y+szBarY+42+(25*(i+1)),GroupName[i].c_str(),GroupName[i].length());//Drawlabels
}
int amt = (ItemValue.size())/(GroupName.size());
int sections = (szBarX)/amt;
int counter = 0;
int count = 0;
// Draw Bar Data
for(unsigned i =0; i<(ItemValue.size()); i=i+GroupName.size())
{
counter = (i/GroupName.size())* sections;
MoveToEx(hdcDst,x+25+14+counter,(y+szBarY),NULL);
LineTo(hdcDst,x+25+14+counter,(y+szBarY+15));
TextOut(hdcDst,(x+25+14+counter)+(ItemName[i].length()),(y+szBarY+15),ItemName[i].c_str(),ItemName[i].length());
for(unsigned j = 0; j<(GroupName.size()); j++)
{
RECT rect;
COLORREF clr = colors[j];
BYTE R = GetRValue(colors[j]);
BYTE G = GetGValue(colors[j]);
BYTE B = GetBValue(colors[j]);
int Flag =0;
// Get a darker shade of the primary color for the sides
if(R>=G&&R>=B)/>/>
{
R=R-60;
clr = RGB(R,G,B)/>/>;
Flag =1;
}
if(G>=R&&G>=B&&Flag==0)
{
G=G-60;
clr = RGB(R,G,B)/>/>;
Flag=1;
}
if(B>=G&&B>=R&&Flag==0)
{
B=B-60;
clr = RGB(R,G,B)/>/>;
Flag=1;
}
HBRUSH hbr2 = CreateSolidBrush(clr);
float result = szBarY-(szBarY*(ItemValue[count]/LargestBar))+y;
rect.bottom = y+szBarY;
rect.right = x+25+14+counter+5+((szBarX/20)*(j+1));
rect.top = (LONG)(result);
rect.left = (x+25+14+counter+5+((szBarX/20)*j));
HBRUSH hbr = CreateSolidBrush(colors[j]);
SelectObject(hdcDst,hbr);
FillRect(hdcDst,&rect,hbr);
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),(LONG)(result),NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+10,(LONG)(result)-5);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j))+10,(LONG)(result)-5);
LineTo(hdcDst,(x+25+14+counter+5+((szBarX/20)*j)),(LONG)(result));
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+10,(LONG)(result)-5,NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+10,y+szBarY-5);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),y+szBarY);
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),(LONG)(result),NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j)),(LONG)(result));
MoveToEx(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),(LONG)(result),NULL);
LineTo(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1)),y+szBarY);
// Shade Bars
SelectObject(hdcDst,hbr2);
FloodFill(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))-1,(LONG)(result)-1,bkcolor);
FloodFill(hdcDst,x+25+14+counter+5+((szBarX/20)*(j+1))+2,(LONG)(result)+2,bkcolor);
FloodFill(hdcDst,x+25+14+counter+5+((szBarX/20)*(j))+9,(LONG)(result)-3,bkcolor);
count++;
}
}
//Draw Graph
COLORREF bkgnd = GetPixel(hdcDst,0,0);
Units = LargestBar/3.0f;
int graph = szBarY/3;
for(int i = 0; i<3; i++)
{
MoveToEx(hdcDst,x+25+14+10,(graph*i)+y-5,NULL);
for(int j=(x+25+14+10); j<=x+25+14+szBarX+15; j++)
{
if(GetPixel(hdcDst,j,(graph*i)+y-5)==bkgnd)
{
SetPixel(hdcDst,j,(graph*i)+y-5,bkcolor);
}
}
stringstream number;
number << setprecision(3);
number << (LargestBar-(Units*i));
string num = "";
number >> num;
TextOut(hdcDst,x+25+14+szBarX+7+10,(graph*i)+y,num.c_str(),num.length());//draw numbers
}
// draw bottom line
for(int j=(x+25+14+10); j<=x+25+14+szBarX+15; j++)
{
if(GetPixel(hdcDst,j,(szBarY+y)-10)==bkgnd)
{
SetPixel(hdcDst,j,(szBarY+y)-10,bkcolor);
}
}
DeleteObject(pen);
DeleteObject(font);
}
A lot of this is the same code for the normal 2D Bar Charts.
But there are some small differences and I am going to just go over the whole routine anyway.
First up we create a pen and a font.
We then draw the x and y axis.
We label the x and y axis.
We calculate our Totals for the chart.
We set up a loop to draw the Legend.
We set up two loops to draw the bar data.
One loop to go through the sets of bars.
the other to loop through the groups.
We then loop through to draw the background graph
and at the same time draw our numbers up the side.
Finally we draw the bottom line to give that 3D look.
and that is basically it, a 3D effect bargraph.
Next an example program that uses the new Library.
#include <Windows.h>
#include <ChartKM.h>
#pragma comment(lib, "ChartKM.lib")
chart3D Chart;
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
/* Make the class name into a global variable */
char szClassName[ ] = "PieChart";
int WINAPI WinMain (HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl))
return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
"Charting Demo Application.", /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
1100, /* The programs width */
550, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message loop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
{
Chart.AddTitle("Traffic Survey High Street, Kirby");
Chart.SetAxisTitles("Vehicles", "Amount Per Hour");
Chart.AddGroupData("2003",RGB(255,0,0));
Chart.AddItemData("Cars",150.0f,1);
Chart.AddItemData("Vans",40.0f,1);
Chart.AddItemData("Bikes",70.0f,1);
Chart.AddItemData("Bicycles",25.0f,1);
Chart.AddItemData("Buses",5.0f,1);
Chart.AddItemData("Trucks",25.0f,1);
InvalidateRect(hwnd,NULL,FALSE);
return 0;
}
case WM_SIZE:
{
InvalidateRect(hwnd,NULL,FALSE);
return 0;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
// Draw the Chart onto the screen dc
Chart.DrawBar3D(hdc,30,30,350,200,RGB(0,0,0));
EndPaint(hwnd,&ps);
return 0;
}
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
We will start at WM_CREATE as the rest is pretty much standard Windows stuff.
case WM_CREATE:
{
Chart.AddTitle("Traffic Survey High Street, Kirby");
Chart.SetAxisTitles("Vehicles", "Amount Per Hour");
Chart.AddGroupData("2003",RGB(255,0,0));
Chart.AddItemData("Cars",150.0f,1);
Chart.AddItemData("Vans",40.0f,1);
Chart.AddItemData("Bikes",70.0f,1);
Chart.AddItemData("Bicycles",25.0f,1);
Chart.AddItemData("Buses",5.0f,1);
Chart.AddItemData("Trucks",25.0f,1);
InvalidateRect(hwnd,NULL,FALSE);
return 0;
}
In the above we add our chart data its the same as the way we did it with our 2D Bar no change there.
In WM_PAINT
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd,&ps);
// Draw the Chart onto the screen dc
Chart.DrawBar3D(hdc,30,30,350,200,RGB(0,0,0));
EndPaint(hwnd,&ps);
return 0;
}
We draw the bar chart and thats it next up we will be discussing the 3D Line Graph.
Till next time
Take Care
Snoopy.
This post has been edited by baavgai: 17 February 2013 - 01:52 PM
Reason for edit:: space cleaning, last one, thanks Snoopy





MultiQuote


|