KD Chart API Documentation 3.0
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!");
64 connect(diagram, SIGNAL(layoutChanged(AbstractDiagram *)),
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;
132 // qDebug() << "CartesianCoordinatePlane::getRawDataBoundingRectFromDiagrams()\ngets diagram->dataBoundaries: " << dataBoundariesPair.first << dataBoundariesPair.second;
133 if (bStarting || dataBoundariesPair.first.x() < minX)
134 minX = dataBoundariesPair.first.x();
135 if (bStarting || dataBoundariesPair.first.y() < minY)
136 minY = dataBoundariesPair.first.y();
137 if (bStarting || dataBoundariesPair.second.x() > maxX)
138 maxX = dataBoundariesPair.second.x();
139 if (bStarting || dataBoundariesPair.second.y() > maxY)
140 maxY = dataBoundariesPair.second.y();
141 bStarting = false;
142 }
143 // qDebug() << "CartesianCoordinatePlane::getRawDataBoundingRectFromDiagrams()\nreturns data boundaries: " << QRectF( QPointF(minX, minY), QSizeF(maxX - minX, maxY - minY) );
146 dataBoundingRect.setTopRight(QPointF(maxX, maxY));
147 return dataBoundingRect;
148}
149
151 const QRectF &r, unsigned int percentX, unsigned int percentY) const
152{
153 QRectF ret = r;
154 if ((axesCalcModeX() != Logarithmic || r.left() < 0.0) && percentX > 0 && percentX != 100) {
155 const bool isPositive = r.left() >= 0;
156 if ((r.right() >= 0) == isPositive) {
157 qreal upperBound = qMax(r.left(), r.right());
158 qreal lowerBound = qMin(r.left(), r.right());
159 qreal innerBound = isPositive ? lowerBound : upperBound;
160 qreal outerBound = isPositive ? upperBound : lowerBound;
161 if (innerBound / outerBound * 100 <= percentX && d->xAxisStartAtZero) {
162 if (isPositive) {
163 ret.setLeft(0.0);
164 } else {
165 ret.setRight(0.0);
166 }
167 }
168 }
169 }
170 // ### this doesn't seem to take into account that Qt's y coordinate is inverted
171 if ((axesCalcModeY() != Logarithmic || r.bottom() < 0.0) && percentY > 0 && percentY != 100) {
172 const bool isPositive = r.bottom() >= 0;
173 if ((r.top() >= 0) == isPositive) {
174 qreal upperBound = qMax(r.top(), r.bottom());
175 qreal lowerBound = qMin(r.top(), r.bottom());
176 const qreal innerBound = isPositive ? lowerBound : upperBound;
177 const qreal outerBound = isPositive ? upperBound : lowerBound;
178 if (innerBound / outerBound * 100 <= percentY) {
179 if (isPositive) {
180 ret.setBottom(0.0);
181 } else {
182 ret.setTop(0.0);
183 }
184 }
185 }
186 }
187 return ret;
188}
189
191{
192 // are manually set ranges to be applied?
193 const bool bAutoAdjustHorizontalRange = d->autoAdjustHorizontalRangeToData < 100;
194 const bool bAutoAdjustVerticalRange = d->autoAdjustVerticalRangeToData < 100;
195
196 const bool bHardHorizontalRange = (!bAutoAdjustHorizontalRange) && (d->horizontalMin != d->horizontalMax || (ISNAN(d->horizontalMin) != ISNAN(d->horizontalMax)));
197 const bool bHardVerticalRange = (!bAutoAdjustVerticalRange) && (d->verticalMin != d->verticalMax || (ISNAN(d->verticalMin) != ISNAN(d->verticalMax)));
199
200 // if custom boundaries are set on the plane, use them
202 dataBoundingRect.setLeft(d->horizontalMin);
203 dataBoundingRect.setRight(d->horizontalMax);
204 dataBoundingRect.setBottom(d->verticalMin);
205 dataBoundingRect.setTop(d->verticalMax);
206 } else {
207 // determine unit of the rectangles of all involved diagrams:
210 if (!ISNAN(d->horizontalMin))
211 dataBoundingRect.setLeft(d->horizontalMin);
212 if (!ISNAN(d->horizontalMax))
213 dataBoundingRect.setRight(d->horizontalMax);
214 }
215 if (bHardVerticalRange) {
216 if (!ISNAN(d->verticalMin))
217 dataBoundingRect.setBottom(d->verticalMin);
218 if (!ISNAN(d->verticalMax))
219 dataBoundingRect.setTop(d->verticalMax);
220 }
221 }
222 // recalculate the bounds, if automatic adjusting of ranges is desired AND
223 // both bounds are at the same side of the zero line
225 dataBoundingRect, d->autoAdjustHorizontalRangeToData, d->autoAdjustVerticalRangeToData);
227 const_cast<CartesianCoordinatePlane *>(this)->d->horizontalMin = dataBoundingRect.left();
228 const_cast<CartesianCoordinatePlane *>(this)->d->horizontalMax = dataBoundingRect.right();
229 }
231 const_cast<CartesianCoordinatePlane *>(this)->d->verticalMin = dataBoundingRect.bottom();
232 const_cast<CartesianCoordinatePlane *>(this)->d->verticalMax = dataBoundingRect.top();
233 }
234 // qDebug() << Q_FUNC_INFO << dataBoundingRect;
235 return dataBoundingRect;
236}
237
239{
241 if (dgr && dgr->referenceDiagram()) {
242 dgr = dgr->referenceDiagram();
243 }
244 const auto *barDiagram = qobject_cast<const BarDiagram *>(dgr);
246
247 // note:
248 // It does make sense to retrieve the orientation from the first diagram. This is because
249 // a coordinate plane can either be for horizontal *or* for vertical diagrams. Both at the
250 // same time won't work, and thus the orientation for all diagrams is the same as for the first one.
251 const Qt::Orientation diagramOrientation = barDiagram != nullptr ? barDiagram->orientation() : Qt::Vertical;
253
255 if (dgr) {
257 // We do not access d->gridAttributesHorizontal/Vertical here, but we use the getter function,
258 // to get the global attrs, if no special ones have been set for the given orientation.
261 // append the first dimension: for Abscissa axes
262 l.append(
264 r.left(), r.right(),
265 diagramIsVertical ? (!stockDiagram && dgr->datasetDimension() > 1) : true,
267 gaH.gridGranularitySequence(),
268 gaH.gridStepWidth(),
269 gaH.gridSubStepWidth()));
270 // append the second dimension: for Ordinate axes
271 l.append(
273 r.bottom(), r.top(),
274 diagramIsVertical ? true : (dgr->datasetDimension() > 1),
276 gaV.gridGranularitySequence(),
277 gaV.gridStepWidth(),
278 gaV.gridSubStepWidth()));
279 } else {
280 l.append(DataDimension()); // This gets us the default 1..0 / 1..0 grid
281 l.append(DataDimension()); // shown, if there is no diagram on this plane.
282 }
283 return l;
284}
285
287{
288 // the rectangle the diagrams cover in the *plane*:
289 // We reserve 1px on each side for antialiased drawing, and respect the way QPainter calculates
290 // the width of a painted rect (the size is the rectangle size plus the pen width). The latter
291 // accounts for another pixel that we subtract from height and width.
292 // This way, most clipping for regular pens should be avoided. When pens with a width larger
293 // than 1 are used, this may not be sufficient.
294 return QRectF(areaGeometry()).adjusted(1.0, 1.0, -2.0, -2.0);
295}
296
298{
299 if (d->dimensions.isEmpty())
300 return QRectF();
301
302 const DataDimension dimX = d->dimensions.first();
303 const DataDimension dimY = d->dimensions.last();
304 const QPointF pt(qMin(dimX.start, dimX.end), qMax(dimY.start, dimY.end));
305 const QSizeF siz(qAbs(dimX.distance()), -qAbs(dimY.distance()));
307
308 // determine logical top left, taking the "reverse" options into account
309 const QPointF topLeft(d->reverseHorizontalPlane ? dataBoundingRect.right() : dataBoundingRect.left(),
310 d->reverseVerticalPlane ? dataBoundingRect.bottom() : dataBoundingRect.top());
311
312 const qreal width = dataBoundingRect.width() * (d->reverseHorizontalPlane ? -1.0 : 1.0);
313 const qreal height = dataBoundingRect.height() * (d->reverseVerticalPlane ? -1.0 : 1.0);
314
315 return QRectF(topLeft, QSizeF(width, height));
316}
317
319{
320 const QRectF logArea(logicalArea());
321 QPointF physicalTopLeft = d->coordinateTransformation.translate(logArea.topLeft());
322 QPointF physicalBottomRight = d->coordinateTransformation.translate(logArea.bottomRight());
323
325}
326
331
333{
334 d->dimensions = gridDimensionsList();
335 Q_ASSERT_X(d->dimensions.count() == 2, "CartesianCoordinatePlane::layoutDiagrams",
336 "Error: gridDimensionsList() did not return exactly two dimensions.");
337
338 // physical area of the plane
340 // .. in contrast to the logical area
341 const QRectF logArea(logicalArea());
342
343 // TODO: isometric scaling for zooming?
344
345 // the plane area might have changed, so the zoom values might also be changed
347
348 d->coordinateTransformation.updateTransform(logArea, physicalArea);
349
350 update();
351}
352
354{
355 d->fixedDataCoordinateSpaceRelation = fixed;
356 d->fixedDataCoordinateSpaceRelationPinnedSize = QSize();
358}
359
361{
362 return d->fixedDataCoordinateSpaceRelation;
363}
364
366{
367 if (d->xAxisStartAtZero == fixedStart)
368 return;
369
370 d->xAxisStartAtZero = fixedStart;
371}
372
374{
375 return d->xAxisStartAtZero;
376}
377
379{
380 if (!d->fixedDataCoordinateSpaceRelation) {
381 return;
382 }
383 // is the new geometry ok?
384 if (!geometry.isValid()) {
385 return;
386 }
387
388 // note that the pinned size can be invalid even after setting it, if geometry wasn't valid.
389 // this is relevant for the cooperation between this method, setFixedDataCoordinateSpaceRelation(),
390 // and handleFixedDataCoordinateSpaceRelation().
391 if (!d->fixedDataCoordinateSpaceRelationPinnedSize.isValid()) {
392 d->fixedDataCoordinateSpaceRelationPinnedSize = geometry.size();
393 d->fixedDataCoordinateSpaceRelationPinnedZoom = ZoomParameters(zoomFactorX(), zoomFactorY(), zoomCenter());
394 return;
395 }
396
397 // if the plane size was changed, change zoom factors to keep the diagram size constant
398 if (d->fixedDataCoordinateSpaceRelationPinnedSize != geometry.size()) {
399 const qreal widthScaling = d->fixedDataCoordinateSpaceRelationPinnedSize.width() / geometry.width();
400 const qreal heightScaling = d->fixedDataCoordinateSpaceRelationPinnedSize.height() / geometry.height();
401
402 const qreal newZoomX = d->fixedDataCoordinateSpaceRelationPinnedZoom.xFactor * widthScaling;
403 const qreal newZoomY = d->fixedDataCoordinateSpaceRelationPinnedZoom.yFactor * heightScaling;
404
405 const QPointF newCenter = QPointF(d->fixedDataCoordinateSpaceRelationPinnedZoom.xCenter / widthScaling,
406 d->fixedDataCoordinateSpaceRelationPinnedZoom.yCenter / heightScaling);
407 // Use these internal methods to avoid sending the propertiesChanged signal more than once
408 bool changed = false;
410 changed = true;
412 changed = true;
414 changed = true;
415 if (changed)
417 }
418}
419
421{
422 // Note: We do not test if the point lays inside of the data area,
423 // but we just apply the transformation calculations to the point.
424 // This allows for basic calculations done by the user, see e.g.
425 // the file examples/Lines/BubbleChart/mainwindow.cpp
426 return d->coordinateTransformation.translate(diagramPoint);
427}
428
430{
431 return d->coordinateTransformation.translateBack(screenPoint);
432}
433
435{
436 if (d->isometricScaling != isOn) {
437 d->isometricScaling = isOn;
440 }
441}
442
444{
445 return d->isometricScaling;
446}
447
449{
450 if (d->coordinateTransformation.zoom.xFactor == factor) {
451 return false;
452 }
453 d->coordinateTransformation.zoom.xFactor = factor;
454 if (d->autoAdjustGridToZoom) {
455 d->grid->setNeedRecalculate();
456 }
457 return true;
458}
459
461{
462 if (d->coordinateTransformation.zoom.yFactor == factor) {
463 return false;
464 }
465 d->coordinateTransformation.zoom.yFactor = factor;
466 if (d->autoAdjustGridToZoom) {
467 d->grid->setNeedRecalculate();
468 }
469 return true;
470}
471
473{
474 if (d->coordinateTransformation.zoom.center() == point) {
475 return false;
476 }
477 d->coordinateTransformation.zoom.setCenter(point);
478 if (d->autoAdjustGridToZoom) {
479 d->grid->setNeedRecalculate();
480 }
481 return true;
482}
483
484void CartesianCoordinatePlane::setZoomFactors(qreal factorX, qreal factorY)
485{
487 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
489 }
490}
491
493{
495 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
497 }
498}
499
501{
503 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
505 }
506}
507
509{
510 if (doneSetZoomCenter(point)) {
511 d->coordinateTransformation.updateTransform(logicalArea(), drawingArea());
513 }
514}
515
517{
518 return d->coordinateTransformation.zoom.center();
519}
520
522{
523 return d->coordinateTransformation.zoom.xFactor;
524}
525
527{
528 return d->coordinateTransformation.zoom.yFactor;
529}
530
532{
533 return d->coordinateTransformation.axesCalcModeY;
534}
535
537{
538 return d->coordinateTransformation.axesCalcModeX;
539}
540
542{
543 if (d->coordinateTransformation.axesCalcModeY != mode || d->coordinateTransformation.axesCalcModeX != mode) {
544 d->coordinateTransformation.axesCalcModeY = mode;
545 d->coordinateTransformation.axesCalcModeX = mode;
550 }
551}
552
554{
555 if (d->coordinateTransformation.axesCalcModeY != mode) {
556 d->coordinateTransformation.axesCalcModeY = mode;
560 }
561}
562
564{
565 if (d->coordinateTransformation.axesCalcModeX != mode) {
566 d->coordinateTransformation.axesCalcModeX = mode;
569 }
570}
571
572namespace {
573inline bool fuzzyCompare(qreal a, qreal b)
574{
575 if (ISNAN(a) && ISNAN(b))
576 return true;
577 if (qFuzzyIsNull(a) && qFuzzyIsNull(b))
578 return true;
579 return qFuzzyCompare(a, b);
580}
581}
582
584{
585 const bool bAutoAdjustHorizontalRange = d->autoAdjustHorizontalRangeToData < 100;
586 if (!fuzzyCompare(d->horizontalMin, range.first) || !fuzzyCompare(d->horizontalMax, range.second) || bAutoAdjustHorizontalRange) {
587 d->autoAdjustHorizontalRangeToData = 100;
588 d->horizontalMin = range.first;
589 d->horizontalMax = range.second;
593 }
594}
595
597{
598 const bool bAutoAdjustVerticalRange = d->autoAdjustVerticalRangeToData < 100;
599 if (!fuzzyCompare(d->verticalMin, range.first) || !fuzzyCompare(d->verticalMax, range.second) || bAutoAdjustVerticalRange) {
600 d->autoAdjustVerticalRangeToData = 100;
601 d->verticalMin = range.first;
602 d->verticalMax = range.second;
606 }
607}
608
610{
611 return QPair<qreal, qreal>(d->horizontalMin, d->horizontalMax);
612}
613
615{
616 return QPair<qreal, qreal>(d->verticalMin, d->verticalMax);
617}
618
620{
622 d->horizontalMin = dataBoundingRect.left();
623 d->horizontalMax = dataBoundingRect.right();
624 d->verticalMin = dataBoundingRect.top();
625 d->verticalMax = dataBoundingRect.bottom();
628}
629
638
647
649{
650 if (d->autoAdjustHorizontalRangeToData != percentEmpty) {
651 d->autoAdjustHorizontalRangeToData = percentEmpty;
652 d->horizontalMin = 0.0;
653 d->horizontalMax = 0.0;
656 }
657}
658
660{
661 if (d->autoAdjustVerticalRangeToData != percentEmpty) {
662 d->autoAdjustVerticalRangeToData = percentEmpty;
663 d->verticalMin = 0.0;
664 d->verticalMax = 0.0;
667 }
668}
669
671{
672 return d->autoAdjustHorizontalRangeToData;
673}
674
676{
677 return d->autoAdjustVerticalRangeToData;
678}
679
681 Qt::Orientation orientation,
682 const GridAttributes &a)
683{
684 if (orientation == Qt::Horizontal)
685 d->gridAttributesHorizontal = a;
686 else
687 d->gridAttributesVertical = a;
688 setHasOwnGridAttributes(orientation, true);
689 update();
691}
692
694{
695 setHasOwnGridAttributes(orientation, false);
696 update();
697}
698
700{
701 if (hasOwnGridAttributes(orientation)) {
702 if (orientation == Qt::Horizontal)
703 return d->gridAttributesHorizontal;
704 else
705 return d->gridAttributesVertical;
706 } else {
707 return globalGridAttributes();
708 }
709}
710
711void CartesianCoordinatePlane::setHasOwnGridAttributes(Qt::Orientation orientation, bool on)
712{
713 if (orientation == Qt::Horizontal)
714 d->hasOwnGridAttributesHorizontal = on;
715 else
716 d->hasOwnGridAttributesVertical = on;
718}
719
721{
722 return orientation == Qt::Horizontal ? d->hasOwnGridAttributesHorizontal
723 : d->hasOwnGridAttributesVertical;
724}
725
727{
728 if (d->autoAdjustGridToZoom != autoAdjust) {
729 d->autoAdjustGridToZoom = autoAdjust;
730 d->grid->setNeedRecalculate();
732 }
733}
734
735#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) && defined(Q_COMPILER_MANGLES_RETURN_TYPE)
736const
737#endif
738 bool
740{
741 return d->autoAdjustGridToZoom;
742}
743
745{
746 CartesianCoordinatePlane *plane = this;
747 auto *diag = dynamic_cast<AbstractCartesianDiagram *>(plane->diagram());
748 const CartesianAxis *sharedAxis = nullptr;
749 if (diag != nullptr) {
750 const CartesianAxisList axes = diag->axes();
751 Q_FOREACH (const CartesianAxis *a, axes) {
752 auto *p = const_cast<CartesianCoordinatePlane *>(
753 dynamic_cast<const CartesianCoordinatePlane *>(a->coordinatePlane()));
754 if (p != nullptr && p != this) {
755 plane = p;
756 sharedAxis = a;
757 }
758 }
759 }
760
761 if (plane == this || painter == nullptr)
762 return plane;
763
764 const QPointF zero = QPointF(0, 0);
765 const QPointF tenX = QPointF(10, 0);
766 const QPointF tenY = QPointF(0, 10);
767
768 if (sharedAxis->isOrdinate()) {
769 painter->translate(translate(zero).x(), 0.0);
770 const qreal factor = (translate(tenX) - translate(zero)).x() / (plane->translate(tenX) - plane->translate(zero)).x();
771 painter->scale(factor, 1.0);
772 painter->translate(-plane->translate(zero).x(), 0.0);
773 }
774 if (sharedAxis->isAbscissa()) {
775 painter->translate(0.0, translate(zero).y());
776 const qreal factor = (translate(tenY) - translate(zero)).y() / (plane->translate(tenY) - plane->translate(zero)).y();
777 painter->scale(1.0, factor);
778 painter->translate(0.0, -plane->translate(zero).y());
779 }
780
781 return plane;
782}
783
785{
786 if (d->reverseHorizontalPlane == reverse)
787 return;
788
789 d->reverseHorizontalPlane = reverse;
792}
793
795{
796 return d->reverseHorizontalPlane;
797}
798
800{
801 if (d->reverseVerticalPlane == reverse)
802 return;
803
804 d->reverseVerticalPlane = reverse;
807}
808
810{
811 return d->reverseVerticalPlane;
812}
813
815{
816 QRectF result;
817
818 const QRectF drawArea = drawingArea();
819
820 result.setTopLeft(translateBack(drawArea.topLeft()));
821 result.setBottomRight(translateBack(drawArea.bottomRight()));
822
823 return result;
824}
825
827{
828 if (rectangle == geometry()) {
829 return;
830 }
831
832 d->geometry = rectangle;
833 if (d->isometricScaling) {
834 const int hfw = heightForWidth(rectangle.width());
835 // same scaling for x and y means a fixed aspect ratio, which is enforced here
836 // always shrink the too large dimension
837 if (hfw < rectangle.height()) {
838 d->geometry.setHeight(hfw);
839 } else {
840 d->geometry.setWidth(qRound(qreal(rectangle.width()) * qreal(rectangle.height()) / qreal(hfw)));
841 }
842 }
843
845
847 diagram->resize(d->geometry.size());
848 }
849}
850
852{
853 // not completely sure why this is required for isometric scaling...
854 return d->isometricScaling ? Qt::Horizontal : (Qt::Horizontal | Qt::Vertical);
855}
856
858{
859 return d->isometricScaling;
860}
861
863{
864 // ### using anything for dataRect that depends on geometry will close a feedback loop which
865 // prevents the geometry from stabilizing. specifically, visibleDataRange() depends on
866 // drawingArea(), and no good will come out of using it here.
868 return qRound(qreal(w) * qAbs(qreal(dataRect.height()) / qreal(dataRect.width())));
869}
870
872{
874 if (d->isometricScaling) {
875 // not sure why the next line doesn't cause an infinite loop, but it improves initial size allocation
876 sh = d->geometry.size();
877 sh.setHeight(heightForWidth(sh.width()));
878 }
879 return sh;
880}
QRect areaGeometry() const override
const AbstractCoordinatePlane * coordinatePlane() const
Convenience function, returns the coordinate plane, in which this axis is used.
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.
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
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 Feb 23 2024 00:02:57 for KD Chart API Documentation by doxygen 1.9.8