KD Chart API Documentation 3.1
Loading...
Searching...
No Matches
KDChartCartesianCoordinatePlane.cpp
Go to the documentation of this file.
1/****************************************************************************
2**
3** This file is part of the KD Chart library.
4**
5** SPDX-FileCopyrightText: 2001 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
6**
7** SPDX-License-Identifier: MIT
8**
9****************************************************************************/
10
12#include "KDChartCartesianCoordinatePlane_p.h"
13
17#include "KDChartAbstractDiagram_p.h"
18#include "KDChartBarDiagram.h"
20#include "KDChartPaintContext.h"
21#include "KDChartPainterSaver_p.h"
22#include "KDChartStockDiagram.h"
23
24#include <KDABLibFakes>
25
26#include <QApplication>
27#include <QElapsedTimer>
28#include <QFont>
29#include <QList>
30#include <QPainter>
31#include <QtDebug>
32
33using namespace KDChart;
34
35#define d d_func()
36
37CartesianCoordinatePlane::Private::Private()
38 : AbstractCoordinatePlane::Private()
39{
40}
41
43 : AbstractCoordinatePlane(new Private(), parent)
44{
45 // this block left empty intentionally
46}
47
49{
50 // this block left empty intentionally
51}
52
53void CartesianCoordinatePlane::init()
54{
55 // this block left empty intentionally
56}
57
59{
61 "CartesianCoordinatePlane::addDiagram", "Only cartesian "
62 "diagrams can be added to a cartesian coordinate plane!");
66
68}
69
71{
72 // prevent recursive call:
73 if (d->bPaintIsRunning) {
74 return;
75 }
76 d->bPaintIsRunning = true;
77
79 if (!diags.isEmpty()) {
81 ctx.setPainter(painter);
82 ctx.setCoordinatePlane(this);
84 ctx.setRectangle(drawArea);
85
86 // enabling clipping so that we're not drawing outside
88 QRect clipRect = drawArea.toRect().adjusted(-1, -1, 1, 1);
89 QRegion clipRegion(clipRect);
90 painter->setClipRegion(clipRegion);
91
92 // paint the coordinate system rulers:
93 d->grid->drawGrid(&ctx);
94
95 // paint the diagrams:
96 for (int i = 0; i < diags.size(); i++) {
97 if (diags[i]->isHidden()) {
98 continue;
99 }
100 bool doDumpPaintTime = AbstractDiagram::Private::get(diags[i])->doDumpPaintTime;
102 if (doDumpPaintTime) {
104 }
105
107 diags[i]->paint(&ctx);
108
109 if (doDumpPaintTime) {
110 qDebug() << "Painting diagram" << i << "took" << stopWatch.elapsed() << "milliseconds";
111 }
112 }
113 }
114 d->bPaintIsRunning = false;
115}
116
121
123{
124 // determine unit of the rectangles of all involved diagrams:
125 qreal minX = 0;
126 qreal maxX = 0;
127 qreal minY = 0;
128 qreal maxY = 0;
129 bool bStarting = true;
130 const auto constDiagrams = diagrams();
131 for (const AbstractDiagram *diagram : constDiagrams) {
133 // qDebug() << "CartesianCoordinatePlane::getRawDataBoundingRectFromDiagrams()\ngets diagram->dataBoundaries: " << dataBoundariesPair.first << dataBoundariesPair.second;
134 if (bStarting || dataBoundariesPair.first.x() < minX)
135 minX = dataBoundariesPair.first.x();
136 if (bStarting || dataBoundariesPair.first.y() < minY)
137 minY = dataBoundariesPair.first.y();
138 if (bStarting || dataBoundariesPair.second.x() > maxX)
139 maxX = dataBoundariesPair.second.x();
140 if (bStarting || dataBoundariesPair.second.y() > maxY)
141 maxY = dataBoundariesPair.second.y();
142 bStarting = false;
143 }
144 // qDebug() << "CartesianCoordinatePlane::getRawDataBoundingRectFromDiagrams()\nreturns data boundaries: " << QRectF( QPointF(minX, minY), QSizeF(maxX - minX, maxY - minY) );
147 dataBoundingRect.setTopRight(QPointF(maxX, maxY));
148 return dataBoundingRect;
149}
150
152 const QRectF &r, unsigned int percentX, unsigned int percentY) const
153{
154 QRectF ret = r;
155 if ((axesCalcModeX() != Logarithmic || r.left() < 0.0) && percentX > 0 && percentX != 100) {
156 const bool isPositive = r.left() >= 0;
157 if ((r.right() >= 0) == isPositive) {
158 qreal upperBound = qMax(r.left(), r.right());
159 qreal lowerBound = qMin(r.left(), r.right());
160 qreal innerBound = isPositive ? lowerBound : upperBound;
161 qreal outerBound = isPositive ? upperBound : lowerBound;
162 if (innerBound / outerBound * 100 <= percentX && d->xAxisStartAtZero) {
163 if (isPositive) {
164 ret.setLeft(0.0);
165 } else {
166 ret.setRight(0.0);
167 }
168 }
169 }
170 }
171 // ### this doesn't seem to take into account that Qt's y coordinate is inverted
172 if ((axesCalcModeY() != Logarithmic || r.bottom() < 0.0) && percentY > 0 && percentY != 100) {
173 const bool isPositive = r.bottom() >= 0;
174 if ((r.top() >= 0) == isPositive) {
175 qreal upperBound = qMax(r.top(), r.bottom());
176 qreal lowerBound = qMin(r.top(), r.bottom());
177 const qreal innerBound = isPositive ? lowerBound : upperBound;
178 const qreal outerBound = isPositive ? upperBound : lowerBound;
179 if (innerBound / outerBound * 100 <= percentY) {
180 if (isPositive) {
181 ret.setBottom(0.0);
182 } else {
183 ret.setTop(0.0);
184 }
185 }
186 }
187 }
188 return ret;
189}
190
192{
193 // are manually set ranges to be applied?
194 const bool bAutoAdjustHorizontalRange = d->autoAdjustHorizontalRangeToData < 100;
195 const bool bAutoAdjustVerticalRange = d->autoAdjustVerticalRangeToData < 100;
196
197 const bool bHardHorizontalRange = (!bAutoAdjustHorizontalRange) && (d->horizontalMin != d->horizontalMax || (ISNAN(d->horizontalMin) != ISNAN(d->horizontalMax)));
198 const bool bHardVerticalRange = (!bAutoAdjustVerticalRange) && (d->verticalMin != d->verticalMax || (ISNAN(d->verticalMin) != ISNAN(d->verticalMax)));
200
201 // if custom boundaries are set on the plane, use them
203 dataBoundingRect.setLeft(d->horizontalMin);
204 dataBoundingRect.setRight(d->horizontalMax);
205 dataBoundingRect.setBottom(d->verticalMin);
206 dataBoundingRect.setTop(d->verticalMax);
207 } else {
208 // determine unit of the rectangles of all involved diagrams:
211 if (!ISNAN(d->horizontalMin))
212 dataBoundingRect.setLeft(d->horizontalMin);
213 if (!ISNAN(d->horizontalMax))
214 dataBoundingRect.setRight(d->horizontalMax);
215 }
216 if (bHardVerticalRange) {
217 if (!ISNAN(d->verticalMin))
218 dataBoundingRect.setBottom(d->verticalMin);
219 if (!ISNAN(d->verticalMax))
220 dataBoundingRect.setTop(d->verticalMax);
221 }
222 }
223 // recalculate the bounds, if automatic adjusting of ranges is desired AND
224 // both bounds are at the same side of the zero line
226 dataBoundingRect, d->autoAdjustHorizontalRangeToData, d->autoAdjustVerticalRangeToData);
228 const_cast<CartesianCoordinatePlane *>(this)->d->horizontalMin = dataBoundingRect.left();
229 const_cast<CartesianCoordinatePlane *>(this)->d->horizontalMax = dataBoundingRect.right();
230 }
232 const_cast<CartesianCoordinatePlane *>(this)->d->verticalMin = dataBoundingRect.bottom();
233 const_cast<CartesianCoordinatePlane *>(this)->d->verticalMax = dataBoundingRect.top();
234 }
235 // qDebug() << Q_FUNC_INFO << dataBoundingRect;
236 return dataBoundingRect;
237}
238
240{
242 if (dgr && dgr->referenceDiagram()) {
243 dgr = dgr->referenceDiagram();
244 }
245 const auto *barDiagram = qobject_cast<const BarDiagram *>(dgr);
247
248 // note:
249 // It does make sense to retrieve the orientation from the first diagram. This is because
250 // a coordinate plane can either be for horizontal *or* for vertical diagrams. Both at the
251 // same time won't work, and thus the orientation for all diagrams is the same as for the first one.
252 const Qt::Orientation diagramOrientation = barDiagram != nullptr ? barDiagram->orientation() : Qt::Vertical;
254
256 if (dgr) {
258 // We do not access d->gridAttributesHorizontal/Vertical here, but we use the getter function,
259 // to get the global attrs, if no special ones have been set for the given orientation.
262 // append the first dimension: for Abscissa axes
263 l.append(
265 r.left(), r.right(),
266 diagramIsVertical ? (!stockDiagram && dgr->datasetDimension() > 1) : true,
268 gaH.gridGranularitySequence(),
269 gaH.gridStepWidth(),
270 gaH.gridSubStepWidth()));
271 // append the second dimension: for Ordinate axes
272 l.append(
274 r.bottom(), r.top(),
275 diagramIsVertical ? true : (dgr->datasetDimension() > 1),
277 gaV.gridGranularitySequence(),
278 gaV.gridStepWidth(),
279 gaV.gridSubStepWidth()));
280 } else {
281 l.append(DataDimension()); // This gets us the default 1..0 / 1..0 grid
282 l.append(DataDimension()); // shown, if there is no diagram on this plane.
283 }
284 return l;
285}
286
288{
289 // the rectangle the diagrams cover in the *plane*:
290 // We reserve 1px on each side for antialiased drawing, and respect the way QPainter calculates
291 // the width of a painted rect (the size is the rectangle size plus the pen width). The latter
292 // accounts for another pixel that we subtract from height and width.
293 // This way, most clipping for regular pens should be avoided. When pens with a width larger
294 // than 1 are used, this may not be sufficient.
295 return QRectF(areaGeometry()).adjusted(1.0, 1.0, -2.0, -2.0);
296}
297
299{
300 if (d->dimensions.isEmpty())
301 return QRectF();
302
303 const DataDimension dimX = d->dimensions.first();
304 const DataDimension dimY = d->dimensions.last();
305 const QPointF pt(qMin(dimX.start, dimX.end), qMax(dimY.start, dimY.end));
306 const QSizeF siz(qAbs(dimX.distance()), -qAbs(dimY.distance()));
308
309 // determine logical top left, taking the "reverse" options into account
310 const QPointF topLeft(d->reverseHorizontalPlane ? dataBoundingRect.right() : dataBoundingRect.left(),
311 d->reverseVerticalPlane ? dataBoundingRect.bottom() : dataBoundingRect.top());
312
313 const qreal width = dataBoundingRect.width() * (d->reverseHorizontalPlane ? -1.0 : 1.0);
314 const qreal height = dataBoundingRect.height() * (d->reverseVerticalPlane ? -1.0 : 1.0);
315
316 return QRectF(topLeft, QSizeF(width, height));
317}
318
320{
321 const QRectF logArea(logicalArea());
322 QPointF physicalTopLeft = d->coordinateTransformation.translate(logArea.topLeft());
323 QPointF physicalBottomRight = d->coordinateTransformation.translate(logArea.bottomRight());
324
326}
327
332
334{
335 d->dimensions = gridDimensionsList();
336 Q_ASSERT_X(d->dimensions.count() == 2, "CartesianCoordinatePlane::layoutDiagrams",
337 "Error: gridDimensionsList() did not return exactly two dimensions.");
338
339 // physical area of the plane
341 // .. in contrast to the logical area
342 const QRectF logArea(logicalArea());
343
344 // TODO: isometric scaling for zooming?
345
346 // the plane area might have changed, so the zoom values might also be changed
348
349 d->coordinateTransformation.updateTransform(logArea, physicalArea);
350
351 update();
352}
353
355{
356 d->fixedDataCoordinateSpaceRelation = fixed;
357 d->fixedDataCoordinateSpaceRelationPinnedSize = QSize();
359}
360
362{
363 return d->fixedDataCoordinateSpaceRelation;
364}
365
367{
368 if (d->xAxisStartAtZero == fixedStart)
369 return;
370
371 d->xAxisStartAtZero = fixedStart;
372}
373
375{
376 return d->xAxisStartAtZero;
377}
378
380{
381 if (!d->fixedDataCoordinateSpaceRelation) {
382 return;
383 }
384 // is the new geometry ok?
385 if (!geometry.isValid()) {
386 return;
387 }
388
389 // note that the pinned size can be invalid even after setting it, if geometry wasn't valid.
390 // this is relevant for the cooperation between this method, setFixedDataCoordinateSpaceRelation(),
391 // and handleFixedDataCoordinateSpaceRelation().
392 if (!d->fixedDataCoordinateSpaceRelationPinnedSize.isValid()) {
393 d->fixedDataCoordinateSpaceRelationPinnedSize = geometry.size();
394 d->fixedDataCoordinateSpaceRelationPinnedZoom = ZoomParameters(zoomFactorX(), zoomFactorY(), zoomCenter());
395 return;
396 }
397
398 // if the plane size was changed, change zoom factors to keep the diagram size constant
399 if (d->fixedDataCoordinateSpaceRelationPinnedSize != geometry.size()) {
400 const qreal widthScaling = d->fixedDataCoordinateSpaceRelationPinnedSize.width() / geometry.width();
401 const qreal heightScaling = d->fixedDataCoordinateSpaceRelationPinnedSize.height() / geometry.height();
402
403 const qreal newZoomX = d->fixedDataCoordinateSpaceRelationPinnedZoom.xFactor * widthScaling;
404 const qreal newZoomY = d->fixedDataCoordinateSpaceRelationPinnedZoom.yFactor * heightScaling;
405
406 const QPointF newCenter = QPointF(d->fixedDataCoordinateSpaceRelationPinnedZoom.xCenter / widthScaling,
407 d->fixedDataCoordinateSpaceRelationPinnedZoom.yCenter / heightScaling);
408 // Use these internal methods to avoid sending the propertiesChanged signal more than once
409 bool changed = false;
411 changed = true;
413 changed = true;
415 changed = true;
416 if (changed)
418 }
419}
420
422{
423 // Note: We do not test if the point lays inside of the data area,
424 // but we just apply the transformation calculations to the point.
425 // This allows for basic calculations done by the user, see e.g.
426 // the file examples/Lines/BubbleChart/mainwindow.cpp
427 return d->coordinateTransformation.translate(diagramPoint);
428}
429
431{
432 return d->coordinateTransformation.translateBack(screenPoint);
433}
434
436{
437 if (d->isometricScaling != isOn) {
438 d->isometricScaling = isOn;
441 }
442}
443
445{
446 return d->isometricScaling;
447}
448
450{
451 if (d->coordinateTransformation.zoom.xFactor == factor) {
452 return false;
453 }
454 d->coordinateTransformation.zoom.xFactor = factor;
455 if (d->autoAdjustGridToZoom) {
456 d->grid->setNeedRecalculate();
457 }
458 return true;
459}
460
462{
463 if (d->coordinateTransformation.zoom.yFactor == factor) {
464 return false;
465 }
466 d->coordinateTransformation.zoom.yFactor = factor;
467 if (d->autoAdjustGridToZoom) {
468 d->grid->setNeedRecalculate();
469 }
470 return true;
471}
472
474{
475 if (d->coordinateTransformation.zoom.center() == point) {
476 return false;
477 }
478 d->coordinateTransformation.zoom.setCenter(point);
479 if (d->autoAdjustGridToZoom) {
480 d->grid->setNeedRecalculate();
481 }
482 return true;
483}
484
485void CartesianCoordinatePlane::setZoomFactors(qreal factorX, qreal factorY)
486{
488 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
490 }
491}
492
494{
496 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
498 }
499}
500
502{
504 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
506 }
507}
508
510{
511 if (doneSetZoomCenter(point)) {
512 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
514 }
515}
516
518{
519 return d->coordinateTransformation.zoom.center();
520}
521
523{
524 return d->coordinateTransformation.zoom.xFactor;
525}
526
528{
529 return d->coordinateTransformation.zoom.yFactor;
530}
531
533{
534 return d->coordinateTransformation.axesCalcModeY;
535}
536
538{
539 return d->coordinateTransformation.axesCalcModeX;
540}
541
543{
544 if (d->coordinateTransformation.axesCalcModeY != mode || d->coordinateTransformation.axesCalcModeX != mode) {
545 d->coordinateTransformation.axesCalcModeY = mode;
546 d->coordinateTransformation.axesCalcModeX = mode;
549 const auto constDiagrams = diagrams();
550 for (AbstractDiagram *diag : constDiagrams) {
552 }
553 }
554}
555
557{
558 if (d->coordinateTransformation.axesCalcModeY != mode) {
559 d->coordinateTransformation.axesCalcModeY = mode;
563 }
564}
565
567{
568 if (d->coordinateTransformation.axesCalcModeX != mode) {
569 d->coordinateTransformation.axesCalcModeX = mode;
572 }
573}
574
575namespace {
576inline bool fuzzyCompare(qreal a, qreal b)
577{
578 if (ISNAN(a) && ISNAN(b))
579 return true;
580 if (qFuzzyIsNull(a) && qFuzzyIsNull(b))
581 return true;
582 return qFuzzyCompare(a, b);
583}
584}
585
587{
588 const bool bAutoAdjustHorizontalRange = d->autoAdjustHorizontalRangeToData < 100;
589 if (!fuzzyCompare(d->horizontalMin, range.first) || !fuzzyCompare(d->horizontalMax, range.second) || bAutoAdjustHorizontalRange) {
590 d->autoAdjustHorizontalRangeToData = 100;
591 d->horizontalMin = range.first;
592 d->horizontalMax = range.second;
596 }
597}
598
600{
601 const bool bAutoAdjustVerticalRange = d->autoAdjustVerticalRangeToData < 100;
602 if (!fuzzyCompare(d->verticalMin, range.first) || !fuzzyCompare(d->verticalMax, range.second) || bAutoAdjustVerticalRange) {
603 d->autoAdjustVerticalRangeToData = 100;
604 d->verticalMin = range.first;
605 d->verticalMax = range.second;
609 }
610}
611
613{
614 return QPair<qreal, qreal>(d->horizontalMin, d->horizontalMax);
615}
616
618{
619 return QPair<qreal, qreal>(d->verticalMin, d->verticalMax);
620}
621
623{
625 d->horizontalMin = dataBoundingRect.left();
626 d->horizontalMax = dataBoundingRect.right();
627 d->verticalMin = dataBoundingRect.top();
628 d->verticalMax = dataBoundingRect.bottom();
631}
632
641
650
652{
653 if (d->autoAdjustHorizontalRangeToData != percentEmpty) {
654 d->autoAdjustHorizontalRangeToData = percentEmpty;
655 d->horizontalMin = 0.0;
656 d->horizontalMax = 0.0;
659 }
660}
661
663{
664 if (d->autoAdjustVerticalRangeToData != percentEmpty) {
665 d->autoAdjustVerticalRangeToData = percentEmpty;
666 d->verticalMin = 0.0;
667 d->verticalMax = 0.0;
670 }
671}
672
674{
675 return d->autoAdjustHorizontalRangeToData;
676}
677
679{
680 return d->autoAdjustVerticalRangeToData;
681}
682
684 Qt::Orientation orientation,
685 const GridAttributes &a)
686{
687 if (orientation == Qt::Horizontal)
688 d->gridAttributesHorizontal = a;
689 else
690 d->gridAttributesVertical = a;
691 setHasOwnGridAttributes(orientation, true);
692 update();
694}
695
697{
698 setHasOwnGridAttributes(orientation, false);
699 update();
700}
701
703{
704 if (hasOwnGridAttributes(orientation)) {
705 if (orientation == Qt::Horizontal)
706 return d->gridAttributesHorizontal;
707 else
708 return d->gridAttributesVertical;
709 } else {
710 return globalGridAttributes();
711 }
712}
713
714void CartesianCoordinatePlane::setHasOwnGridAttributes(Qt::Orientation orientation, bool on)
715{
716 if (orientation == Qt::Horizontal)
717 d->hasOwnGridAttributesHorizontal = on;
718 else
719 d->hasOwnGridAttributesVertical = on;
721}
722
724{
725 return orientation == Qt::Horizontal ? d->hasOwnGridAttributesHorizontal
726 : d->hasOwnGridAttributesVertical;
727}
728
730{
731 if (d->autoAdjustGridToZoom != autoAdjust) {
732 d->autoAdjustGridToZoom = autoAdjust;
733 d->grid->setNeedRecalculate();
735 }
736}
737
738#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined(Q_COMPILER_MANGLES_RETURN_TYPE)
739const
740#endif
741 bool
743{
744 return d->autoAdjustGridToZoom;
745}
746
748{
749 CartesianCoordinatePlane *plane = this;
750 auto *diag = dynamic_cast<AbstractCartesianDiagram *>(plane->diagram());
751 const CartesianAxis *sharedAxis = nullptr;
752 if (diag != nullptr) {
753 const CartesianAxisList axes = diag->axes();
754 for (const CartesianAxis *a : axes) {
755 auto *p = const_cast<CartesianCoordinatePlane *>(
756 dynamic_cast<const CartesianCoordinatePlane *>(a->coordinatePlane()));
757 if (p != nullptr && p != this) {
758 plane = p;
759 sharedAxis = a;
760 }
761 }
762 }
763
764 if (plane == this || painter == nullptr)
765 return plane;
766
767 const QPointF zero = QPointF(0, 0);
768 const QPointF tenX = QPointF(10, 0);
769 const QPointF tenY = QPointF(0, 10);
770
771 if (sharedAxis->isOrdinate()) {
772 painter->translate(translate(zero).x(), 0.0);
773 const qreal factor = (translate(tenX) - translate(zero)).x() / (plane->translate(tenX) - plane->translate(zero)).x();
774 painter->scale(factor, 1.0);
775 painter->translate(-plane->translate(zero).x(), 0.0);
776 }
777 if (sharedAxis->isAbscissa()) {
778 painter->translate(0.0, translate(zero).y());
779 const qreal factor = (translate(tenY) - translate(zero)).y() / (plane->translate(tenY) - plane->translate(zero)).y();
780 painter->scale(1.0, factor);
781 painter->translate(0.0, -plane->translate(zero).y());
782 }
783
784 return plane;
785}
786
788{
789 if (d->reverseHorizontalPlane == reverse)
790 return;
791
792 d->reverseHorizontalPlane = reverse;
795}
796
798{
799 return d->reverseHorizontalPlane;
800}
801
803{
804 if (d->reverseVerticalPlane == reverse)
805 return;
806
807 d->reverseVerticalPlane = reverse;
810}
811
813{
814 return d->reverseVerticalPlane;
815}
816
818{
819 QRectF result;
820
821 const QRectF drawArea = drawingArea();
822
823 result.setTopLeft(translateBack(drawArea.topLeft()));
824 result.setBottomRight(translateBack(drawArea.bottomRight()));
825
826 return result;
827}
828
830{
831 if (rectangle == geometry()) {
832 return;
833 }
834
835 d->geometry = rectangle;
836 if (d->isometricScaling) {
837 const int hfw = heightForWidth(rectangle.width());
838 // same scaling for x and y means a fixed aspect ratio, which is enforced here
839 // always shrink the too large dimension
840 if (hfw < rectangle.height()) {
841 d->geometry.setHeight(hfw);
842 } else {
843 d->geometry.setWidth(qRound(qreal(rectangle.width()) * qreal(rectangle.height()) / qreal(hfw)));
844 }
845 }
846
848
849 const auto constDiagrams = diagrams();
850 for (AbstractDiagram *diagram : constDiagrams) {
851 diagram->resize(d->geometry.size());
852 }
853}
854
856{
857 // not completely sure why this is required for isometric scaling...
858 return d->isometricScaling ? Qt::Horizontal : (Qt::Horizontal | Qt::Vertical);
859}
860
862{
863 return d->isometricScaling;
864}
865
867{
868 // ### using anything for dataRect that depends on geometry will close a feedback loop which
869 // prevents the geometry from stabilizing. specifically, visibleDataRange() depends on
870 // drawingArea(), and no good will come out of using it here.
872 return qRound(qreal(w) * qAbs(qreal(dataRect.height()) / qreal(dataRect.width())));
873}
874
876{
878 if (d->isometricScaling) {
879 // not sure why the next line doesn't cause an infinite loop, but it improves initial size allocation
880 sh = d->geometry.size();
881 sh.setHeight(heightForWidth(sh.width()));
882 }
883 return sh;
884}
QRect areaGeometry() const override
Base class for diagrams based on a cartesian coordianate system.
Base class common for all coordinate planes, CartesianCoordinatePlane, PolarCoordinatePlane,...
virtual void addDiagram(AbstractDiagram *diagram)
AbstractDiagram defines the interface for diagram classes.
void layoutChanged(AbstractDiagram *)
const QPair< QPointF, QPointF > dataBoundaries() const
Return the bottom left and top right data point, that the diagram will display (unless the grid adjus...
virtual void resize(const QSizeF &area)=0
DataDimensionsList getDataDimensionsList() const override
bool hasOwnGridAttributes(Qt::Orientation orientation) const
void setVerticalRange(const QPair< qreal, qreal > &range)
Set the boundaries of the visible value space displayed in vertical direction.
unsigned int autoAdjustVerticalRangeToData() const
Returns the maximal allowed percent of the vertical space covered by the coordinate plane that may be...
unsigned int autoAdjustHorizontalRangeToData() const
Returns the maximal allowed percent of the horizontal space covered by the coordinate plane that may ...
void setZoomFactors(qreal factorX, qreal factorY) override
void adjustRangesToData()
Adjust both, horizontal and vertical range settings to the ranges covered by the model's data values.
const QPointF translate(const QPointF &diagramPoint) const override
AbstractCoordinatePlane * sharedAxisMasterPlane(QPainter *p=nullptr) override
Qt::Orientations expandingDirections() const override
void setAutoAdjustVerticalRangeToData(unsigned int percentEmpty=67)
Automatically adjust vertical range settings to the ranges covered by the model's values,...
const GridAttributes gridAttributes(Qt::Orientation orientation) const
void addDiagram(AbstractDiagram *diagram) override
const QPointF translateBack(const QPointF &screenPoint) const
void setAutoAdjustHorizontalRangeToData(unsigned int percentEmpty=67)
Automatically adjust horizontal range settings to the ranges covered by the model's values,...
void setZoomCenter(const QPointF &center) override
QRectF adjustedToMaxEmptyInnerPercentage(const QRectF &r, unsigned int percentX, unsigned int percentY) const
void setHorizontalRange(const QPair< qreal, qreal > &range)
Set the boundaries of the visible value space displayed in horizontal direction.
void resetGridAttributes(Qt::Orientation orientation)
void setGridAttributes(Qt::Orientation orientation, const GridAttributes &)
void handleFixedDataCoordinateSpaceRelation(const QRectF &geometry)
A chart with one or more diagrams.
Helper class for one dimension of data, e.g. for the rows in a data model, or for the labels of an ax...
A set of attributes controlling the appearance of grids.
Stores information about painting diagrams.
void setPainter(QPainter *painter)
bool isEmpty() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
T qobject_cast(QObject *object)
void scale(qreal sx, qreal sy)
void setClipRegion(const QRegion &region, Qt::ClipOperation operation)
void translate(const QPointF &offset)
qreal x() const const
qreal y() const const
QRect adjusted(int dx1, int dy1, int dx2, int dy2) const const
int height() const const
bool isValid() const const
QSize size() const const
int width() const const
QRectF adjusted(qreal dx1, qreal dy1, qreal dx2, qreal dy2) const const
qreal bottom() const const
QRectF intersected(const QRectF &rectangle) const const
qreal left() const const
QRectF normalized() const const
qreal right() const const
void setBottomLeft(const QPointF &position)
void setBottomRight(const QPointF &position)
void setLeft(qreal x)
void setTopLeft(const QPointF &position)
qreal top() const const
Orientation

© 2001 Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
https://www.kdab.com/development-resources/qt-tools/kd-chart/
Generated on Fri Apr 26 2024 00:04:56 for KD Chart API Documentation by doxygen 1.9.8