24 #include "KDChartCartesianCoordinatePlane_p.h" 27 #include "KDChartAbstractDiagram_p.h" 29 #include "CartesianCoordinateTransformation.h" 32 #include "KDChartPainterSaver_p.h" 36 #include <KDABLibFakes> 38 #include <QApplication> 50 CartesianCoordinatePlane::Private::Private()
52 , bPaintIsRunning( false )
53 , hasOwnGridAttributesHorizontal( false )
54 , hasOwnGridAttributesVertical( false )
55 , isometricScaling( false )
60 , autoAdjustHorizontalRangeToData( 67 )
61 , autoAdjustVerticalRangeToData( 67 )
62 , autoAdjustGridToZoom( true )
63 , fixedDataCoordinateSpaceRelation( false )
64 , xAxisStartAtZero( true )
65 , reverseVerticalPlane( false )
66 , reverseHorizontalPlane( false )
70 CartesianCoordinatePlane::CartesianCoordinatePlane(
Chart* parent )
81 void CartesianCoordinatePlane::init()
89 Q_ASSERT_X( dynamic_cast<AbstractCartesianDiagram*>( diagram ),
90 "CartesianCoordinatePlane::addDiagram",
"Only cartesian " 91 "diagrams can be added to a cartesian coordinate plane!" );
103 if (
d->bPaintIsRunning ) {
106 d->bPaintIsRunning =
true;
109 if ( !diags.isEmpty() )
118 PainterSaver painterSaver( painter );
119 QRect clipRect = drawArea.toRect().adjusted( -1, -1, 1, 1 );
120 QRegion clipRegion( clipRect );
121 painter->setClipRegion( clipRegion );
124 d->grid->drawGrid( &ctx );
127 for (
int i = 0; i < diags.size(); i++ )
129 if ( diags[i]->isHidden() ) {
132 bool doDumpPaintTime = AbstractDiagram::Private::get( diags[ i ] )->doDumpPaintTime;
134 if ( doDumpPaintTime ) {
138 PainterSaver diagramPainterSaver( painter );
139 diags[i]->paint( &ctx );
141 if ( doDumpPaintTime ) {
142 qDebug() <<
"Painting diagram" << i <<
"took" << stopWatch.elapsed() <<
"milliseconds";
147 d->bPaintIsRunning =
false;
163 bool bStarting =
true;
168 if ( bStarting || dataBoundariesPair.first.x() < minX ) minX = dataBoundariesPair.first.x();
169 if ( bStarting || dataBoundariesPair.first.y() < minY ) minY = dataBoundariesPair.first.y();
170 if ( bStarting || dataBoundariesPair.second.x() > maxX ) maxX = dataBoundariesPair.second.x();
171 if ( bStarting || dataBoundariesPair.second.y() > maxY ) maxY = dataBoundariesPair.second.y();
175 QRectF dataBoundingRect;
176 dataBoundingRect.setBottomLeft( QPointF( minX, minY ) );
177 dataBoundingRect.setTopRight( QPointF( maxX, maxY ) );
178 return dataBoundingRect;
183 const QRectF& r,
unsigned int percentX,
unsigned int percentY )
const 187 const bool isPositive = r.left() >= 0;
188 if ( ( r.right() >= 0 ) == isPositive ) {
189 qreal upperBound = qMax( r.left(), r.right() );
190 qreal lowerBound = qMin( r.left(), r.right() );
191 qreal innerBound = isPositive ? lowerBound : upperBound;
192 qreal outerBound = isPositive ? upperBound : lowerBound;
193 if ( innerBound / outerBound * 100 <= percentX &&
d->xAxisStartAtZero ) {
204 const bool isPositive = r.bottom() >= 0;
205 if ( ( r.top() >= 0 ) == isPositive ) {
206 qreal upperBound = qMax( r.top(), r.bottom() );
207 qreal lowerBound = qMin( r.top(), r.bottom() );
208 const qreal innerBound = isPositive ? lowerBound : upperBound;
209 const qreal outerBound = isPositive ? upperBound : lowerBound;
210 if ( innerBound / outerBound * 100 <= percentY ) {
212 ret.setBottom( 0.0 );
226 const bool bAutoAdjustHorizontalRange =
d->autoAdjustHorizontalRangeToData < 100;
227 const bool bAutoAdjustVerticalRange =
d->autoAdjustVerticalRangeToData < 100;
229 const bool bHardHorizontalRange = (!bAutoAdjustHorizontalRange) && (
d->horizontalMin !=
d->horizontalMax || (ISNAN(
d->horizontalMin) != ISNAN(
d->horizontalMax)));
230 const bool bHardVerticalRange = (!bAutoAdjustVerticalRange) && (
d->verticalMin !=
d->verticalMax || (ISNAN(
d->verticalMin) != ISNAN(
d->verticalMax)));
231 QRectF dataBoundingRect;
234 if ( bHardHorizontalRange && bHardVerticalRange ) {
235 dataBoundingRect.setLeft(
d->horizontalMin );
236 dataBoundingRect.setRight(
d->horizontalMax );
237 dataBoundingRect.setBottom(
d->verticalMin );
238 dataBoundingRect.setTop(
d->verticalMax );
242 if ( bHardHorizontalRange ) {
243 if (!ISNAN(
d->horizontalMin))
244 dataBoundingRect.setLeft(
d->horizontalMin );
245 if (!ISNAN(
d->horizontalMax))
246 dataBoundingRect.setRight(
d->horizontalMax );
248 if ( bHardVerticalRange ) {
249 if (!ISNAN(
d->verticalMin))
250 dataBoundingRect.setBottom(
d->verticalMin );
251 if (!ISNAN(
d->verticalMax))
252 dataBoundingRect.setTop(
d->verticalMax );
258 dataBoundingRect,
d->autoAdjustHorizontalRangeToData,
d->autoAdjustVerticalRangeToData );
259 if ( bAutoAdjustHorizontalRange ) {
263 if ( bAutoAdjustVerticalRange ) {
268 return dataBoundingRect;
286 const Qt::Orientation diagramOrientation = barDiagram != 0 ? barDiagram->
orientation() : Qt::Vertical;
287 const bool diagramIsVertical = diagramOrientation == Qt::Vertical;
300 diagramIsVertical ? ( !stockDiagram && dgr->
datasetDimension() > 1 ) :
true,
329 return QRectF(
areaGeometry() ).adjusted( 1.0, 1.0, -2.0, -2.0 );
335 if (
d->dimensions.isEmpty() )
340 const QPointF pt( qMin( dimX.
start, dimX.
end ), qMax( dimY.
start, dimY.
end ) );
342 const QRectF dataBoundingRect( pt, siz );
345 const QPointF topLeft(
d->reverseHorizontalPlane ? dataBoundingRect.right() : dataBoundingRect.left(),
346 d->reverseVerticalPlane ? dataBoundingRect.bottom() : dataBoundingRect.top() );
348 const qreal width = dataBoundingRect.width() * (
d->reverseHorizontalPlane ? -1.0 : 1.0 );
349 const qreal height = dataBoundingRect.height() * (
d->reverseVerticalPlane ? -1.0 : 1.0 );
351 return QRectF( topLeft, QSizeF( width, height ) );
357 QPointF physicalTopLeft =
d->coordinateTransformation.translate( logArea.topLeft() );
358 QPointF physicalBottomRight =
d->coordinateTransformation.translate( logArea.bottomRight() );
360 return QRectF( physicalTopLeft, physicalBottomRight ).normalized();
371 Q_ASSERT_X (
d->dimensions.count() == 2,
"CartesianCoordinatePlane::layoutDiagrams",
372 "Error: gridDimensionsList() did not return exactly two dimensions." );
384 d->coordinateTransformation.updateTransform( logArea, physicalArea );
391 d->fixedDataCoordinateSpaceRelation = fixed;
392 d->fixedDataCoordinateSpaceRelationPinnedSize = QSize();
398 return d->fixedDataCoordinateSpaceRelation;
403 if (
d->xAxisStartAtZero == fixedStart)
406 d->xAxisStartAtZero = fixedStart;
411 return d->xAxisStartAtZero;
416 if ( !
d->fixedDataCoordinateSpaceRelation ) {
420 if ( !geometry.isValid() ) {
427 if ( !
d->fixedDataCoordinateSpaceRelationPinnedSize.isValid() ) {
428 d->fixedDataCoordinateSpaceRelationPinnedSize = geometry.size();
434 if (
d->fixedDataCoordinateSpaceRelationPinnedSize != geometry.size() ) {
435 const qreal widthScaling =
d->fixedDataCoordinateSpaceRelationPinnedSize.width() / geometry.width();
436 const qreal heightScaling =
d->fixedDataCoordinateSpaceRelationPinnedSize.height() / geometry.height();
438 const qreal newZoomX =
d->fixedDataCoordinateSpaceRelationPinnedZoom.xFactor * widthScaling;
439 const qreal newZoomY =
d->fixedDataCoordinateSpaceRelationPinnedZoom.yFactor * heightScaling;
441 const QPointF newCenter = QPointF(
d->fixedDataCoordinateSpaceRelationPinnedZoom.xCenter / widthScaling,
442 d->fixedDataCoordinateSpaceRelationPinnedZoom.yCenter / heightScaling );
444 bool changed =
false;
462 return d->coordinateTransformation.translate( diagramPoint );
467 return d->coordinateTransformation.translateBack( screenPoint );
472 if (
d->isometricScaling != isOn ) {
473 d->isometricScaling = isOn;
481 return d->isometricScaling;
486 if (
d->coordinateTransformation.zoom.xFactor == factor ) {
489 d->coordinateTransformation.zoom.xFactor = factor;
490 if (
d->autoAdjustGridToZoom ) {
491 d->grid->setNeedRecalculate();
498 if (
d->coordinateTransformation.zoom.yFactor == factor ) {
501 d->coordinateTransformation.zoom.yFactor = factor;
502 if (
d->autoAdjustGridToZoom ) {
503 d->grid->setNeedRecalculate();
510 if (
d->coordinateTransformation.zoom.center() == point ) {
513 d->coordinateTransformation.zoom.setCenter( point );
514 if (
d->autoAdjustGridToZoom ) {
515 d->grid->setNeedRecalculate();
554 return d->coordinateTransformation.zoom.center();
559 return d->coordinateTransformation.zoom.xFactor;
564 return d->coordinateTransformation.zoom.yFactor;
570 return d->coordinateTransformation.axesCalcModeY;
575 return d->coordinateTransformation.axesCalcModeX;
580 if (
d->coordinateTransformation.axesCalcModeY != mode ||
581 d->coordinateTransformation.axesCalcModeX != mode ) {
582 d->coordinateTransformation.axesCalcModeY = mode;
583 d->coordinateTransformation.axesCalcModeX = mode;
593 if (
d->coordinateTransformation.axesCalcModeY != mode ) {
594 d->coordinateTransformation.axesCalcModeY = mode;
603 if (
d->coordinateTransformation.axesCalcModeX != mode ) {
604 d->coordinateTransformation.axesCalcModeX = mode;
611 inline bool fuzzyCompare( qreal a, qreal b )
613 if ( ISNAN(a) && ISNAN(b) )
615 if ( qFuzzyIsNull(a) && qFuzzyIsNull(b) )
617 return qFuzzyCompare( a, b );
623 const bool bAutoAdjustHorizontalRange =
d->autoAdjustHorizontalRangeToData < 100;
624 if ( !fuzzyCompare(
d->horizontalMin, range.first) || !fuzzyCompare(
d->horizontalMax, range.second) || bAutoAdjustHorizontalRange ) {
625 d->autoAdjustHorizontalRangeToData = 100;
626 d->horizontalMin = range.first;
627 d->horizontalMax = range.second;
636 const bool bAutoAdjustVerticalRange =
d->autoAdjustVerticalRangeToData < 100;
637 if ( !fuzzyCompare(
d->verticalMin, range.first) || !fuzzyCompare(
d->verticalMax, range.second) || bAutoAdjustVerticalRange ) {
638 d->autoAdjustVerticalRangeToData = 100;
639 d->verticalMin = range.first;
640 d->verticalMax = range.second;
660 d->horizontalMin = dataBoundingRect.left();
661 d->horizontalMax = dataBoundingRect.right();
662 d->verticalMin = dataBoundingRect.top();
663 d->verticalMax = dataBoundingRect.bottom();
671 d->horizontalMin = dataBoundingRect.left();
672 d->horizontalMax = dataBoundingRect.right();
680 d->verticalMin = dataBoundingRect.bottom();
681 d->verticalMax = dataBoundingRect.top();
688 if (
d->autoAdjustHorizontalRangeToData != percentEmpty )
690 d->autoAdjustHorizontalRangeToData = percentEmpty;
691 d->horizontalMin = 0.0;
692 d->horizontalMax = 0.0;
700 if (
d->autoAdjustVerticalRangeToData != percentEmpty )
702 d->autoAdjustVerticalRangeToData = percentEmpty;
703 d->verticalMin = 0.0;
704 d->verticalMax = 0.0;
712 return d->autoAdjustHorizontalRangeToData;
717 return d->autoAdjustVerticalRangeToData;
721 Qt::Orientation orientation,
724 if ( orientation == Qt::Horizontal )
725 d->gridAttributesHorizontal = a;
727 d->gridAttributesVertical = a;
728 setHasOwnGridAttributes( orientation,
true );
735 setHasOwnGridAttributes( orientation,
false );
742 if ( orientation == Qt::Horizontal )
743 return d->gridAttributesHorizontal;
745 return d->gridAttributesVertical;
751 void CartesianCoordinatePlane::setHasOwnGridAttributes( Qt::Orientation orientation,
bool on )
753 if ( orientation == Qt::Horizontal )
754 d->hasOwnGridAttributesHorizontal = on;
756 d->hasOwnGridAttributesVertical = on;
762 return orientation == Qt::Horizontal ?
d->hasOwnGridAttributesHorizontal
763 :
d->hasOwnGridAttributesVertical;
768 if (
d->autoAdjustGridToZoom != autoAdjust ) {
769 d->autoAdjustGridToZoom = autoAdjust;
770 d->grid->setNeedRecalculate();
775 #if QT_VERSION < 0x040400 || defined(Q_COMPILER_MANGLES_RETURN_TYPE) 780 return d->autoAdjustGridToZoom;
795 if ( p != 0 && p !=
this )
803 if ( plane ==
this || painter == 0 )
806 const QPointF zero = QPointF( 0, 0 );
807 const QPointF tenX = QPointF( 10, 0 );
808 const QPointF tenY = QPointF( 0, 10 );
813 painter->translate(
translate( zero ).x(), 0.0 );
815 painter->scale( factor, 1.0 );
816 painter->translate( -plane->
translate( zero ).x(), 0.0 );
820 painter->translate( 0.0,
translate( zero ).y() );
822 painter->scale( 1.0, factor );
823 painter->translate( 0.0, -plane->
translate( zero ).y() );
832 if (
d->reverseHorizontalPlane == reverse )
835 d->reverseHorizontalPlane = reverse;
842 return d->reverseHorizontalPlane;
847 if (
d->reverseVerticalPlane == reverse )
850 d->reverseVerticalPlane = reverse;
857 return d->reverseVerticalPlane;
867 result.setBottomRight(
translateBack( drawArea.bottomRight() ) );
878 d->geometry = rectangle;
879 if (
d->isometricScaling ) {
883 if ( hfw < rectangle.height() ) {
884 d->geometry.setHeight( hfw );
886 d->geometry.setWidth( qRound( qreal( rectangle.width() ) *
887 qreal( rectangle.height() ) / qreal( hfw ) ) );
894 diagram->
resize(
d->geometry.size() );
901 return d->isometricScaling ? Qt::Horizontal : ( Qt::Horizontal | Qt::Vertical );
906 return d->isometricScaling;
915 return qRound( qreal( w ) * qAbs( qreal( dataRect.height() ) / qreal( dataRect.width() ) ) );
921 if (
d->isometricScaling ) {
923 sh =
d->geometry.size();
void handleFixedDataCoordinateSpaceRelation(const QRectF &geometry)
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane, TernaryCoordinatePlane.
bool isVerticalRangeReversed() const
void setIsometricScaling(bool onOff)
If onOff is true, enforce that X and Y distances are scaled by the same factor.
void setZoomCenter(const QPointF ¢er) override
void layoutDiagrams() override
Distribute the available space among the diagrams and axes.
unsigned int autoAdjustVerticalRangeToData() const
Returns the maximal allowed percent of the vertical space covered by the coordinate plane that may be...
void setPainter(QPainter *painter)
void setHorizontalRangeReversed(bool reverse)
Sets whether the horizontal range should be reversed or not, i.e.
void addDiagram(AbstractDiagram *diagram) override
Adds a diagram to this coordinate plane.
QSize sizeHint() const override
QRect geometry() const override
pure virtual in QLayoutItem
void resetGridAttributes(Qt::Orientation orientation)
Reset the attributes to be used for grid lines drawn in horizontal direction (or in vertical directio...
A chart with one or more diagrams.
void setAxesCalcModeY(AxesCalcMode mode)
Specifies the calculation mode for all Ordinate axes.
ZoomParameters stores the center and the factor of zooming internally.
void setAutoAdjustVerticalRangeToData(unsigned int percentEmpty=67)
Automatically adjust vertical range settings to the ranges covered by the model's values...
void adjustHorizontalRangeToData()
Adjust horizontal range settings to the ranges covered by the model's data values.
QRectF diagramArea() const
Returns the (physical) area occupied by the diagram.
bool hasHeightForWidth() const override
void setGeometry(const QRect &r) override
reimplemented from AbstractCoordinatePlane
const QPointF translateBack(const QPointF &screenPoint) const
const QPointF translate(const QPointF &diagramPoint) const override
Translate the given point in value space coordinates to a position in pixel space.
void slotLayoutChanged(AbstractDiagram *)
QPair< qreal, qreal > verticalRange() const
const GridAttributes gridAttributes(Qt::Orientation orientation) const
void viewportCoordinateSystemChanged()
Emitted upon change of the view coordinate system.
virtual QRectF drawingArea() const
virtual void resize(const QSizeF &area)=0
Called by the widget's sizeEvent.
unsigned int autoAdjustHorizontalRangeToData() const
Returns the maximal allowed percent of the horizontal space covered by the coordinate plane that may ...
DataDimensionsList getDataDimensionsList() const override
qreal gridSubStepWidth() const
Returns the sub-step width to be used for calculating the sub-grid lines.
virtual QRectF calculateRawDataBoundingRect() const
Qt::Orientations expandingDirections() const override
QRectF adjustedToMaxEmptyInnerPercentage(const QRectF &r, unsigned int percentX, unsigned int percentY) const
BarDiagram defines a common bar diagram.
AbstractCoordinatePlane * sharedAxisMasterPlane(QPainter *p=0) override
reimpl
const bool autoAdjustGridToZoom() const
Return the status of the built-in grid adjusting feature.
qreal zoomFactorY() const override
void update()
Calling update() on the plane triggers the global KDChart::Chart::update()
void setXAxisStartAtZero(bool fixedStart)
Allows to fix the lower bound of X axis to zero when diagram is in first quadrant.
AbstractDiagram defines the interface for diagram classes.
void setGridAttributes(Qt::Orientation orientation, const GridAttributes &)
Set the attributes to be used for grid lines drawn in horizontal direction (or in vertical direction...
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
bool xAxisStartAtZero() const
void setAutoAdjustHorizontalRangeToData(unsigned int percentEmpty=67)
Automatically adjust horizontal range settings to the ranges covered by the model's values...
bool isHorizontalRangeReversed() const
The class for cartesian axes.
QPointF zoomCenter() const override
void setFixedDataCoordinateSpaceRelation(bool fixed)
Allows to specify a fixed data-space / coordinate-space relation.
QRectF visibleDiagramArea() const
Returns the visible part of the diagram area, i.e.
bool doneSetZoomFactorX(qreal factor)
void setHorizontalRange(const QPair< qreal, qreal > &range)
Set the boundaries of the visible value space displayed in horizontal direction.
AbstractDiagram * diagram()
QSize sizeHint() const override
pure virtual in QLayoutItem
qreal gridStepWidth() const
Returns the step width to be used for calculating the grid lines.
void setZoomFactorY(qreal factor) override
void setZoomFactors(qreal factorX, qreal factorY) override
virtual bool isOrdinate() const
virtual AbstractCartesianDiagram * referenceDiagram() const
QPair< qreal, qreal > horizontalRange() const
virtual KDChart::CartesianAxisList axes() const
bool hasFixedDataCoordinateSpaceRelation() const
virtual bool isAbscissa() const
bool doneSetZoomCenter(const QPointF ¢er)
Qt::Orientation orientation() const
void paint(QPainter *) override
reimpl
bool hasOwnGridAttributes(Qt::Orientation orientation) const
~CartesianCoordinatePlane() override
void setVerticalRangeReversed(bool reverse)
Sets whether the vertical range should be reversed or not, i.e.
Base class for diagrams based on a cartesian coordianate system.
Stores information about painting diagrams.
void setVerticalRange(const QPair< qreal, qreal > &range)
Set the boundaries of the visible value space displayed in vertical direction.
KDChartEnums::GranularitySequence gridGranularitySequence() const
Returns the granularity sequence to be used for calculating the grid lines.
AxesCalcMode axesCalcModeY() const
void adjustRangesToData()
Adjust both, horizontal and vertical range settings to the ranges covered by the model's data values...
A set of attributes controlling the appearance of grids.
AxesCalcMode axesCalcModeX() const
DataDimensionsList gridDimensionsList()
Returns the dimensions used for drawing the grid lines.
void setAxesCalcModeX(AxesCalcMode mode)
Specifies the calculation mode for all Abscissa axes.
qreal distance() const
Returns the size of the distance, equivalent to the width() (or height(), resp.) of a QRectF...
void propertiesChanged()
Emitted upon change of a property of the Coordinate Plane or any of its components.
int heightForWidth(int w) const override
void setAxesCalcModes(AxesCalcMode mode)
Specifies the calculation modes for all axes.
GridAttributes globalGridAttributes() const
Cartesian coordinate plane.
void setCoordinatePlane(AbstractCoordinatePlane *plane)
QRectF getRawDataBoundingRectFromDiagrams() const
void setRectangle(const QRectF &rect)
AbstractDiagramList diagrams()
virtual void addDiagram(AbstractDiagram *diagram)
Adds a diagram to this coordinate plane.
Helper class for one dimension of data, e.g.
void adjustVerticalRangeToData()
Adjust vertical range settings to the ranges covered by the model's data values.
void setAutoAdjustGridToZoom(bool autoAdjust)
Disable / re-enable the built-in grid adjusting feature.
void setGeometry(const QRect &r) override
pure virtual in QLayoutItem
int datasetDimension() const
The dataset dimension of a diagram determines how many value dimensions it expects each datapoint to ...
QRectF visibleDataRange() const
Returns the currently visible data range.
const AbstractCoordinatePlane * coordinatePlane() const
Convenience function, returns the coordinate plane, in which this axis is used.
qreal zoomFactorX() const override
void setGridNeedsRecalculate()
Used by the chart to clear the cached grid data.
QRectF logicalArea() const
Returns the logical area, i.e., the rectangle defined by the very top left and very bottom right coor...
QRect areaGeometry() const override
void setZoomFactorX(qreal factor) override
bool doneSetZoomFactorY(qreal factor)
bool doesIsometricScaling() const