// SmartGraph.cpp : Implementation of SmartGraph
#include "stdafx.h"
#include "SmartGraph.h"
#include ".\smartgraph.h"
// SmartGraph
STDMETHODIMP SmartGraph::get_Title(BSTR* pVal)
{
*pVal = m_strTitle.AllocSysString();
return S_OK;
}
STDMETHODIMP SmartGraph::put_Title(BSTR newVal)
{
m_strTitle = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_xLable(BSTR* pVal)
{
*pVal = m_strxLable.AllocSysString();
//*pVal = _com_util::ConvertStringToBSTR((char*)m_strxLable);
return S_OK;
}
STDMETHODIMP SmartGraph::put_xLable(BSTR newVal)
{
m_strxLable = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_yLable(BSTR* pVal)
{
*pVal = m_stryLable.AllocSysString();
return S_OK;
}
STDMETHODIMP SmartGraph::put_yLable(BSTR newVal)
{
m_stryLable = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_Columns(LONG* pVal)
{
*pVal = m_nCol;
return S_OK;
}
STDMETHODIMP SmartGraph::put_Columns(LONG newVal)
{
m_nCol = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_Rows(LONG* pVal)
{
*pVal = m_nRow;
return S_OK;
}
STDMETHODIMP SmartGraph::put_Rows(LONG newVal)
{
m_nRow = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_MarginBottom(LONG* pVal)
{
*pVal = m_nBMargin;
return S_OK;
}
STDMETHODIMP SmartGraph::put_MarginBottom(LONG newVal)
{
m_nBMargin = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_MarginLeft(LONG* pVal)
{
*pVal = m_nLMargin;
return S_OK;
}
STDMETHODIMP SmartGraph::put_MarginLeft(LONG newVal)
{
m_nLMargin = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_MarginTop(LONG* pVal)
{
*pVal = m_nTMargin;
return S_OK;
}
STDMETHODIMP SmartGraph::put_MarginTop(LONG newVal)
{
m_nTMargin = newVal;
UpdateGraph();
return S_OK;
}
STDMETHODIMP SmartGraph::get_MarginRight(LONG* pVal)
{
*pVal = m_nRMargin;
return S_OK;
}
STDMETHODIMP SmartGraph::put_MarginRight(LONG newVal)
{
m_nRMargin = newVal;
UpdateGraph();
return S_OK;
}
void SmartGraph::CreateFonts(void)
{
m_FontX = CreateFont( 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,_T("Arial") );
m_FontY = CreateFont( 12, 0, 900, 0, FW_NORMAL, FALSE, FALSE, 0,
ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN,_T("Arial") );
}
STDMETHODIMP SmartGraph::SetData(DOUBLE* xData, DOUBLE* yData, LONG NumOfPoints, VARIANT_BOOL bResample)
{
m_bResample = bResample;
SetData(xData,yData,NumOfPoints);
return S_OK;
}
///<ISmartGraph::SetData2 Implementation/>
STDMETHODIMP SmartGraph::SetData2(DOUBLE* xData, DOUBLE* yData, LONG NumOfPoints, DOUBLE xMin, DOUBLE xMax, DOUBLE yMin, DOUBLE yMax, VARIANT_BOOL bResample)
{
m_bResample = bResample;
SetData(xData, yData, NumOfPoints, xMin, xMax, yMin, yMax);
return S_OK;
}
///<SmartGraph::SetData a general function used by ISmartGraph::SetData and ISmartGraph::SetData2 methods>
void SmartGraph::SetData(double* xData, double* yData, long NumOfPoints,
double xMin, double xMax, double yMin, double yMax)
{
SAFE_DELETE(m_pxData);
SAFE_DELETE(m_pyData);
///<ZoomParam>
//Set zoom parameters to show all samples
if(!m_lstZoom.IsEmpty())
m_lstZoom.RemoveAll();
ZoomParam zp;
zp.nFrom = 0;
zp.nTo = NumOfPoints;
zp.nLen = NumOfPoints;
m_lstZoom.AddTail(zp);
///</ZoomParam>
m_pxData = new double[NumOfPoints];
m_pyData = new double[NumOfPoints];
m_nDataLength = NumOfPoints;
if(xData == NULL)
{
for(int i = 0; i < NumOfPoints; i++)
m_pxData[i] = i;
}
else
memcpy(m_pxData, xData, NumOfPoints*sizeof(double));
if(yData == NULL)
{
for(int i = 0; i < NumOfPoints; i++)
m_pyData[i] = i;
}
else
memcpy(m_pyData, yData, NumOfPoints*sizeof(double));
double nLen = 20*(m_rcPlot.right - m_rcPlot.left);
//m_dFactor = nLen/(double)NumOfPoints;
int nFactor = NumOfPoints / nLen;
if(m_bResample && (nFactor > 1))
{
double * xTmp = new double [nLen];
double * yTmp = new double [nLen];
for (int i = 0; i < nLen; i++)
{
xTmp[i] = m_pxData[nFactor*i];
yTmp[i] = m_pyData[nFactor*i];
}
if((xMax < xMin) || (yMax < yMin))
m_cDataSet->SetData(xTmp, yTmp, nLen);
else
m_cDataSet->SetData(xTmp, yTmp, nLen,xMin,xMax,yMin,yMax);
delete [] xTmp;
delete [] yTmp;
}
else
{
if((xMax < xMin) || (yMax < yMin))
m_cDataSet->SetData(/*m_pxData*/xData, m_pyData, NumOfPoints);
else
m_cDataSet->SetData(m_pxData, m_pyData, NumOfPoints,xMin,xMax,yMin,yMax);
}
return;
}
void SmartGraph::UpdateGraph(HDC dc)
{
if(m_bDirty)
{
DeleteDC(m_dcMem);
DeleteObject(m_bmTemp);
m_dcMem = CreateCompatibleDC(dc);
m_bmTemp = CreateCompatibleBitmap(dc, m_rcClient.right - m_rcClient.left, m_rcClient.bottom - m_rcClient.top);
m_bmOld = (HBITMAP)SelectObject( m_dcMem, m_bmTemp );
SetWindowOrgEx(m_dcMem,m_rcClient.left, m_rcClient.top,0);
SetBkMode(m_dcMem, TRANSPARENT);
FillRect(m_dcMem, &m_rcClient, m_brMarginColor);
FillRect(m_dcMem, &m_rcPlot, m_brBackColor);
if(m_bGrid)
DrawGrids(m_dcMem);
static bool first = true;
if(first && m_clrForeColor == 0)
{
m_clrForeColor = RGB(0,255,0);
first = false;
}
HPEN oldPen = (HPEN)SelectObject(m_dcMem,m_penGraph);
m_cDataSet->Draw(m_dcMem,m_rcPlot,m_nPlotType);
SelectObject(m_dcMem,oldPen);
DrawLabes(m_dcMem,m_rcClient);
m_bDirty = false;
}
BitBlt(dc,m_rcClient.left,m_rcClient.top, m_rcClient.right - m_rcClient.left, m_rcClient.bottom - m_rcClient.top,
m_dcMem,m_rcClient.left,m_rcClient.top,SRCCOPY);
/*SetBkMode(dc, TRANSPARENT);
FillRect(dc, &m_rcClient, m_brMarginColor);
FillRect(dc, &m_rcPlot, m_brBackColor);
if(m_bGrid)
DrawGrids(dc);
static bool first = true;
if(first && m_clrForeColor == 0)
{
m_clrForeColor = RGB(0,255,0);
}
first = false;
HPEN pen = CreatePen(PS_SOLID,1,m_clrForeColor);
HPEN oldPen = (HPEN)SelectObject(dc,pen);
m_cDataSet->Draw(dc,m_rcPlot,m_nPlotType);
DrawLabes(dc,m_rcClient);
SelectObject(dc,oldPen);*/
}
int SmartGraph::DrawGrids(HDC dc)
{
int x = m_rcPlot.left;
if(m_penGrids)
DeleteObject(m_penGrids);
m_penGrids = CreatePen(PS_DOT,1,RGB(128,128,128));
HPEN oldPen = (HPEN)SelectObject(dc,m_penGrids);
for(int i = 0; i < m_nRow; i++)
{
x += (m_rcPlot.right-m_rcPlot.left)/m_nRow;
MoveToEx(dc,x,m_rcPlot.bottom,0);
LineTo(dc,x,m_rcPlot.top);
}
int y = m_rcPlot.bottom;
for(int i = 0; i < m_nCol; i++)
{
y -= (m_rcPlot.bottom-m_rcPlot.top)/m_nCol;
MoveToEx(dc,m_rcPlot.left,y,0);
LineTo(dc,m_rcPlot.right,y);
}
SelectObject(dc,oldPen);
return 0;
}
int SmartGraph::DrawLabes(HDC dc, RECT rc)
{
SetBkMode(dc,TRANSPARENT);
SelectObject(dc,m_FontY);
TextOut(dc, rc.left + m_nLMargin/2 - 15, (rc.top+rc.bottom)/2, m_stryLable, lstrlen(m_stryLable));
SetTextAlign(dc, TA_CENTER|TA_BASELINE);
//LPCTSTR pszCaption = m_strTitle;//_T("Smart Graph");
SelectObject(dc,m_FontX);
TextOut(dc, (rc.left + rc.right) / 2, rc.top+m_nTMargin/2, m_strTitle, m_strTitle.GetLength());
TextOut(dc, (rc.left + rc.right) / 2, rc.bottom-m_nBMargin/2 + 10, m_strxLable, m_strxLable.GetLength());
CString str;
double yMax=0,xMax=0,yMin=0,xMin=0,xabsMax=0,yabsMax=0;
xMax = m_cDataSet->m_xDataSet.Max;
xMin = m_cDataSet->m_xDataSet.Min;
xabsMax = max(abs(xMin), abs(xMax));
int scale = 1;
if( (xabsMax > 1000) || (xabsMax < 0.001) )
scale = log10(xabsMax);
double range = (xMax-xMin);
if(scale != 1)
range = (xMax-xMin)/(pow(10, scale));
if(scale != 1)
{
str.Format(_T("(10^%d)"),scale);//x Axes Scale
TextOut(dc, m_rcPlot.right - 40, m_rcPlot.bottom + 15, str, str.GetLength());
}
double start = m_cDataSet->m_xDataSet.Min;
if(scale != 1)
start = m_cDataSet->m_xDataSet.Min/(pow(10,scale));
int W = m_rcPlot.right - m_rcPlot.left;
for(int i = 0; i <= m_nCol; i++)
{
str.Format(_T("%-4.2f"),start);
start += range/(double)m_nCol;
TextOut(dc, m_rcPlot.left + i*W/m_nCol, m_rcPlot.bottom + 10, str, str.GetLength());
}
////////////////////////////////////////////////////////////////////////////////////////////
scale = 1;
yMax = m_cDataSet->m_yDataSet.Max;
yMin = m_cDataSet->m_yDataSet.Min;
yabsMax = max(abs(yMin), abs(yMax));
if( (yabsMax > 1000) || (yabsMax < 0.001) )
scale = log10(yabsMax);
if(scale != 1)
range = (yMax-yMin)/(pow(10, scale));
else
range = (yMax-yMin);
if(scale != 1)
{
str.Format(_T("(10^%d)"),scale);//y Axes Scale
TextOut(dc, m_rcPlot.left + 20, m_rcPlot.top - 10, str, str.GetLength());
}
if(scale != 1)
start = m_cDataSet->m_yDataSet.Min/(pow(10,scale));
else
start = m_cDataSet->m_yDataSet.Min;
int H = m_rcPlot.bottom - m_rcPlot.top;
for(int i = 0; i <= m_nRow; i++)
{
str.Format(_T("%-4.3f"),start);
start += range/(double)m_nRow;
TextOut(dc, m_rcPlot.left - 10, m_rcPlot.bottom - i*H/m_nRow, str,str.GetLength());
}
SetTextColor(dc,RGB(0,255,255));
SetTextAlign(dc,TA_LEFT);
DrawText(dc,m_strLegend,lstrlen(m_strLegend),&m_rcLegend, DT_NOCLIP);
return 0;
}
STDMETHODIMP SmartGraph::ShowGrid(VARIANT_BOOL bShow)
{
m_bGrid = bShow;
m_bDirty = true;
/*m_nReason = GRID_CHANGED;*/
return S_OK;
}
STDMETHODIMP SmartGraph::UpdateGraph(void)
{
m_bDirty = true;
/*m_nReason = DATA_CHANGED;*/
if(m_hWndParent)
::RedrawWindow(m_hWndParent, &m_rcClient,0,RDW_INVALIDATE | RDW_UPDATENOW/* | RDW_ERASE*/);
return S_OK;
}
//0--> Normal , 1-->Dot , 2-->Bar
STDMETHODIMP SmartGraph::SetPlotType(LONG nType)
{
ATLASSERT((nType > -1) && (nType < 3));
m_nPlotType = nType;
UpdateGraph();
return S_OK;
}
LRESULT SmartGraph::OnLButtonDown(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
LButtonDown(pt.x, pt.y, wParam);
return 0;
}
LRESULT SmartGraph::OnMouseMove(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
MouseMove(pt.x, pt.y, wParam);
return 0;
}
LRESULT SmartGraph::OnLButtonUp(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
LButtonUp(pt.x, pt.y, wParam);
return 0;
}
//The rect in which plot area is located.
STDMETHODIMP SmartGraph::GetPlotRect(LONG* left, LONG* top, LONG* right, LONG* bottom)
{
*left = m_rcPlot.left;
*top = m_rcPlot.top;
*right = m_rcPlot.right;
*bottom = m_rcPlot.bottom;
return S_OK;
}
//The rect in which all graph components(plot area and lables) are located.
STDMETHODIMP SmartGraph::GetClientRect(LONG* left, LONG* top, LONG* right, LONG* bottom)
{
RECT rc;
*left = m_rcPlot.left - m_nLMargin;
*top = m_rcPlot.top - m_nTMargin;
*bottom = m_rcPlot.bottom + m_nBMargin;
*right = m_rcPlot.right + m_nRMargin;
return S_OK;
}
//Zoom in with respect to previous zoom parameters
STDMETHODIMP SmartGraph::ZoomIn(LONG FromSample, LONG ToSample)
{
if( (FromSample < 0) || ( (ToSample-FromSample) > m_lstZoom.GetTail().nLen) )
return S_FALSE;
//Zoom with respect to previous zoom
ZoomParam zp;
zp.nFrom = FromSample + m_lstZoom.GetTail().nFrom;
zp.nTo = ToSample + m_lstZoom.GetTail().nFrom;
zp.nLen = ToSample - FromSample;
m_lstZoom.AddTail(zp);
Zoom();
return S_OK;
}
STDMETHODIMP SmartGraph::ZoomInByPercent(DOUBLE FromPercent, DOUBLE ToPercent)
{
// TODO: Add your implementation code here
int From = FromPercent * m_lstZoom.GetTail().nLen / 100;
int To = ToPercent * m_lstZoom.GetTail().nLen / 100;
ZoomIn(From, To);
return S_OK;
}
STDMETHODIMP SmartGraph::ZoomOut(void)
{
if(m_lstZoom.GetCount() < 2)
return S_FALSE;
m_lstZoom.RemoveTail();
Zoom();
return S_OK;
}
STDMETHODIMP SmartGraph::Reset(void)
{
while (m_lstZoom.GetCount() > 1)
{
m_lstZoom.RemoveTail();
}
Zoom();
return S_OK;
}
int SmartGraph::Zoom(void)
{
int start = m_lstZoom.GetTail().nFrom;
int end = m_lstZoom.GetTail().nTo;
int len = m_lstZoom.GetTail().nLen;
int nLen = 20*(m_rcPlot.right - m_rcPlot.left);
int nFactor = len / nLen;
if(m_bResample && (nFactor > 1))
{
double * xTmp = new double [nLen];
double * yTmp = new double [nLen];
for (int i = 0; i < nLen; i++)
{
xTmp[i] = m_pxData[start + nFactor*i];
yTmp[i] = m_pyData[start + nFactor*i];
}
m_cDataSet->SetData(xTmp, yTmp, nLen);
delete [] xTmp;
delete [] yTmp;
}
else
{
m_cDataSet->SetData(m_pxData + start, m_pyData + start, len);
}
if(m_hWndParent)
::RedrawWindow(m_hWndParent, &m_rcPlot,0,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);
return 0;
}
STDMETHODIMP SmartGraph::GetDisplayedRange(LONGLONG* nStartSample, LONGLONG* nEndSample)
{
*nStartSample = m_lstZoom.GetTail().nFrom;
*nEndSample = m_lstZoom.GetTail().nTo;
return S_OK;
}
STDMETHODIMP SmartGraph::SetLegendText(BSTR strText, LONG top, LONG left, LONG bottom, LONG right)
{
m_strLegend = _com_util::ConvertBSTRToString(strText);
m_rcLegend.top = top + m_rcPlot.top;
m_rcLegend.left = left + m_rcPlot.left;
m_rcLegend.right = right + m_rcPlot.left;
m_rcLegend.bottom = bottom+ m_rcPlot.top;
return S_OK;
}
STDMETHODIMP SmartGraph::SetParentWnd(OLE_HANDLE hWnd)
{
m_hWndParent = (HWND)hWnd;
return S_OK;
}
STDMETHODIMP SmartGraph::GetPlotType(LONG* PlotType)
{
*PlotType = m_nPlotType;
return S_OK;
}