kchart

KDChartHiLoPainter.cpp
1/*
2 KDChart - a multi-platform charting engine
3 */
4
5/****************************************************************************
6 ** Copyright (C) 2001-2003 Klarälvdalens Datakonsult AB. All rights reserved.
7 **
8 ** This file is part of the KDChart library.
9 **
10 ** This file may be distributed and/or modified under the terms of the
11 ** GNU General Public License version 2 as published by the Free Software
12 ** Foundation and appearing in the file LICENSE.GPL included in the
13 ** packaging of this file.
14 **
15 ** Licensees holding valid commercial KDChart licenses may use this file in
16 ** accordance with the KDChart Commercial License Agreement provided with
17 ** the Software.
18 **
19 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
20 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 **
22 ** See http://www.klaralvdalens-datakonsult.se/?page=products for
23 ** information about KDChart Commercial License Agreements.
24 **
25 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
26 ** licensing are not clear to you.
27 **
28 **********************************************************************/
29#include "KDChartHiLoPainter.h"
30#include <KDChartParams.h>
31#include "KDChartTextPiece.h"
32
33#include <tqpainter.h>
34
35#include <stdlib.h>
36
49KDChartAxesPainter( params )
50{
51 // This constructor intentionally left blank so far; we cannot setup the
52 // geometry yet since we do not know the size of the painter.
53}
54
55
60{
61 // intentionally left blank
62}
63
64
78TQString KDChartHiLoPainter::fallbackLegendText( uint dataset ) const
79{
80 return TQObject::tr( "Value " ) + TQString::number( dataset + 1 );
81}
82
83
94{
95 return data->usedRows();
96}
97
98
99bool KDChartHiLoPainter::isNormalMode() const
100{
101 return KDChartParams::HiLoNormal == params()->hiLoChartSubType();
102}
103
104int KDChartHiLoPainter::clipShiftUp( bool, double ) const
105{
106 return 0;
107}
108
109void KDChartHiLoPainter::specificPaintData( TQPainter* painter,
110 const TQRect& ourClipRect,
112 KDChartDataRegionList* /*regions*/,
113 const KDChartAxisParams* axisPara,
114 bool /*bNormalMode*/,
115 uint /*chart*/,
116 double logWidth,
117 double areaWidthP1000,
118 double logHeight,
119 double axisYOffset,
120 double /*minColumnValue*/,
121 double /*maxColumnValue*/,
122 double /*columnValueDistance*/,
123 uint chartDatasetStart,
124 uint chartDatasetEnd,
125 uint datasetStart,
126 uint datasetEnd )
127{
128 double areaHeightP1000 = logHeight / 1000.0;
129 double averageValueP1000 = ( areaWidthP1000 + areaHeightP1000 ) / 2.0;
130 int datasetNum=abs(static_cast<int>(chartDatasetEnd-chartDatasetStart))+1;
131
132 painter->setPen( params()->outlineDataColor() );
133
134 // Number of values: If -1, use all values, otherwise use the
135 // specified number of values.
136 int numValues = 0;
137 if ( params()->numValues() != -1 )
138 numValues = params()->numValues();
139 else
140 numValues = data->usedCols();
141
142 // We need to make sure that we have a certain number of
143 // cells in the dataset(s), depending on the sub type to display.
144 if( (numValues < 2) ||
145 ((params()->hiLoChartSubType() == KDChartParams::HiLoClose) && (numValues < 3)) ||
146 ((params()->hiLoChartSubType() == KDChartParams::HiLoOpenClose) && (numValues < 4)) ){
147 tqDebug( "\nNot enough data to display a High/Low Chart!\n" );
148 tqDebug( "type requiring" );
149 tqDebug( "---- ---------" );
150 tqDebug( "High/Low 2 data cells per series" );
151 tqDebug( "High/Low/Close 3 data cells per series" );
152 tqDebug( "High/Low/open/Close 4 data cells per series\n" );
153 return; // PENDING(kalle) Throw exception?
154 }
155
156 double pixelsPerUnit = 0.0;
157 if( 0.0 != axisPara->trueAxisHigh() - axisPara->trueAxisLow() )
158 pixelsPerUnit = logHeight / (axisPara->trueAxisHigh() - axisPara->trueAxisLow());
159 else
160 pixelsPerUnit = logHeight / 10;
161
162 // Distance between the individual "stocks"
163 double pointDist = logWidth / (double)datasetNum;
164
165 // compute the position of the 0 axis
166 double zeroXAxisI = axisPara->axisZeroLineStartY() - _dataRect.y();
167
168 const int nLineWidth = params()->lineWidth();
169
170 // Loop over the datasets, draw one "stock" line for each series.
171 for ( uint dataset = chartDatasetStart;
172 dataset <= chartDatasetEnd;
173 ++dataset ) {
174 // The first and the second col are always high and low; we sort them
175 // accordingly.
176 TQVariant valueA;
177 TQVariant valueB;
178 if( dataset >= datasetStart &&
179 dataset <= datasetEnd &&
180 data->cellCoord( dataset, 0, valueA, 1 ) &&
181 data->cellCoord( dataset, 1, valueB, 1 ) &&
182 TQVariant::Double == valueA.type() &&
183 TQVariant::Double == valueB.type() ){
184 const double cellValue1 = valueA.toDouble();
185 const double cellValue2 = valueB.toDouble();
186 const double lowValue = TQMIN( cellValue1, cellValue2 );
187 const double highValue = TQMAX( cellValue1, cellValue2 );
188 const double lowDrawValue = lowValue * pixelsPerUnit;
189 const double highDrawValue = highValue * pixelsPerUnit;
190
191 painter->setPen( TQPen( params()->dataColor( dataset ),
192 nLineWidth ) );
193 // draw line from low to high
194 int xpos = static_cast<int>(
195 pointDist * ( (double)(dataset-chartDatasetStart) + 0.5 ) );
196 int lowYPos = static_cast<int>( zeroXAxisI - lowDrawValue );
197 int highYPos = static_cast<int>( zeroXAxisI - highDrawValue );
198
199 painter->drawLine( xpos, lowYPos, xpos, highYPos );
200
201 // Find out how long open/close lines need to be in case we
202 // need them. We make them 1/10 of the space available for one
203 // "stock".
204 int openCloseTickLength = static_cast<int>( pointDist * 0.1 );
205 // we need these here because we might need to consider these
206 // later when drawing the low and high labels
207 bool hasOpen = false, hasClose = false;
208 double openValue = 0.0, openDrawValue = 0.0,
209 closeValue = 0.0, closeDrawValue = 0.0;
210
211 // if we have an open/close chart, show the open value
212 if( params()->hiLoChartSubType() == KDChartParams::HiLoOpenClose ) {
213 // Only do this if there is a value in the third col.
214 if( data->cellCoord( dataset, 2, valueA, 1 ) &&
215 TQVariant::Double == valueA.type() ) {
216 hasOpen = true;
217 openValue = valueA.toDouble();
218 openDrawValue = openValue * pixelsPerUnit;
219 painter->drawLine( xpos - openCloseTickLength,
220 static_cast<int>( zeroXAxisI - openDrawValue ),
221 xpos,
222 static_cast<int>( zeroXAxisI - openDrawValue ) );
223 }
224 }
225
226 // If we have an open/close chart or a close chart, show the
227 // close value, but only if there is a value in the
228 // corresponding column (2 for HiLoClose, 3 for
229 // HiLoOpenClose).
230 if( ( params()->hiLoChartSubType() == KDChartParams::HiLoClose &&
231 data->cellCoord( dataset, 2, valueA, 1 ) &&
232 TQVariant::Double == valueA.type() ) ||
233 ( params()->hiLoChartSubType() == KDChartParams::HiLoOpenClose &&
234 data->cellCoord( dataset, 3, valueB, 1 ) &&
235 TQVariant::Double == valueB.type() ) ) {
236 hasClose = true;
237 closeValue = ( params()->hiLoChartSubType() == KDChartParams::HiLoClose )
238 ? valueA.toDouble()
239 : valueB.toDouble();
240 closeDrawValue = closeValue * pixelsPerUnit;
241 painter->drawLine( xpos,
242 static_cast<int>( zeroXAxisI - closeDrawValue ),
243 xpos + openCloseTickLength,
244 static_cast<int>( zeroXAxisI - closeDrawValue ) );
245 }
246
247 // Draw the low value, if requested.
248 if( params()->hiLoChartPrintLowValues() ) {
249 // PENDING(kalle) Number formatting?
250 TQFont theFont( params()->hiLoChartLowValuesFont() );
251 if ( params()->hiLoChartLowValuesUseFontRelSize() ) {
252 int nTxtHeight =
253 static_cast < int > ( params()->hiLoChartLowValuesFontRelSize()
254 * averageValueP1000 );
255 theFont.setPointSizeFloat( nTxtHeight );
256 }
257 KDChartTextPiece lowText( painter, TQString::number( lowValue ),
258 theFont );
259 int width = lowText.width();
260 int height = lowText.height();
261
262 // Check whether there is enough space below the data display
263 int valX = 0, valY = 0;
264 //tqDebug("\nzeroXAxisI %f lowDrawValue %f height %i logHeight %f _dataRect.y() %i axisYOffset %f",zeroXAxisI,highDrawValue,height,logHeight,_dataRect.y(),axisYOffset);
265 //tqDebug("zeroXAxisI - lowDrawValue + height %f < axisYOffset + logHeight %f",
266 //zeroXAxisI - lowDrawValue + height, axisYOffset+logHeight);
267 if( zeroXAxisI - lowDrawValue + height < axisYOffset+logHeight ) {
268 // enough space
269 valX = xpos - ( width / 2 );
270 valY = (int)lowDrawValue - lowText.fontLeading();
271 } else {
272 // not enough space - move to left
273 if( !hasOpen || height < openDrawValue ) {
274 // Either there is no open value or it is high enough
275 // that we can put the low value to the left.
276 valX = xpos - width - nLineWidth;
277 valY = static_cast<int>(zeroXAxisI)
278 - lowYPos
279 + height/2
280 + nLineWidth/2;
281 } else
282 ; // no way to draw it (really?)
283 }
284 lowText.draw( painter,
285 valX, static_cast<int>( zeroXAxisI - valY ),
286 ourClipRect,
287 params()->hiLoChartLowValuesColor() );
288 }
289
290 // Draw the high value, if requested.
291 if( params()->hiLoChartPrintHighValues() ) {
292 // PENDING(kalle) Number formatting?
293 TQFont theFont( params()->hiLoChartHighValuesFont() );
294 if ( params()->hiLoChartHighValuesUseFontRelSize() ) {
295 int nTxtHeight =
296 static_cast < int > ( params()->hiLoChartHighValuesFontRelSize()
297 * averageValueP1000 );
298 theFont.setPointSizeFloat( nTxtHeight );
299 }
300 KDChartTextPiece highText( painter, TQString::number( highValue ),
301 theFont );
302 int width = highText.width();
303 int height = highText.height();
304
305 // Check whether there is enough space above the data display
306 int valX = 0, valY = 0;
307 if( zeroXAxisI - highDrawValue - height > axisYOffset ) {
308 // enough space
309 valX = xpos - ( width / 2 );
310 valY = (int)highDrawValue + highText.fontLeading() + height;
311 } else {
312 // not enough space - move to right
313 if( !hasClose ||
314 height < ( _dataRect.height() - closeDrawValue ) ) {
315 // Either there is no close value or it is low enough
316 // that we can put the high value to the right.
317 valX = xpos + nLineWidth;
318 valY = static_cast<int>(zeroXAxisI)
319 - highYPos
320 + height/2
321 - nLineWidth/2;
322 } else
323 ; // no way to draw it (really?)
324 }
325 highText.draw( painter,
326 valX, static_cast<int>( zeroXAxisI - valY ),
327 ourClipRect,
328 params()->hiLoChartHighValuesColor() );
329 }
330
331 // Draw the open value, if requested.
332 if( params()->hiLoChartPrintOpenValues() &&
333 params()->hiLoChartSubType() == KDChartParams::HiLoOpenClose ) {
334 // PENDING(kalle) Number formatting?
335 TQFont theFont( params()->hiLoChartOpenValuesFont() );
336 if ( params()->hiLoChartOpenValuesUseFontRelSize() ) {
337 int nTxtHeight =
338 static_cast < int > ( params()->hiLoChartOpenValuesFontRelSize()
339 * averageValueP1000 );
340 theFont.setPointSizeFloat( nTxtHeight );
341 }
342 KDChartTextPiece openText( painter, TQString::number( openValue ),
343 theFont );
344 int width = openText.width();
345 int height = openText.height();
346
347 // We can pretty safely assume that there is always enough
348 // space to the left and right of the data display.
349 int valX = 0, valY = 0;
350 valX = xpos - openCloseTickLength - width;
351 valY = (int)openDrawValue + ( height / 2 );
352 openText.draw( painter,
353 valX, static_cast<int>( zeroXAxisI - valY ),
354 ourClipRect,
355 params()->hiLoChartOpenValuesColor() );
356 }
357
358 // Draw the close value, if requested.
359 if( params()->hiLoChartPrintCloseValues() &&
360 ( params()->hiLoChartSubType() == KDChartParams::HiLoOpenClose
361 ||
362 params()->hiLoChartSubType() == KDChartParams::HiLoClose ) ) {
363 // PENDING(kalle) Number formatting?
364 TQFont theFont( params()->hiLoChartCloseValuesFont() );
365 if ( params()->hiLoChartCloseValuesUseFontRelSize() ) {
366 int nTxtHeight =
367 static_cast < int > ( params()->hiLoChartCloseValuesFontRelSize()
368 * averageValueP1000 );
369 theFont.setPointSizeFloat( nTxtHeight );
370 }
371 KDChartTextPiece closeText( painter, TQString::number( closeValue ),
372 theFont );
373 //int width = closeText.width();
374 int height = closeText.height();
375
376 // We can pretty safely assume that there is always enough
377 // space to the left and right of the data display.
378 int valX = 0, valY = 0;
379 valX = xpos + openCloseTickLength;
380 valY = (int)closeDrawValue + ( height / 2 );
381 closeText.draw( painter,
382 valX, static_cast<int>( zeroXAxisI - valY ),
383 ourClipRect,
384 params()->hiLoChartCloseValuesColor() );
385 }
386
387 } else
388 continue; // we cannot display this value
389 }
390}
Header for all common chart parameters.
A common base class for classes that implement chart painters for chart types ith axes.
access the chart axis parameters.
double trueAxisHigh() const
Returns the true end value of the ordinate axis labels as is was calculated and set by setTrueAxisLow...
double trueAxisLow() const
Returns the true start value of the ordinate axis labels as is was calculated and set by setTrueAxisL...
double axisZeroLineStartY() const
Returns the not-rounded y-position where drawing of this axis zero line started.
The collection class used by KD Chart to store data region information.
virtual TQString fallbackLegendText(uint dataset) const
This method is a specialization that returns a fallback legend text appropriate for HiLo that do not ...
virtual uint numLegendFallbackTexts(KDChartTableDataBase *data) const
This methods returns the number of elements to be shown in the legend in case fallback texts are used...
KDChartHiLoPainter(KDChartParams *params)
Constructor.
virtual ~KDChartHiLoPainter()
Destructor.
Bundles the display parameters of a chart.
TQColor hiLoChartCloseValuesColor() const
Returns the colour of the font size to be used for printing the close values.
bool hiLoChartPrintOpenValues() const
Returns whether the open values will be printed under their respective entries.
bool hiLoChartPrintCloseValues() const
Returns whether the close values will be printed under their respective entries.
bool hiLoChartPrintLowValues() const
Returns whether the low values will be printed under their respective entries.
int hiLoChartCloseValuesFontRelSize() const
Returns the relative size (in per mille of the chart width) of font size to be used for printing the ...
TQColor hiLoChartHighValuesColor() const
Returns the colour of the font size to be used for printing the high values.
int numValues() const
Returns how many of the values should be shown.
TQColor hiLoChartOpenValuesColor() const
Returns the colour of the font size to be used for printing the open values.
int hiLoChartOpenValuesFontRelSize() const
Returns the relative size (in per mille of the chart width) of font size to be used for printing the ...
int lineWidth() const
Returns the line width of the lines in line charts.
int hiLoChartLowValuesFontRelSize() const
Returns the relative size (in per mille of the chart width) of font size to be used for printing the ...
TQColor hiLoChartLowValuesColor() const
Returns the colour of the font size to be used for printing the low values.
int hiLoChartHighValuesFontRelSize() const
Returns the relative size (in per mille of the chart width) of font size to be used for printing the ...
HiLoChartSubType hiLoChartSubType() const
Returns the HiLo chart subtype.
bool hiLoChartPrintHighValues() const
Returns whether the high values will be printed under their respective entries.
KD Chart's build-in table data for an easy way of storing data values.
virtual uint usedCols() const
Returns the number of cols in the table that actually contain data.
virtual bool cellCoord(uint _row, uint _col, TQVariant &_value, int coordinate=1) const =0
Returns one of the coordinate data value(s) stored in a cell.
virtual uint usedRows() const
Returns the number of rows in the table that actually contain data.