feat: graphs now properly sized + port static graphs to c++

This commit is contained in:
2026-11-08 01:28:27 +01:00
parent a7767d2a80
commit d69a6bcafd
17 changed files with 1592 additions and 1257 deletions
+290
View File
@@ -0,0 +1,290 @@
#pragma once
#include <QCanvasPainterItem>
#include <QColor>
#include <qobject.h>
#include <qqmlintegration.h>
#include <qtmetamacros.h>
#include <qvariant.h>
#include <QString>
#include <limits>
namespace ZShell::components {
class LineGraphRenderer;
// A line graph with an optional grid, axis labels, y auto-scaling, a moving
// average, smoothed Catmull-Rom curve, an area fill and a marker. Static: it draws
// whatever `values` holds at the given x steps, unlike Sparkline which slides a
// rolling buffer. Both share curve smoothing and device-pixel alignment through
// internal::linegeometry.
class LineGraph : public QCanvasPainterItem {
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(
QVariantList values READ values WRITE setValues NOTIFY valuesChanged
FINAL)
Q_PROPERTY(int xSteps READ xSteps WRITE setXSteps NOTIFY xStepsChanged FINAL)
Q_PROPERTY(qreal yMin READ yMin WRITE setYMin NOTIFY yMinChanged FINAL)
Q_PROPERTY(qreal yMax READ yMax WRITE setYMax NOTIFY yMaxChanged FINAL)
Q_PROPERTY(
qreal yPaddingTop READ yPaddingTop WRITE setYPaddingTop NOTIFY
yPaddingTopChanged FINAL)
Q_PROPERTY(
qreal yPaddingBottom READ yPaddingBottom WRITE setYPaddingBottom NOTIFY
yPaddingBottomChanged FINAL)
Q_PROPERTY(
int verticalLineStep READ verticalLineStep WRITE setVerticalLineStep
NOTIFY verticalLineStepChanged FINAL)
Q_PROPERTY(
int horizontalLineStep READ horizontalLineStep WRITE
setHorizontalLineStep NOTIFY horizontalLineStepChanged FINAL)
Q_PROPERTY(
bool firstXLine READ firstXLine WRITE setFirstXLine NOTIFY
firstXLineChanged FINAL)
Q_PROPERTY(
bool lastXLine READ lastXLine WRITE setLastXLine NOTIFY
lastXLineChanged FINAL)
Q_PROPERTY(
int minHorizontalLines READ minHorizontalLines WRITE
setMinHorizontalLines NOTIFY minHorizontalLinesChanged FINAL)
Q_PROPERTY(
XLabelMode xLabelMode READ xLabelMode WRITE setXLabelMode NOTIFY
xLabelModeChanged FINAL)
Q_PROPERTY(
bool useTwelveHourClock READ useTwelveHourClock WRITE
setUseTwelveHourClock NOTIFY useTwelveHourClockChanged FINAL)
Q_PROPERTY(
YLabelMode yLabelMode READ yLabelMode WRITE setYLabelMode NOTIFY
yLabelModeChanged FINAL)
Q_PROPERTY(
QString yLabelSuffix READ yLabelSuffix WRITE setYLabelSuffix NOTIFY
yLabelSuffixChanged FINAL)
Q_PROPERTY(
int yLabelDecimals READ yLabelDecimals WRITE setYLabelDecimals NOTIFY
yLabelDecimalsChanged FINAL)
Q_PROPERTY(
qreal smoothing READ smoothing WRITE setSmoothing NOTIFY
smoothingChanged FINAL)
Q_PROPERTY(
bool curveSmoothing READ curveSmoothing WRITE setCurveSmoothing NOTIFY
curveSmoothingChanged FINAL)
Q_PROPERTY(
qreal markerX READ markerX WRITE setMarkerX NOTIFY markerXChanged FINAL)
Q_PROPERTY(
qreal markerGap READ markerGap WRITE setMarkerGap NOTIFY
markerGapChanged FINAL)
Q_PROPERTY(
QColor lineColor READ lineColor WRITE setLineColor NOTIFY
lineColorChanged FINAL)
Q_PROPERTY(
QColor gridColor READ gridColor WRITE setGridColor NOTIFY
gridColorChanged FINAL)
Q_PROPERTY(
QColor markerColor READ markerColor WRITE setMarkerColor NOTIFY
markerColorChanged FINAL)
Q_PROPERTY(
QColor labelColor READ labelColor WRITE setLabelColor NOTIFY
labelColorChanged FINAL)
Q_PROPERTY(
qreal gridAlpha READ gridAlpha WRITE setGridAlpha NOTIFY
gridAlphaChanged FINAL)
Q_PROPERTY(
qreal labelAlpha READ labelAlpha WRITE setLabelAlpha NOTIFY
labelAlphaChanged FINAL)
Q_PROPERTY(
qreal fillAlpha READ fillAlpha WRITE setFillAlpha NOTIFY
fillAlphaChanged FINAL)
Q_PROPERTY(
qreal lineWidth READ lineWidth WRITE setLineWidth NOTIFY
lineWidthChanged FINAL)
Q_PROPERTY(
qreal markerDotRadius READ markerDotRadius WRITE setMarkerDotRadius
NOTIFY markerDotRadiusChanged FINAL)
Q_PROPERTY(
qreal labelFontSize READ labelFontSize WRITE setLabelFontSize NOTIFY
labelFontSizeChanged FINAL)
public:
// How an x tick (integer index 0..xSteps) is labelled. Hour renders an
// hour-of-day, honouring useTwelveHourClock.
enum class XLabelMode { None, Number, Hour };
Q_ENUM(XLabelMode)
// How a y tick value is labelled. Value renders the number rounded to
// yLabelDecimals places, followed by yLabelSuffix.
enum class YLabelMode { Off, Value };
Q_ENUM(YLabelMode)
explicit LineGraph(QQuickItem* parent = nullptr);
[[nodiscard]] QVariantList values() const;
void setValues(const QVariantList& values);
[[nodiscard]] int xSteps() const;
void setXSteps(int xSteps);
[[nodiscard]] qreal yMin() const;
void setYMin(qreal value);
[[nodiscard]] qreal yMax() const;
void setYMax(qreal value);
[[nodiscard]] qreal yPaddingTop() const;
void setYPaddingTop(qreal value);
[[nodiscard]] qreal yPaddingBottom() const;
void setYPaddingBottom(qreal value);
[[nodiscard]] int verticalLineStep() const;
void setVerticalLineStep(int step);
[[nodiscard]] int horizontalLineStep() const;
void setHorizontalLineStep(int step);
[[nodiscard]] bool firstXLine() const;
void setFirstXLine(bool show);
[[nodiscard]] bool lastXLine() const;
void setLastXLine(bool show);
[[nodiscard]] int minHorizontalLines() const;
void setMinHorizontalLines(int count);
[[nodiscard]] XLabelMode xLabelMode() const;
void setXLabelMode(XLabelMode mode);
[[nodiscard]] bool useTwelveHourClock() const;
void setUseTwelveHourClock(bool use);
[[nodiscard]] YLabelMode yLabelMode() const;
void setYLabelMode(YLabelMode mode);
[[nodiscard]] QString yLabelSuffix() const;
void setYLabelSuffix(const QString& suffix);
[[nodiscard]] int yLabelDecimals() const;
void setYLabelDecimals(int decimals);
[[nodiscard]] qreal smoothing() const;
void setSmoothing(qreal smoothing);
[[nodiscard]] bool curveSmoothing() const;
void setCurveSmoothing(bool enabled);
[[nodiscard]] qreal markerX() const;
void setMarkerX(qreal markerX);
[[nodiscard]] qreal markerGap() const;
void setMarkerGap(qreal gap);
[[nodiscard]] QColor lineColor() const;
void setLineColor(const QColor& color);
[[nodiscard]] QColor gridColor() const;
void setGridColor(const QColor& color);
[[nodiscard]] QColor markerColor() const;
void setMarkerColor(const QColor& color);
[[nodiscard]] QColor labelColor() const;
void setLabelColor(const QColor& color);
[[nodiscard]] qreal gridAlpha() const;
void setGridAlpha(qreal alpha);
[[nodiscard]] qreal labelAlpha() const;
void setLabelAlpha(qreal alpha);
[[nodiscard]] qreal fillAlpha() const;
void setFillAlpha(qreal alpha);
[[nodiscard]] qreal lineWidth() const;
void setLineWidth(qreal width);
[[nodiscard]] qreal markerDotRadius() const;
void setMarkerDotRadius(qreal radius);
[[nodiscard]] qreal labelFontSize() const;
void setLabelFontSize(qreal size);
signals:
void valuesChanged();
void xStepsChanged();
void yMinChanged();
void yMaxChanged();
void yPaddingTopChanged();
void yPaddingBottomChanged();
void verticalLineStepChanged();
void horizontalLineStepChanged();
void firstXLineChanged();
void lastXLineChanged();
void minHorizontalLinesChanged();
void xLabelModeChanged();
void useTwelveHourClockChanged();
void yLabelModeChanged();
void yLabelSuffixChanged();
void yLabelDecimalsChanged();
void smoothingChanged();
void curveSmoothingChanged();
void markerXChanged();
void markerGapChanged();
void lineColorChanged();
void gridColorChanged();
void markerColorChanged();
void labelColorChanged();
void gridAlphaChanged();
void labelAlphaChanged();
void fillAlphaChanged();
void lineWidthChanged();
void markerDotRadiusChanged();
void labelFontSizeChanged();
protected:
[[nodiscard]] QCanvasPainterItemRenderer* createItemRenderer()
const override;
// Device-pixel snapping and stroke width are quantized in device pixels, so
// they must use the ratio the window actually has.
void itemChange(ItemChange change, const ItemChangeData& value) override;
private:
friend class LineGraphRenderer;
QVariantList m_values;
int m_xSteps = 24;
qreal m_yMin = std::numeric_limits<qreal>::quiet_NaN();
qreal m_yMax = std::numeric_limits<qreal>::quiet_NaN();
qreal m_yPaddingTop = 0.0;
qreal m_yPaddingBottom = 0.0;
int m_verticalLineStep = 0;
int m_horizontalLineStep = 0;
bool m_firstXLine = true;
bool m_lastXLine = false;
int m_minHorizontalLines = 0;
XLabelMode m_xLabelMode = XLabelMode::None;
bool m_useTwelveHourClock = false;
YLabelMode m_yLabelMode = YLabelMode::Off;
QString m_yLabelSuffix;
int m_yLabelDecimals = 0;
qreal m_smoothing = 0.0;
bool m_curveSmoothing = true;
qreal m_markerX = -1.0;
qreal m_markerGap = 2.0;
QColor m_lineColor = Qt::white;
QColor m_gridColor = Qt::white;
QColor m_markerColor = Qt::white;
QColor m_labelColor = Qt::white;
qreal m_gridAlpha = 0.12;
qreal m_labelAlpha = 0.6;
qreal m_fillAlpha = 0.15;
qreal m_lineWidth = 2.0;
qreal m_markerDotRadius = 4.0;
qreal m_labelFontSize = 8.0;
qreal m_dpr = 1.0;
};
} // namespace ZShell::components