Add x axis

This commit is contained in:
Emil Sawicki 2022-01-25 19:13:00 +01:00
parent fdf7807cfb
commit a3ffc08d49
5 changed files with 91 additions and 10 deletions

View File

@ -68,17 +68,22 @@ void LinesChart::drawDesignMode(QPainter* painter, qreal hStep, qreal vStep, qre
} }
} }
qreal LinesChart::calculateValueYPos(qreal, qreal max, qreal value, qreal delta, qreal height) qreal LinesChart::calculatePos(const AxisData &data, qreal value, qreal rectSize) const
{ {
return (max - value) / delta * height; if (data.reverseDirection() && data.rangeMin() >= 0) {
// Not flipping for minimum less than 0 because lower number is at the bottom.
return (1 - (data.rangeMax() - value) / data.delta()) * rectSize;
} else {
return (data.rangeMax() - value) / data.delta() * rectSize;
}
} }
void LinesChart::paintSeries(QPainter *painter, SeriesItem *series, QRectF barsRect) void LinesChart::paintSeries(QPainter *painter, SeriesItem *series, QRectF barsRect)
{ {
const AxisData &yAxisData = this->yAxisData(); const AxisData &yAxisData = this->yAxisData();
const qreal delta = yAxisData.delta();
const qreal hStep = barsRect.width() / valuesCount(); const qreal xAxisDiff = std::max(1.0, maxXValue() - minXValue());
const qreal hStep = barsRect.width() / xAxisDiff;
const qreal topMargin = barsRect.top(); const qreal topMargin = barsRect.top();
QPen pen(series->color()); QPen pen(series->color());
@ -91,11 +96,11 @@ void LinesChart::paintSeries(QPainter *painter, SeriesItem *series, QRectF barsR
qreal lastXValue = barsRect.left() + hStep/2; qreal lastXValue = barsRect.left() + hStep/2;
if (!values.isEmpty()) { if (!values.isEmpty()) {
// Calculate first point position on plot before loop // Calculate first point position on plot before loop
lastYValue = calculateValueYPos(yAxisData.rangeMin(), yAxisData.rangeMax(), values.first(), delta, barsRect.height()); lastYValue = calculatePos(yAxisData, values.first(), barsRect.height());
} }
for (int i = 0; i < values.count()-1; ++i ){ for (int i = 0; i < values.count()-1; ++i ){
const qreal startY = lastYValue; const qreal startY = lastYValue;
const qreal endY = calculateValueYPos(yAxisData.rangeMin(), yAxisData.rangeMax(), values.at(i+1), delta, barsRect.height()); const qreal endY = calculatePos(yAxisData, values.at(i+1), barsRect.height());
// Record last used Y position to only calculate new one // Record last used Y position to only calculate new one
lastYValue = endY; lastYValue = endY;

View File

@ -10,7 +10,7 @@ public:
void paintChart(QPainter *painter, QRectF chartRect); void paintChart(QPainter *painter, QRectF chartRect);
protected: protected:
void drawDesignMode(QPainter *painter, qreal hStep, qreal vStep, qreal topShift, QRectF barsRect); void drawDesignMode(QPainter *painter, qreal hStep, qreal vStep, qreal topShift, QRectF barsRect);
qreal calculateValueYPos(qreal min, qreal max, qreal value, qreal delta, qreal height); qreal calculatePos(const AxisData &data, qreal value, qreal rectSize) const;
void paintSeries(QPainter *painter, SeriesItem *series, QRectF barsRect); void paintSeries(QPainter *painter, SeriesItem *series, QRectF barsRect);
private: private:

View File

@ -79,6 +79,16 @@ void SeriesItem::setLabelsColumn(const QString &labelsColumn)
m_labelsColumn = labelsColumn; m_labelsColumn = labelsColumn;
} }
QString SeriesItem::xAxisColumn() const
{
return m_xAxisColumn;
}
void SeriesItem::setXAxisColumn(const QString &xAxisColumn)
{
m_xAxisColumn = xAxisColumn;
}
SeriesItem *SeriesItem::clone() SeriesItem *SeriesItem::clone()
{ {
SeriesItem* result = new SeriesItem(); SeriesItem* result = new SeriesItem();
@ -98,6 +108,8 @@ void SeriesItem::fillSeriesData(IDataSource *dataSource)
while(!dataSource->eof()){ while(!dataSource->eof()){
if (!m_labelsColumn.isEmpty()) if (!m_labelsColumn.isEmpty())
m_data.labels().append(dataSource->data(m_labelsColumn).toString()); m_data.labels().append(dataSource->data(m_labelsColumn).toString());
if (!m_xAxisColumn.isEmpty())
m_data.xAxisValues().append(dataSource->data(m_xAxisColumn).toDouble());
m_data.values().append(dataSource->data(m_valuesColumn).toDouble()); m_data.values().append(dataSource->data(m_valuesColumn).toDouble());
m_data.colors().append((currentColorIndex<32)?color_map[currentColorIndex]:generateColor()); m_data.colors().append((currentColorIndex<32)?color_map[currentColorIndex]:generateColor());
dataSource->next(); dataSource->next();
@ -130,7 +142,8 @@ ChartItem::ChartItem(QObject *owner, QGraphicsItem *parent)
: ItemDesignIntf(xmlTag, owner, parent), m_legendBorder(true), : ItemDesignIntf(xmlTag, owner, parent), m_legendBorder(true),
m_legendAlign(LegendAlignCenter), m_titleAlign(TitleAlignCenter), m_legendAlign(LegendAlignCenter), m_titleAlign(TitleAlignCenter),
m_chartType(Pie), m_labelsField(""), m_isEmpty(true), m_chartType(Pie), m_labelsField(""), m_isEmpty(true),
m_showLegend(true), m_drawPoints(true), m_seriesLineWidth(4) m_showLegend(true), m_drawPoints(true), m_seriesLineWidth(4),
m_horizontalAxisOnTop(false), m_legendStyle(LegendPoints)
{ {
m_labels<<"First"<<"Second"<<"Thrid"; m_labels<<"First"<<"Second"<<"Thrid";
m_chart = new PieChart(this); m_chart = new PieChart(this);
@ -235,6 +248,7 @@ void ChartItem::updateItemSize(DataSourceManager *dataManager, RenderPass , int
foreach (SeriesItem* series, m_series) { foreach (SeriesItem* series, m_series) {
if (series->isEmpty()){ if (series->isEmpty()){
series->setLabelsColumn(m_labelsField); series->setLabelsColumn(m_labelsField);
series->setXAxisColumn(m_xAxisField);
series->fillSeriesData(ds); series->fillSeriesData(ds);
} }
} }
@ -464,6 +478,31 @@ void ChartItem::setSeriesLineWidth(int newSeriesLineWidth)
m_seriesLineWidth = newSeriesLineWidth; m_seriesLineWidth = newSeriesLineWidth;
} }
QString ChartItem::xAxisField() const
{
return m_xAxisField;
}
void ChartItem::setXAxisField(const QString &xAxisField)
{
m_xAxisField = xAxisField;
}
bool ChartItem::horizontalAxisOnTop() const
{
return m_horizontalAxisOnTop;
}
void ChartItem::setHorizontalAxisOnTop(bool horizontalAxisOnTop)
{
if (m_horizontalAxisOnTop != horizontalAxisOnTop){
m_horizontalAxisOnTop = horizontalAxisOnTop;
notify("horizontalAxisOnTop", !m_horizontalAxisOnTop, m_horizontalAxisOnTop);
update();
}
m_horizontalAxisOnTop = horizontalAxisOnTop;
}
AbstractChart::AbstractChart(ChartItem *chartItem) AbstractChart::AbstractChart(ChartItem *chartItem)
:m_chartItem(chartItem) :m_chartItem(chartItem)
{ {
@ -550,20 +589,40 @@ qreal AbstractSeriesChart::minValue()
AxisData AbstractSeriesChart::yAxisData() AxisData AbstractSeriesChart::yAxisData()
{ {
return m_yAxisData; return m_yAxisData;
qreal AbstractSeriesChart::minXValue()
{
return m_chartItem->xAxisData()->minValue();
}
} }
void AbstractSeriesChart::updateMinAndMaxValues() void AbstractSeriesChart::updateMinAndMaxValues()
{ {
qreal maxYValue = 0; qreal maxYValue = 0;
qreal minYValue = 0; qreal minYValue = 0;
qreal maxXValue = 0;
qreal minXValue = 0;
if (m_chartItem->itemMode() == DesignMode) { if (m_chartItem->itemMode() == DesignMode) {
maxYValue = 40; maxYValue = 40;
maxXValue = 40;
} else { } else {
for (SeriesItem* series : m_chartItem->series()){ for (SeriesItem* series : m_chartItem->series()){
for (qreal value : series->data()->values()){ for (qreal value : series->data()->values()){
minYValue = std::min(minYValue, value); minYValue = std::min(minYValue, value);
maxYValue = std::max(maxYValue, value); maxYValue = std::max(maxYValue, value);
} }
if (series->data()->xAxisValues().isEmpty()) {
// Grid plot starts from 0 on x axis so x range must be decresed by 1
const bool startingFromZero = m_chartItem->chartType() == ChartItem::GridLines;
const qreal valuesCount = this->valuesCount() - (startingFromZero ? 1 : 0);
minXValue = std::min(0.0, minXValue);
maxXValue = std::max(valuesCount, maxXValue);
} else {
for (qreal value : series->data()->xAxisValues()){
minXValue = std::min(value, minXValue);
maxXValue = std::max(value, maxXValue);
}
}
} }
} }

View File

@ -16,11 +16,12 @@ class SeriesItemData : public QObject{
Q_OBJECT Q_OBJECT
public: public:
QList<qreal>& values(){ return m_values;} QList<qreal>& values(){ return m_values;}
QList<qreal>& xAxisValues(){ return m_xAxisValues;}
QList<QString>& labels(){ return m_labels;} QList<QString>& labels(){ return m_labels;}
QList<QColor>& colors() { return m_colors;} QList<QColor>& colors() { return m_colors;}
void clear(){ m_values.clear(); m_labels.clear(); m_colors.clear(); } void clear(){ m_values.clear(); m_labels.clear(); m_colors.clear(); }
private: private:
QList<qreal> m_values; QList<qreal> m_values, m_xAxisValues;
QList<QString> m_labels; QList<QString> m_labels;
QList<QColor> m_colors; QList<QColor> m_colors;
}; };
@ -30,6 +31,7 @@ class SeriesItem : public QObject{
Q_PROPERTY(QString name READ name WRITE setName) Q_PROPERTY(QString name READ name WRITE setName)
Q_PROPERTY(QString valuesColumn READ valuesColumn WRITE setValuesColumn) Q_PROPERTY(QString valuesColumn READ valuesColumn WRITE setValuesColumn)
Q_PROPERTY(QString labelsColumn READ labelsColumn WRITE setLabelsColumn) Q_PROPERTY(QString labelsColumn READ labelsColumn WRITE setLabelsColumn)
Q_PROPERTY(QString xAxisColumn READ xAxisColumn WRITE setXAxisColumn)
Q_PROPERTY(QColor color READ color WRITE setColor) Q_PROPERTY(QColor color READ color WRITE setColor)
Q_PROPERTY(SeriesItemPreferredType preferredType READ preferredType WRITE setPreferredType) Q_PROPERTY(SeriesItemPreferredType preferredType READ preferredType WRITE setPreferredType)
public: public:
@ -46,6 +48,8 @@ public:
void setValuesColumn(const QString &valuesColumn); void setValuesColumn(const QString &valuesColumn);
QString labelsColumn() const; QString labelsColumn() const;
void setLabelsColumn(const QString &labelsColumn); void setLabelsColumn(const QString &labelsColumn);
QString xAxisColumn() const;
void setXAxisColumn(const QString &xAxisColumn);
SeriesItem* clone(); SeriesItem* clone();
void fillSeriesData(IDataSource* dataSource); void fillSeriesData(IDataSource* dataSource);
SeriesItemData* data(){ return &m_data;} SeriesItemData* data(){ return &m_data;}
@ -58,6 +62,7 @@ private:
QString m_name; QString m_name;
QString m_valuesColumn; QString m_valuesColumn;
QString m_labelsColumn; QString m_labelsColumn;
QString m_xAxisColumn;
SeriesItemData m_data; SeriesItemData m_data;
QColor m_color; QColor m_color;
SeriesItemPreferredType m_preferredType; SeriesItemPreferredType m_preferredType;
@ -86,7 +91,8 @@ public:
protected: protected:
qreal maxValue(); qreal maxValue();
qreal minValue(); qreal minValue();
AxisData yAxisData(); qreal maxXValue();
qreal minXValue();
void updateMinAndMaxValues(); void updateMinAndMaxValues();
int valuesCount(); int valuesCount();
int seriesCount(); int seriesCount();
@ -136,6 +142,8 @@ class ChartItem : public LimeReport::ItemDesignIntf
//linesChart //linesChart
Q_PROPERTY(bool drawPoints READ drawPoints WRITE setDrawPoints) Q_PROPERTY(bool drawPoints READ drawPoints WRITE setDrawPoints)
Q_PROPERTY(int seriesLineWidth READ seriesLineWidth WRITE setSeriesLineWidth) Q_PROPERTY(int seriesLineWidth READ seriesLineWidth WRITE setSeriesLineWidth)
Q_PROPERTY(bool horizontalAxisOnTop READ horizontalAxisOnTop WRITE setHorizontalAxisOnTop)
Q_PROPERTY(QString xAxisField READ xAxisField WRITE setXAxisField)
friend class AbstractChart; friend class AbstractChart;
public: public:
@ -194,6 +202,12 @@ public:
int seriesLineWidth() const; int seriesLineWidth() const;
void setSeriesLineWidth(int newSeriesLineWidth); void setSeriesLineWidth(int newSeriesLineWidth);
QString xAxisField() const;
void setXAxisField(const QString &xAxisField);
bool horizontalAxisOnTop() const;
void setHorizontalAxisOnTop(bool horizontalAxisOnTop);
protected: protected:
void paintChartTitle(QPainter* painter, QRectF titleRect); void paintChartTitle(QPainter* painter, QRectF titleRect);
virtual BaseDesignIntf* createSameTypeItem(QObject *owner, QGraphicsItem *parent); virtual BaseDesignIntf* createSameTypeItem(QObject *owner, QGraphicsItem *parent);
@ -222,6 +236,8 @@ private:
bool m_showLegend; bool m_showLegend;
bool m_drawPoints; bool m_drawPoints;
int m_seriesLineWidth; int m_seriesLineWidth;
QString m_xAxisField;
bool m_horizontalAxisOnTop;
}; };
} //namespace LimeReport } //namespace LimeReport
#endif // LRCHARTITEM_H #endif // LRCHARTITEM_H

View File

@ -144,6 +144,7 @@ void QObjectPropertyModel::translatePropertyName()
tr("chartType"); tr("chartType");
tr("drawLegendBorder"); tr("drawLegendBorder");
tr("labelsField"); tr("labelsField");
tr("xAxisField");
tr("legendAlign"); tr("legendAlign");
tr("series"); tr("series");
tr("titleAlign"); tr("titleAlign");