// XTPChartAxisView.cpp // // This file is a part of the XTREME TOOLKIT PRO MFC class library. // (c)1998-2012 Codejock Software, All Rights Reserved. // // THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE // RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN // CONSENT OF CODEJOCK SOFTWARE. // // THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED // IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO // YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A // SINGLE COMPUTER. // // CONTACT INFORMATION: // support@codejock.com // http://www.codejock.com // ///////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include "../../Types/XTPChartTypes.h" #include "Common/Base/Types/XTPPoint3.h" #include "../../XTPChartDefines.h" #include "../../XTPChartElement.h" #include #include "../../XTPChartElementView.h" #include "../../XTPChartPanel.h" #include "../../XTPChartContentView.h" #include "../../XTPChartLegend.h" #include #include "../../XTPChartDiagram.h" #include "../Diagram2D/XTPChartDiagram2D.h" #include "XTPChartAxis.h" #include "XTPChartAxisView.h" #include "XTPChartAxisRange.h" #include "XTPChartAxisLabel.h" #include "XTPChartAxisGridLines.h" #include "XTPChartAxisTickMarks.h" #include "XTPChartAxisTitle.h" #include "XTPChartAxisConstantLines.h" #include "XTPChartAxisStrips.h" #include "XTPChartAxisCustomLabels.h" #include "XTPChartScaleTypeMap.h" #include "../../Drawing/XTPChartDeviceCommand.h" #include "../../Drawing/XTPChartLineDeviceCommand.h" #include "../../Drawing/XTPChartRectangleDeviceCommand.h" #include "../../Utils/XTPChartTextPainter.h" #include #include "../../Appearance/XTPChartLineStyle.h" #include "../../Appearance/XTPChartFillStyle.h" #define SCROLLBARSIZE 10 ////////////////////////////////////////////////////////////////////////// // CXTPChartAxisView CXTPChartAxisView::CXTPChartAxisView(CXTPChartAxis* pAxis, CXTPChartElementView* pParentView) : CXTPChartElementView(pParentView) { m_dGridSpacing = 1; m_pAxis = pAxis; } CXTPChartAxisView::~CXTPChartAxisView() { } ////////////////////////////////////////////////////////////////////////// // CXTPChartDiagram2DAxisView CXTPChartDiagram2DAxisView::CXTPChartDiagram2DAxisView(CXTPChartAxis* pAxis, CXTPChartElementView* pParentView) : CXTPChartAxisView(pAxis, pParentView) { ASSERT(m_pContainer); m_nSize = 0; m_ptOldPosition = CPoint(0, 0); m_rcBounds.SetRectEmpty(); } CXTPChartDiagram2DAxisView::~CXTPChartDiagram2DAxisView() { } double CXTPChartAxisView::ValueToAxis(double dValue) const { if (!m_pAxis->IsLogarithmic()) return dValue; if (fabs(dValue) < CXTPMathUtils::m_dEPS) return 0; if (dValue < 0) return 0; return log(dValue) / log(m_pAxis->GetLogarithmicBase()); } double CXTPChartAxisView::AxisToValue(double dValue) const { if (!m_pAxis->IsLogarithmic()) return dValue; return pow(m_pAxis->GetLogarithmicBase(), dValue); } double CXTPChartAxisView::GetRangeMinValue() const { return m_pAxis->GetRange()->GetMinValue(); } double CXTPChartAxisView::GetRangeMaxValue() const { return m_pAxis->GetRange()->GetMaxValue(); } double CXTPChartAxisView::GetViewRangeMinValue() const { return max(m_pAxis->GetRange()->GetViewMinValue(), GetRangeMinValue()); } double CXTPChartAxisView::GetViewRangeMaxValue() const { return min(m_pAxis->GetRange()->GetViewMaxValue(), GetRangeMaxValue()); } double CXTPChartAxisView::GetAxisRangeMinValue() const { return ValueToAxis(GetViewRangeMinValue()); } double CXTPChartAxisView::GetAxisRangeMaxValue() const { return ValueToAxis(GetViewRangeMaxValue()); } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateInterlacedDeviceCommand(CXTPChartDeviceContext* pDC, CRect rcPane) { UNREFERENCED_PARAMETER(pDC); if (!m_pAxis->IsInterlaced()) return NULL; if (m_arrTicks.GetSize() < 1) return NULL; CXTPChartDeviceCommand* pCommands = new CXTPChartDeviceCommand(); BOOL bVertical = IsVertical(); BOOL bReversed = m_pAxis->IsReversed(); int nLeft = bVertical ? (bReversed ? m_rcBounds.top : m_rcBounds.bottom) : (bReversed ? m_rcBounds.right : m_rcBounds.left); int i = 0; double dMark; double dGridSpacing = GetGridSpacing(); int nCount = int((m_arrTicks[0].m_dValue - GetRangeMinValue()) / dGridSpacing); if ((nCount & 1) == 1) { dMark = m_arrTicks[0].m_dValue; nLeft = (int)ValueToPoint(dMark); i = 1; } while (i <= m_arrTicks.GetSize()) { int nRight; if (i >= m_arrTicks.GetSize()) { nRight = bVertical ? (!bReversed ? m_rcBounds.top : m_rcBounds.bottom) : (!bReversed ? m_rcBounds.right : m_rcBounds.left); } else { dMark = m_arrTicks[i].m_dValue; nRight = (int)ValueToPoint(dMark); } i++; CXTPChartRectF rc = bVertical ? CXTPChartRectF((float)rcPane.left, (float)nRight, (float)rcPane.Width(), (float)nLeft - nRight) : CXTPChartRectF((float)nLeft, (float)rcPane.top, (float)nRight - nLeft, (float)rcPane.Height()); if (rc.Width < 0) rc.X += rc.Width, rc.Width = -rc.Width; if (rc.Height < 0) rc.Y += rc.Height, rc.Height = -rc.Height; pCommands->AddChildCommand(m_pAxis->GetInterlacedFillStyle()->CreateDeviceCommand(rc, m_pAxis->GetActualInterlacedColor(), m_pAxis->GetActualInterlacedColor2())); if (i >= m_arrTicks.GetSize()) break; dMark = m_arrTicks[i].m_dValue; nLeft = (int)ValueToPoint(dMark); i++; } return pCommands; } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateStripsDeviceCommand(CXTPChartDeviceContext* pDC, CRect rcPane) { UNREFERENCED_PARAMETER(pDC); CXTPChartAxisStrips* pStrips = m_pAxis->GetStrips(); if (pStrips->GetCount() == 0) return NULL; CXTPChartDeviceCommand* pCommands = new CXTPChartDeviceCommand(); BOOL bVertical = IsVertical(); for (int i = 0; i < pStrips->GetCount(); i++) { CXTPChartAxisStrip* pStrip = pStrips->GetAt(i); if (!pStrip->IsVisible()) continue; double dMarkLeft = !pStrip->GetAxisMinValue().IsEmpty() ? m_pAxis->GetScaleTypeMap()->ValueToInternal(pStrip->GetAxisMinValue()) : pStrip->GetAxisMinValueInternal(); double dMarkRight = !pStrip->GetAxisMaxValue().IsEmpty() ? m_pAxis->GetScaleTypeMap()->ValueToInternal(pStrip->GetAxisMaxValue()) : pStrip->GetAxisMaxValueInternal(); int nLeft = (int)ValueToPoint(dMarkLeft); int nRight = (int)ValueToPoint(dMarkRight); CXTPChartRectF rc; if (bVertical) { rc = CXTPChartRectF((float)rcPane.left, (float)nRight, (float)rcPane.Width(), (float)nLeft - nRight); } else { rc = CXTPChartRectF((float)nLeft, (float)rcPane.top, (float)nRight - nLeft, (float)rcPane.Height()); } rc.Normalize(); pCommands->AddChildCommand(pStrip->GetFillStyle()->CreateDeviceCommand(rc, pStrip->GetActualColor(), pStrip->GetActualColor2())); } return pCommands; } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateConstantLinesDeviceCommand(CXTPChartDeviceContext* pDC, CRect rcPane, BOOL bBehind) { CXTPChartAxisConstantLines* pConstantLines = m_pAxis->GetConstantLines(); if (pConstantLines->GetCount() == 0) return NULL; CXTPChartDeviceCommand* pCommands = new CXTPChartDeviceCommand(); BOOL bVertical = IsVertical(); for (int i = 0; i < pConstantLines->GetCount(); i++) { CXTPChartAxisConstantLine* pConstantLine = pConstantLines->GetAt(i); if (!pConstantLine->IsVisible()) continue; if (pConstantLine->IsShowBehind() != bBehind) continue; double dMark = !pConstantLine->GetAxisValue().IsEmpty() ? m_pAxis->GetScaleTypeMap()->ValueToInternal(pConstantLine->GetAxisValue()) : pConstantLine->GetAxisValueInternal(); int nLeft = (int)ValueToPoint(dMark); if (bVertical) { pCommands->AddChildCommand(pConstantLine->GetLineStyle()->CreateDeviceCommand(CXTPPoint3d(rcPane.left, nLeft), CXTPPoint3d(rcPane.right, nLeft), pConstantLine->GetActualColor())); } else { pCommands->AddChildCommand(pConstantLine->GetLineStyle()->CreateDeviceCommand(CXTPPoint3d(nLeft, rcPane.top), CXTPPoint3d(nLeft, rcPane.bottom), pConstantLine->GetActualColor())); } CXTPChartString strText = pConstantLine->GetText(); if (bVertical) { CXTPChartTextPainter painter(pDC, strText, pConstantLine); int x = pConstantLine->GetAlignment() == xtpChartAlignNear ? rcPane.left + 2 : pConstantLine->GetAlignment() == xtpChartAlignFar ? rcPane.right - 2 - (int)painter.GetSize().Width : (rcPane.left + rcPane.right - (int)painter.GetSize().Width) / 2; painter.SetLocation(CXTPPoint2i(x, pConstantLine->IsTextBelow() ? nLeft + 2 : nLeft - (int)painter.GetSize().Height)); pCommands->AddChildCommand(painter.CreateDeviceCommand(pDC, pConstantLine->GetActualTextColor())); } else { CXTPChartRotatedTextPainterNearLine painter(pDC, strText, pConstantLine, CPoint(0, 0), TRUE ? xtpChartTextNearRight : xtpChartTextNearTop, 90); int y = pConstantLine->GetAlignment() == xtpChartAlignNear ? rcPane.bottom - (int)painter.GetSize().Width / 2 : pConstantLine->GetAlignment() == xtpChartAlignFar ? rcPane.top + (int)painter.GetSize().Width / 2 : (rcPane.top + rcPane.bottom) / 2; painter.SetBasePoint(CPoint(pConstantLine->IsTextBelow() ? nLeft + 2 - (int)painter.GetSize().Height : nLeft + 2, y)); pCommands->AddChildCommand(painter.CreateDeviceCommand(pDC, pConstantLine->GetActualTextColor())); } } return pCommands; } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateGridLinesDeviceCommand(CXTPChartDeviceContext* pDC, CRect rcPane) { UNREFERENCED_PARAMETER(pDC); CXTPChartAxisGridLines* pGridLines = m_pAxis->GetGridLines(); if (!pGridLines->IsVisible()) return NULL; CXTPChartDeviceCommand* pCommands = new CXTPChartDeviceCommand(); CXTPChartColor clrGridLines = pGridLines->GetColor(); CXTPChartColor clrMinorGridLines = pGridLines->GetMinorColor(); BOOL bMinorVisible = pGridLines->IsMinorVisible(); BOOL bVertical = IsVertical(); for (int i = 0; i < m_arrTicks.GetSize(); i++) { int nLeft = (int)ValueToPoint(m_arrTicks[i].m_dValue); if (bVertical) { pCommands->AddChildCommand(pGridLines->GetLineStyle()->CreateDeviceCommand(CXTPPoint3d(rcPane.left, nLeft), CXTPPoint3d(rcPane.right, nLeft), clrGridLines)); } else { pCommands->AddChildCommand(pGridLines->GetLineStyle()->CreateDeviceCommand(CXTPPoint3d(nLeft, rcPane.top), CXTPPoint3d(nLeft, rcPane.bottom), clrGridLines)); } } if (bMinorVisible) { for (int i = 0; i < m_arrMinorTicks.GetSize(); i++) { int nLeft = (int)ValueToPoint(m_arrMinorTicks[i]); if (bVertical) { pCommands->AddChildCommand(pGridLines->GetMinorLineStyle()->CreateDeviceCommand(CXTPPoint3d(rcPane.left, nLeft), CXTPPoint3d(rcPane.right, nLeft), clrMinorGridLines)); } else { pCommands->AddChildCommand(pGridLines->GetMinorLineStyle()->CreateDeviceCommand(CXTPPoint3d(nLeft, rcPane.top), CXTPPoint3d(nLeft, rcPane.bottom), clrMinorGridLines)); } } } return pCommands; } double CXTPChartDiagram2DAxisView::GetScale() const { double dMinValue = GetAxisRangeMinValue(); double dMaxValue = GetAxisRangeMaxValue(); if (IsVertical()) { return (m_rcBounds.Height()) / (dMaxValue - dMinValue); } else { return (m_rcBounds.Width()) / (dMaxValue - dMinValue); } } double CXTPChartDiagram2DAxisView::DistanceToPoint(double x) const { double dMinValue = GetAxisRangeMinValue(); double dMaxValue = GetAxisRangeMaxValue(); if (IsVertical()) { return x / (dMaxValue - dMinValue) * (m_rcBounds.Height()); } else { return x / (dMaxValue - dMinValue) * (m_rcBounds.Width()); } } double CXTPChartDiagram2DAxisView::PointToValue(int nPoint) const { double dMinValue = GetAxisRangeMinValue(); double dMaxValue = GetAxisRangeMaxValue(); BOOL bRevered = m_pAxis->IsReversed(); double dValue; if (bRevered) { if (IsVertical()) { dValue = dMinValue + (double)(nPoint - m_rcBounds.top) * (dMaxValue - dMinValue) / m_rcBounds.Height(); } else { dValue = dMinValue + (double)(m_rcBounds.right - nPoint) * (dMaxValue - dMinValue) / m_rcBounds.Width(); } } else { if (IsVertical()) { dValue = dMinValue + (double)(m_rcBounds.bottom - nPoint) * (dMaxValue - dMinValue) / m_rcBounds.Height() ; } else { dValue = dMinValue + (double)(nPoint - m_rcBounds.left) * (dMaxValue - dMinValue) / m_rcBounds.Width(); } } return AxisToValue(dValue); } double CXTPChartDiagram2DAxisView::ValueToPoint(double x) const { double dMinValue = GetAxisRangeMinValue(); double dMaxValue = GetAxisRangeMaxValue(); x = ValueToAxis(x); BOOL bRevered = m_pAxis->IsReversed(); double dValue; if (bRevered) { if (IsVertical()) { dValue = m_rcBounds.top + (x - dMinValue) / (dMaxValue - dMinValue) * (m_rcBounds.Height()); } else { dValue = m_rcBounds.right - (x - dMinValue) / (dMaxValue - dMinValue) * (m_rcBounds.Width()); } } else { if (IsVertical()) { dValue = m_rcBounds.bottom - (x - dMinValue) / (dMaxValue - dMinValue) * (m_rcBounds.Height()); } else { dValue = m_rcBounds.left + (x - dMinValue) / (dMaxValue - dMinValue) * (m_rcBounds.Width()); } } return CXTPMathUtils::Round(dValue); } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateTickMarksDeviceCommand(CXTPChartDeviceContext* pDC) { UNREFERENCED_PARAMETER(pDC); CXTPChartDeviceCommand* pCommands = new CXTPChartHitTestElementCommand(m_pAxis, m_rcBounds); CXTPChartAxisTickMarks* pTickMarks = m_pAxis->GetTickMarks(); if (!pTickMarks->IsVisible()) return pCommands; int nScrollBarSize = IsScollBarVisible() ? SCROLLBARSIZE : 0; CXTPChartColor clrAxis = m_pAxis->GetActualColor(); int nLength = pTickMarks->GetLength(); int nThickness = pTickMarks->GetThickness(); BOOL bMinorVisible = pTickMarks->IsMinorVisible(); BOOL bVertical = IsVertical(); BOOL bCross = pTickMarks->IsCrossAxis(); int nAxisThickness = m_pAxis->GetThickness() - 1 + nScrollBarSize; int nExtraLength = bCross ? nLength + nAxisThickness : 0; for (int i = 0; i < m_arrTicks.GetSize(); i++) { int nLeft = (int)ValueToPoint(m_arrTicks[i].m_dValue); if (bVertical) { if (m_pAxis->GetAlignment() == xtpChartAxisNear) pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(m_rcBounds.right - nAxisThickness - nLength, nLeft), CXTPPoint3d(m_rcBounds.right - nAxisThickness + nExtraLength, nLeft), clrAxis, nThickness)); else pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(m_rcBounds.left + nAxisThickness - nExtraLength, nLeft), CXTPPoint3d(m_rcBounds.left + nAxisThickness + nLength, nLeft), clrAxis, nThickness)); } else { if (m_pAxis->GetAlignment() == xtpChartAxisNear) pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(nLeft, m_rcBounds.top + nAxisThickness - nExtraLength), CXTPPoint3d(nLeft, m_rcBounds.top + nAxisThickness + nLength), clrAxis, nThickness)); else pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(nLeft, m_rcBounds.bottom - nAxisThickness - nLength), CXTPPoint3d(nLeft, m_rcBounds.bottom - nAxisThickness + nExtraLength), clrAxis, nThickness)); } } if (bMinorVisible) { nLength = pTickMarks->GetMinorLength(); int nExtraLength = bCross ? nLength + nAxisThickness : 0; int nMinorThickness = pTickMarks->GetMinorThickness(); for (int i = 0; i < m_arrMinorTicks.GetSize(); i++) { int nLeft = (int)ValueToPoint(m_arrMinorTicks[i]); if (bVertical) { if (m_pAxis->GetAlignment() == xtpChartAxisNear) pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(m_rcBounds.right - nAxisThickness - nLength, nLeft), CXTPPoint3d(m_rcBounds.right - nAxisThickness + nExtraLength, nLeft), clrAxis, nMinorThickness)); else pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(m_rcBounds.left + nAxisThickness - nExtraLength, nLeft), CXTPPoint3d(m_rcBounds.left + nAxisThickness + nLength, nLeft), clrAxis, nMinorThickness)); } else { if (m_pAxis->GetAlignment() == xtpChartAxisNear) pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(nLeft, m_rcBounds.top + nAxisThickness - nExtraLength), CXTPPoint3d(nLeft, m_rcBounds.top + nAxisThickness + nLength), clrAxis, nMinorThickness)); else pCommands->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(nLeft, m_rcBounds.bottom - nAxisThickness - nLength), CXTPPoint3d(nLeft, m_rcBounds.bottom - nAxisThickness + nExtraLength), clrAxis, nMinorThickness)); } } } return pCommands; } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateLabelsDeviceCommand(CXTPChartDeviceContext* pDC) { if (!m_pAxis->GetLabel()->IsVisible()) return NULL; CXTPChartDeviceCommand* pLabelsCommand = new CXTPChartHitTestElementCommand(m_pAxis->GetLabel(), m_rcBounds); CXTPChartColor clrAxis = m_pAxis->GetActualColor(); BOOL bVertical = IsVertical(); int nAngle = m_pAxis->GetLabel()->GetAngle(); BOOL bNear = m_pAxis->GetAlignment() == xtpChartAxisNear; int nOffset = m_pAxis->GetThickness() + (m_pAxis->GetTickMarks()->IsVisible() ? m_pAxis->GetTickMarks()->GetLength() : 0) + (IsScollBarVisible() ? SCROLLBARSIZE : 0); for (int i = 0; i < m_arrTicks.GetSize(); i++) { int nLeft = (int)ValueToPoint(m_arrTicks[i].m_dValue); CXTPChartString s = m_arrTicks[i].m_strLabel; if (bVertical) { CXTPChartRotatedTextPainterNearLine painter(pDC, s, m_pAxis->GetLabel(), CPoint(bNear ? m_rcBounds.right - nOffset : m_rcBounds.left + nOffset, nLeft), bNear ? xtpChartTextNearLeft : xtpChartTextNearRight, (float)nAngle); pLabelsCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, m_pAxis->GetLabel()->GetActualTextColor())); } else { CXTPChartRotatedTextPainterNearLine painter(pDC, s, m_pAxis->GetLabel(), CPoint(nLeft, bNear ? m_rcBounds.top + nOffset : m_rcBounds.bottom - nOffset), bNear ? xtpChartTextNearBottom : xtpChartTextNearTop, (float)nAngle); pLabelsCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, m_pAxis->GetLabel()->GetActualTextColor())); } } return pLabelsCommand; } void CXTPChartDiagram2DAxisView::OnLButtonDown(UINT /*nFlags*/, CPoint point) { CXTPChartContainer* pContainer = m_pContainer; ASSERT (pContainer); if (m_rcScrollBar.GetLeft() > point.x || m_rcScrollBar.GetRight() < point.x) return; if (m_rcScrollBar.GetTop() > point.y || m_rcScrollBar.GetBottom() < point.y) return; m_pContainer->SetCapture(this); m_ptOldPosition = point; if (IsVertical()) { double top = m_rcThumb.GetTop(); double bottom = m_rcThumb.GetBottom(); if (point.y < top || point.y > bottom) { double dy = !m_pAxis->IsReversed() ? (m_rcScrollBar.GetBottom() - point.y) : (point.y - m_rcScrollBar.GetTop()); double pos = dy * (ValueToAxis(GetRangeMaxValue()) - ValueToAxis(GetRangeMinValue())) / m_rcScrollBar.Height + ValueToAxis(GetRangeMinValue()); double delta = -(GetAxisRangeMinValue() - (pos - (GetAxisRangeMaxValue() - GetAxisRangeMinValue()) / 2)); if (GetAxisRangeMaxValue() + delta > ValueToAxis(GetRangeMaxValue())) delta = ValueToAxis(GetRangeMaxValue()) - GetAxisRangeMaxValue(); if (GetAxisRangeMinValue() + delta < ValueToAxis(GetRangeMinValue())) delta = ValueToAxis(GetRangeMinValue()) - GetAxisRangeMinValue(); m_pAxis->GetRange()->SetViewMaxValue(AxisToValue(GetAxisRangeMaxValue() + delta)); m_pAxis->GetRange()->SetViewMinValue(AxisToValue(GetAxisRangeMinValue() + delta)); } } else { double left = m_rcThumb.GetLeft(); double right = m_rcThumb.GetRight(); if (point.x < left || point.x > right) { double dx = !m_pAxis->IsReversed() ? (point.x - m_rcScrollBar.GetLeft()) : (m_rcScrollBar.GetRight() - point.x); double pos = dx * (ValueToAxis(GetRangeMaxValue()) - ValueToAxis(GetRangeMinValue())) / m_rcScrollBar.Width + ValueToAxis(GetRangeMinValue()); double delta = -(GetAxisRangeMinValue() - (pos - (GetAxisRangeMaxValue() - GetAxisRangeMinValue()) / 2)); if (GetAxisRangeMaxValue() + delta > ValueToAxis(GetRangeMaxValue())) delta = ValueToAxis(GetRangeMaxValue()) - GetAxisRangeMaxValue(); if (GetAxisRangeMinValue() + delta < ValueToAxis(GetRangeMinValue())) delta = ValueToAxis(GetRangeMinValue()) - GetAxisRangeMinValue(); m_pAxis->GetRange()->SetViewMaxValue(AxisToValue(GetAxisRangeMaxValue() + delta)); m_pAxis->GetRange()->SetViewMinValue(AxisToValue(GetAxisRangeMinValue() + delta)); } } } void CXTPChartDiagram2DAxisView::OnMouseMove(UINT /*nFlags*/, CPoint point) { int dx = point.x - m_ptOldPosition.x; int dy = point.y - m_ptOldPosition.y; m_ptOldPosition = point; CXTPChartContainer* pContainer = m_pContainer; ASSERT (pContainer); m_pAxis->GetRange()->SetViewAutoRange(FALSE); double dMinValue = ValueToAxis(GetRangeMinValue()); double dMaxValue = ValueToAxis(GetRangeMaxValue()); double dScale = 0; if (IsVertical()) { dScale = (m_rcBounds.Height()) / (dMaxValue - dMinValue); } else { dScale = (m_rcBounds.Width()) / (dMaxValue - dMinValue); } double delta = 1.0 / dScale; if (IsVertical()) delta *= -dy; else delta *= dx; if (m_pAxis->IsReversed()) delta *= -1; if (GetAxisRangeMaxValue() + delta > dMaxValue) delta = dMaxValue - GetAxisRangeMaxValue(); if (GetAxisRangeMinValue() + delta < dMinValue) delta = dMinValue - GetAxisRangeMinValue(); m_pAxis->GetRange()->SetViewMaxValue(AxisToValue(GetAxisRangeMaxValue() + delta)); m_pAxis->GetRange()->SetViewMinValue(AxisToValue(GetAxisRangeMinValue() + delta)); } void CXTPChartDiagram2DAxisView::PerformPaneDragging(int dx, int dy) { CXTPChartContainer* pContainer = m_pContainer; ASSERT (pContainer); m_pAxis->GetRange()->SetViewAutoRange(FALSE); double delta = 1.0 / GetScale(); if (IsVertical()) delta *= dy; else delta *= -dx; if (m_pAxis->IsReversed()) delta *= -1; double dMinValue = ValueToAxis(GetRangeMinValue()); double dMaxValue = ValueToAxis(GetRangeMaxValue()); if (GetAxisRangeMaxValue() + delta > dMaxValue) delta = dMaxValue - GetAxisRangeMaxValue(); if (GetAxisRangeMinValue() + delta < dMinValue) delta = dMinValue - GetAxisRangeMinValue(); m_pAxis->GetRange()->SetViewMaxValue(AxisToValue(GetAxisRangeMaxValue() + delta)); m_pAxis->GetRange()->SetViewMinValue(AxisToValue(GetAxisRangeMinValue() + delta)); } void CXTPChartDiagram2DAxisView::PerformMouseWheel(short zDelta, CPoint /*pt*/) { CXTPChartContainer* pContainer = m_pContainer; ASSERT (pContainer); if (!m_pAxis->IsAllowZoom()) return; CXTPChartAxisRange* pRange = m_pAxis->GetRange(); pRange->SetViewAutoRange(FALSE); double dRange = (GetAxisRangeMaxValue() - GetAxisRangeMinValue()); double delta = dRange / 10; if (zDelta >= 0) delta = -delta; if (dRange - 2 * delta < pRange->GetZoomLimit()) { delta = (dRange - pRange->GetZoomLimit()) / 2; } pRange->SetViewMaxValue(min(GetRangeMaxValue(), AxisToValue(GetAxisRangeMaxValue() - delta))); pRange->SetViewMinValue(max(GetRangeMinValue(), AxisToValue(GetAxisRangeMinValue() + delta))); } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateScrollBarDeviceCommand(CXTPChartDeviceContext* /*pDC*/) { m_rcScrollBar = CXTPChartRectF(0, 0, 0, 0); if (!IsScollBarVisible()) return NULL; CXTPChartDeviceCommand* pCommand = new CXTPChartDeviceCommand(); CRect rcBounds = m_rcBounds; int nSize = SCROLLBARSIZE; if (IsVertical()) { if (m_pAxis->GetAlignment() == xtpChartAxisNear) { rcBounds.left = rcBounds.right - nSize; } else { rcBounds.right = rcBounds.left + nSize; } } else { if (m_pAxis->GetAlignment() == xtpChartAxisNear) { rcBounds.bottom = rcBounds.top + nSize; } else { rcBounds.top = rcBounds.bottom - nSize; } } CXTPChartColor clrAxis = m_pAxis->GetActualColor(); pCommand->AddChildCommand(new CXTPChartSolidRectangleDeviceCommand(rcBounds, CXTPChartColor::White)); pCommand->AddChildCommand(new CXTPChartBoundedRectangleDeviceCommand(rcBounds, clrAxis, 1)); CXTPChartRectF rcScrollBar(rcBounds); rcScrollBar.DeflateRect(1.5f, 1.5f, 1.5f, 1.5f); double dRangeMaxValue = ValueToAxis(GetRangeMaxValue()); double dRangeMinValue = ValueToAxis(GetRangeMinValue()); double minValue = (GetAxisRangeMinValue() - dRangeMinValue) / (dRangeMaxValue - dRangeMinValue); double maxValue = (GetAxisRangeMaxValue() - dRangeMinValue) / (dRangeMaxValue - dRangeMinValue); const int MIN_BUTTON_SIZE = 15; CXTPChartRectF rcThumb(rcScrollBar); if (IsVertical()) { double top, bottom; if (!m_pAxis->IsReversed()) { bottom = rcThumb.GetBottom() - rcThumb.Height * minValue; top = rcThumb.GetBottom() - rcThumb.Height * maxValue; } else { top = rcThumb.GetTop() + rcThumb.Height * minValue; bottom = rcThumb.GetTop() + rcThumb.Height * maxValue; } if (bottom - top < MIN_BUTTON_SIZE) { bottom = top + MIN_BUTTON_SIZE; if (bottom > rcScrollBar.GetBottom()) { bottom = rcScrollBar.GetBottom(); top = bottom - MIN_BUTTON_SIZE; } if (top < rcScrollBar.GetTop()) top = rcScrollBar.GetTop(); } rcThumb.Y = (float)top; rcThumb.Height = (float)(bottom - top); } else { double left, right; if (!m_pAxis->IsReversed()) { left = rcThumb.GetLeft() + rcThumb.Width * minValue; right = rcThumb.GetLeft() + rcThumb.Width * maxValue; } else { right = rcThumb.GetRight() - rcThumb.Width * minValue; left = rcThumb.GetRight() - rcThumb.Width * maxValue; } if (right - left < MIN_BUTTON_SIZE) { right = left + MIN_BUTTON_SIZE; if (right > rcScrollBar.GetRight()) { right = rcScrollBar.GetRight(); left = right - MIN_BUTTON_SIZE; } if (left < rcScrollBar.GetLeft()) left = rcScrollBar.GetLeft(); } rcThumb.X = (float)left; rcThumb.Width = (float)(right - left); } m_rcScrollBar = rcScrollBar; m_rcThumb = rcThumb; pCommand->AddChildCommand(new CXTPChartSolidRectangleDeviceCommand(rcThumb, clrAxis)); if (IsVertical()) { if (rcThumb.Height > 10) { CXTPChartPointF pt = rcThumb.GetCenter(); pCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand( CXTPPoint3d(pt.X - 1, pt.Y), CXTPPoint3d(pt.X + 1, pt.Y), CXTPChartColor::White, 1)); pCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand( CXTPPoint3d(pt.X - 1, pt.Y - 2), CXTPPoint3d(pt.X + 1, pt.Y - 2), CXTPChartColor::White, 1)); pCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand( CXTPPoint3d(pt.X - 1, pt.Y + 2), CXTPPoint3d(pt.X + 1, pt.Y + 2), CXTPChartColor::White, 1)); } } else { if (rcThumb.Width > 10) { CXTPChartPointF pt = rcThumb.GetCenter(); pCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand( CXTPPoint3d(pt.X, pt.Y - 1), CXTPPoint3d(pt.X, pt.Y + 1), CXTPChartColor::White, 1)); pCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand( CXTPPoint3d(pt.X - 2, pt.Y - 1), CXTPPoint3d(pt.X - 2, pt.Y + 1), CXTPChartColor::White, 1)); pCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand( CXTPPoint3d(pt.X + 2, pt.Y - 1), CXTPPoint3d(pt.X + 2, pt.Y + 1), CXTPChartColor::White, 1)); } } return pCommand; } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateTitleDeviceCommand(CXTPChartDeviceContext* pDC) { CXTPChartAxisTitle* pTitle = GetAxis()->GetTitle(); if (!pTitle->IsVisible()) return NULL; CXTPChartString strText = pTitle->GetText(); CXTPChartDeviceCommand* pCommand = new CXTPChartHitTestElementCommand(pTitle, m_rcBounds); if (IsVertical()) { if (m_pAxis->GetAlignment() == xtpChartAxisNear) { CXTPChartRotatedTextPainterNearLine painter(pDC, pTitle->GetText(), pTitle, CPoint(m_rcBounds.left, m_rcBounds.CenterPoint().y), xtpChartTextNearRight, 270); pCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, pTitle->GetActualTextColor())); } else { CXTPChartRotatedTextPainterNearLine painter(pDC, pTitle->GetText(), pTitle, CPoint(m_rcBounds.right, m_rcBounds.CenterPoint().y), xtpChartTextNearLeft, 90); pCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, pTitle->GetActualTextColor())); } } else { if (m_pAxis->GetAlignment() == xtpChartAxisNear) { if (pTitle->GetAlignment() == xtpChartAlignCenter) { CXTPChartRotatedTextPainterNearLine painter(pDC, pTitle->GetText(), pTitle, CPoint(m_rcBounds.CenterPoint().x, m_rcBounds.bottom + 3), xtpChartTextNearTop, 0); pCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, pTitle->GetActualTextColor())); } else { CXTPChartTextPainter painter(pDC, pTitle->GetText(), pTitle); painter.SetLocation(CXTPChartPointF(pTitle->GetAlignment() == xtpChartAlignNear ? m_rcBounds.left : m_rcBounds.right - painter.GetSize().Width, m_rcBounds.bottom + 3 - painter.GetSize().Height)); pCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, pTitle->GetActualTextColor())); } } else { CXTPChartRotatedTextPainterNearLine painter(pDC, pTitle->GetText(), pTitle, CPoint(m_rcBounds.CenterPoint().x, m_rcBounds.top), xtpChartTextNearBottom, 0); pCommand->AddChildCommand(painter.CreateDeviceCommand(pDC, pTitle->GetActualTextColor())); } } return pCommand; } BOOL CXTPChartDiagram2DAxisView::IsScollBarVisible() const { if (m_pAxis->GetRange()->IsViewAutoRange()) return FALSE; if (fabs(GetViewRangeMinValue() - GetRangeMinValue()) < CXTPMathUtils::m_dEPS && fabs(GetViewRangeMaxValue() - GetRangeMaxValue()) < CXTPMathUtils::m_dEPS) return FALSE; CXTPChartDiagram2D* pDiagram = DYNAMIC_DOWNCAST(CXTPChartDiagram2D, m_pAxis->GetDiagram()); if (!pDiagram) return FALSE; return pDiagram->IsAllowScroll(); } CXTPChartDeviceCommand* CXTPChartDiagram2DAxisView::CreateDeviceCommand(CXTPChartDeviceContext* pDC) { CXTPChartDeviceCommand* pAxisCommand = new CXTPChartDeviceCommand(); CXTPChartColor clrAxis = m_pAxis->GetActualColor(); int nScrollBarSize = IsScollBarVisible() ? SCROLLBARSIZE : 0; int nThickness = m_pAxis->GetThickness(); if (m_pAxis->IsVisible()) { if (IsVertical()) { float fPosition = m_pAxis->GetAlignment() == xtpChartAxisNear ? m_rcBounds.right - nScrollBarSize - nThickness / 2.0f + 0.5f : m_rcBounds.left + nScrollBarSize + nThickness / 2.0f - 0.5f; pAxisCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(fPosition, (float)m_rcBounds.top), CXTPPoint3d(fPosition, m_rcBounds.bottom + 0.5f), clrAxis, m_pAxis->GetThickness())); } else { float fPosition = m_pAxis->GetAlignment() == xtpChartAxisNear ? m_rcBounds.top + nScrollBarSize + nThickness / 2.0f - 0.5f : m_rcBounds.bottom - nThickness / 2.0f + 0.5f - nScrollBarSize; pAxisCommand->AddChildCommand(new CXTPChartSolidLineDeviceCommand(CXTPPoint3d(m_rcBounds.left, fPosition), CXTPPoint3d(m_rcBounds.right + 0.5f, fPosition), clrAxis, nThickness)); } pAxisCommand->AddChildCommand(CreateTickMarksDeviceCommand(pDC)); pAxisCommand->AddChildCommand(CreateLabelsDeviceCommand(pDC)); pAxisCommand->AddChildCommand(CreateTitleDeviceCommand(pDC)); pAxisCommand->AddChildCommand(CreateScrollBarDeviceCommand(pDC)); } return pAxisCommand; } double CXTPChartAxisView::CalculateGridSpacing(double nAxisRangeDelta, double nScreenDelta, double nGridSpacingFactor) { if (m_pAxis->GetScaleType() == xtpChartScaleQualitative) return 1.0; double multipliers[] = { 1, 2, 3, 5 }; if (nScreenDelta <= 0) return 1; double deltaCoef = nGridSpacingFactor * nAxisRangeDelta / nScreenDelta; if (deltaCoef < CXTPMathUtils::m_dEPS) return 1; if (deltaCoef > 1.0) { for (double factor = 1;; factor *= 10) { for (int i = 0; i < 4; i++) { double result = multipliers[i] * factor; if (deltaCoef <= result) return result; } } } else { double result = 1; if (m_pAxis->GetScaleType() == xtpChartScaleDateTime) return result; for (double factor = 0.1;; factor /= 10) { for (int i = 4 - 1; i >= 0; i--) { double newResult = multipliers[i] * factor; if (deltaCoef > newResult) return result; result = newResult; } } } } void CXTPChartDiagram2DAxisView::SetBounds(CXTPChartDeviceContext* pDC, CRect rcBounds) { UNREFERENCED_PARAMETER(pDC); m_rcBounds = rcBounds; } void CXTPChartDiagram2DAxisView::CreateTickMarks(CXTPChartDeviceContext* pDC, CRect rcDiagram) { UNREFERENCED_PARAMETER(pDC); UNREFERENCED_PARAMETER(rcDiagram); m_arrTicks.RemoveAll(); m_arrMinorTicks.RemoveAll(); double dViewMinValue = GetViewRangeMinValue(); double dViewMaxValue = GetViewRangeMaxValue(); double dAxisMinValue = GetAxisRangeMinValue(); double dAxisMaxValue = GetAxisRangeMaxValue(); double dGridSpacing = GetGridSpacing(); BOOL bVertical = IsVertical(); BOOL bNear = m_pAxis->GetAlignment() == xtpChartAxisNear; int nAngle = m_pAxis->GetLabel()->GetAngle(); if (m_pAxis->GetCustomLabels()->GetCount() > 0) { CXTPChartAxisCustomLabels* pCustomLabels = m_pAxis->GetCustomLabels(); int nCount = pCustomLabels->GetCount(); for (int i = 0; i < nCount; i++) { CXTPChartAxisCustomLabel* pLabel = pCustomLabels->GetAt(i); CXTPChartAxisViewTick tick; tick.m_dValue = !pLabel->GetAxisValue().IsEmpty() ? m_pAxis->GetScaleTypeMap()->ValueToInternal(pLabel->GetAxisValue()) : pLabel->GetAxisValueInternal(); if (tick.m_dValue >= dViewMinValue && tick.m_dValue <= dViewMaxValue) { tick.m_strLabel = pLabel->GetText(); CXTPChartRotatedTextPainterNearLine painter(pDC, tick.m_strLabel, m_pAxis->GetLabel(), CPoint(0, 0), bVertical ? (bNear ? xtpChartTextNearLeft : xtpChartTextNearRight) : (bNear ? xtpChartTextNearBottom : xtpChartTextNearTop), (float)nAngle); tick.m_szLabel = painter.GetSize(); tick.m_szBounds = painter.GetRoundedBounds().Size(); m_arrTicks.Add(tick); } } } else { if (dAxisMinValue < -CXTPMathUtils::m_dEPS) dAxisMinValue += -CXTPMathUtils::m_dEPS; double dMark = ((int)(dAxisMinValue / dGridSpacing)) * dGridSpacing; if (dMark < dAxisMinValue) dMark += dGridSpacing; while (dMark < dAxisMaxValue + CXTPMathUtils::m_dEPS) { CXTPChartAxisViewTick tick; tick.m_dValue = AxisToValue(dMark); tick.m_strLabel = m_pAxis->GetScaleTypeMap()->InternalToValue(m_pAxis->GetLabel()->GetFormat(), tick.m_dValue); CXTPChartRotatedTextPainterNearLine painter(pDC, tick.m_strLabel, m_pAxis->GetLabel(), CPoint(0, 0), bVertical ? (bNear ? xtpChartTextNearLeft : xtpChartTextNearRight) : (bNear ? xtpChartTextNearBottom : xtpChartTextNearTop), (float)nAngle); tick.m_szLabel = painter.GetSize(); tick.m_szBounds = painter.GetRoundedBounds().Size(); m_arrTicks.Add(tick); dMark += dGridSpacing; } int nMinorCount = m_pAxis->GetMinorCount(); if (m_arrTicks.GetSize() > 0 && nMinorCount > 0) { double cur, prev; for (int i = 0; i <= m_arrTicks.GetSize(); i++) { if (m_pAxis->IsLogarithmic()) { cur = i == m_arrTicks.GetSize() ? m_arrTicks[i - 1].m_dValue * m_pAxis->GetLogarithmicBase() : m_arrTicks[i].m_dValue; prev = i == 0 ? m_arrTicks[0].m_dValue / m_pAxis->GetLogarithmicBase() : m_arrTicks[i - 1].m_dValue; } else { cur = i == m_arrTicks.GetSize() ? m_arrTicks[i - 1].m_dValue + dGridSpacing : m_arrTicks[i].m_dValue; prev = i == 0 ? cur - dGridSpacing : m_arrTicks[i - 1].m_dValue; } for (int j = 0; j < nMinorCount; j++) { double dValue = prev + (cur - prev) * (j + 1) / (nMinorCount + 1); if (dValue >= dViewMinValue && dValue <= dViewMaxValue) { m_arrMinorTicks.Add(dValue); } } } } } } void CXTPChartDiagram2DAxisView::CalcSize(CXTPChartDeviceContext* pDC, CRect rcDiagram) { CXTPChartAxis* pAxis = GetAxis(); double dScreenLength = IsVertical() ? rcDiagram.Height() : rcDiagram.Width(); if (dScreenLength < 1) { m_nSize = 0; return; } if (pAxis->GetGridSpacingAuto()) { double dRangeDelta = GetAxisRangeMaxValue() - GetAxisRangeMinValue(); m_dGridSpacing = CalculateGridSpacing(dRangeDelta, dScreenLength, IsVertical() ? 30 : 50); if (pAxis->IsLogarithmic()) m_dGridSpacing = max(1, m_dGridSpacing); } else { m_dGridSpacing = pAxis->GetGridSpacing(); } pAxis->m_dGridSpacing = m_dGridSpacing; CreateTickMarks(pDC, rcDiagram); if (!pAxis->IsVisible()) { m_nSize = 0; return; } BOOL bVertical = IsVertical(); m_nSize = pAxis->GetThickness(); if (pAxis->GetTickMarks()->IsVisible()) { m_nSize += pAxis->GetTickMarks()->GetLength(); } if (IsScollBarVisible()) { m_nSize += SCROLLBARSIZE; } if (pAxis->GetLabel()->IsVisible()) { int nLabelSize = 0; for (int i = 0; i < m_arrTicks.GetSize(); i++) { CSize szBounds = m_arrTicks[i].m_szBounds; nLabelSize = max(nLabelSize, bVertical ? szBounds.cx : szBounds.cy); } m_nSize += nLabelSize; } if (pAxis->GetTitle()->IsVisible()) { CXTPChartAxisTitle* pTitle = GetAxis()->GetTitle(); CXTPChartString strText = pTitle->GetText(); BOOL bNear = m_pAxis->GetAlignment() == xtpChartAxisNear; CXTPChartRotatedTextPainterNearLine painter(pDC, pTitle->GetText(), pTitle, CPoint(0, 0), IsVertical() ? (bNear ? xtpChartTextNearRight : xtpChartTextNearLeft) : (bNear ? xtpChartTextNearTop : xtpChartTextNearBottom), (float)(IsVertical() ? (bNear ? 270 : 90) : 0)); CSize szTitle = painter.GetRoundedBounds().Size(); m_nSize += bVertical ? szTitle.cx : szTitle.cy; } } BOOL CXTPChartDiagram2DAxisView::IsVertical() const { return m_pAxis->IsVertical(); } void CXTPChartDiagram2DAxisView::CreateView(CXTPChartDeviceContext* pDC) { UNREFERENCED_PARAMETER(pDC); } void CXTPChartAxisView::AddLegendItems() { CXTPChartElementView* pParentView = m_pParentView; while (pParentView->GetParentView() != NULL) pParentView = pParentView->GetParentView(); CXTPChartContentView* pContentView = (CXTPChartContentView*)pParentView; if (pContentView->GetLegendView()) { CXTPChartAxisConstantLines* pConstantLines = m_pAxis->GetConstantLines(); int i; for (i = 0; i < pConstantLines->GetCount(); i++) { CXTPChartAxisConstantLine* pConstantLine = pConstantLines->GetAt(i); if (!pConstantLine->IsVisible() || !pConstantLine->IsLegendVisible()) continue; pContentView->GetLegendView()->AddItem(pConstantLine); } CXTPChartAxisStrips* pStrips = m_pAxis->GetStrips(); for (i = 0; i < pStrips->GetCount(); i++) { CXTPChartAxisStrip* pStrip = pStrips->GetAt(i); if (!pStrip->IsVisible() || !pStrip->IsLegendVisible()) continue; pContentView->GetLegendView()->AddItem(pStrip); } } }