mirror of
https://github.com/fralx/LimeReport.git
synced 2024-12-24 00:33:02 +03:00
Merge pull request #388 from emil-sawicki9/feature/add-horizontal-legend
Feature/add horizontal legend
This commit is contained in:
commit
2ccb2faf18
@ -143,7 +143,7 @@ void PieChart::paintChartLegend(QPainter *painter, QRectF legendRect)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF PieChart::calcChartLegendSize(const QFont &font)
|
QSizeF PieChart::calcChartLegendSize(const QFont &font, qreal)
|
||||||
{
|
{
|
||||||
QFontMetrics fm(font);
|
QFontMetrics fm(font);
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ namespace LimeReport{
|
|||||||
class PieChart : public AbstractChart{
|
class PieChart : public AbstractChart{
|
||||||
public:
|
public:
|
||||||
PieChart(ChartItem* chartItem):AbstractChart(chartItem){}
|
PieChart(ChartItem* chartItem):AbstractChart(chartItem){}
|
||||||
QSizeF calcChartLegendSize(const QFont &font);
|
QSizeF calcChartLegendSize(const QFont &font, qreal maxWidth = 0);
|
||||||
void paintChart(QPainter *painter, QRectF chartRect);
|
void paintChart(QPainter *painter, QRectF chartRect);
|
||||||
void paintChartLegend(QPainter *painter, QRectF legendRect);
|
void paintChartLegend(QPainter *painter, QRectF legendRect);
|
||||||
protected:
|
protected:
|
||||||
|
@ -141,10 +141,11 @@ void SeriesItem::setPreferredType(const SeriesItemPreferredType& type)
|
|||||||
|
|
||||||
ChartItem::ChartItem(QObject *owner, QGraphicsItem *parent)
|
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(LegendAlignRightCenter), 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_gridChartLines(AllLines)
|
m_horizontalAxisOnTop(false), m_gridChartLines(AllLines),
|
||||||
|
m_legendStyle(LegendPoints)
|
||||||
{
|
{
|
||||||
m_labels<<"First"<<"Second"<<"Thrid";
|
m_labels<<"First"<<"Second"<<"Thrid";
|
||||||
m_chart = new PieChart(this);
|
m_chart = new PieChart(this);
|
||||||
@ -195,11 +196,24 @@ void ChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
|||||||
}
|
}
|
||||||
|
|
||||||
const QRectF titleRect = QRectF(borderMargin,borderMargin,rect().width()-borderMargin*2,titleOffset);
|
const QRectF titleRect = QRectF(borderMargin,borderMargin,rect().width()-borderMargin*2,titleOffset);
|
||||||
QRectF legendRect = QRectF(0,0,0,0);
|
QRectF legendRect = QRectF(0, 0, 0, 0);
|
||||||
if (m_showLegend)
|
QRectF diagramRect = rect().adjusted(borderMargin, titleOffset + borderMargin,
|
||||||
|
-(borderMargin * 2), -borderMargin);
|
||||||
|
if (m_showLegend) {
|
||||||
legendRect = m_chart->calcChartLegendRect(painter->font(), rect(), false, borderMargin, titleOffset);
|
legendRect = m_chart->calcChartLegendRect(painter->font(), rect(), false, borderMargin, titleOffset);
|
||||||
QRectF diagramRect = rect().adjusted(borderMargin,titleOffset+borderMargin,
|
switch(legendAlign()) {
|
||||||
-(legendRect.width()+borderMargin*2),-borderMargin);
|
case LegendAlignRightTop:
|
||||||
|
case LegendAlignRightBottom:
|
||||||
|
case LegendAlignRightCenter:
|
||||||
|
diagramRect.adjust(0, 0, -legendRect.width(), 0);
|
||||||
|
break;
|
||||||
|
case LegendAlignBottomLeft:
|
||||||
|
case LegendAlignBottomCenter:
|
||||||
|
case LegendAlignBottomRight:
|
||||||
|
diagramRect.adjust(0, 0, 0, -(legendRect.height() + borderMargin * 2));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
paintChartTitle(painter, titleRect);
|
paintChartTitle(painter, titleRect);
|
||||||
if (m_showLegend)
|
if (m_showLegend)
|
||||||
@ -414,6 +428,22 @@ void ChartItem::setLegendAlign(const LegendAlign &legendAlign)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ChartItem::LegendStyle ChartItem::legendStyle() const
|
||||||
|
{
|
||||||
|
return m_legendStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChartItem::setLegendStyle(const LegendStyle &legendStyle)
|
||||||
|
{
|
||||||
|
if (m_legendStyle == legendStyle) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LegendStyle oldValue = m_legendStyle;
|
||||||
|
m_legendStyle = legendStyle;
|
||||||
|
notify("legendStyle", oldValue, m_legendStyle);
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
bool ChartItem::drawLegendBorder() const
|
bool ChartItem::drawLegendBorder() const
|
||||||
{
|
{
|
||||||
return m_legendBorder;
|
return m_legendBorder;
|
||||||
@ -571,37 +601,61 @@ AbstractChart::AbstractChart(ChartItem *chartItem)
|
|||||||
|
|
||||||
QRectF AbstractChart::calcChartLegendRect(const QFont &font, const QRectF &parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset)
|
QRectF AbstractChart::calcChartLegendRect(const QFont &font, const QRectF &parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset)
|
||||||
{
|
{
|
||||||
QSizeF legendSize = calcChartLegendSize(font);
|
const QSizeF legendSize = calcChartLegendSize(font, parentRect.width() * 0.9);
|
||||||
qreal legendTopMargin = 0;
|
qreal legendTopMargin = 0;
|
||||||
qreal legendBottomMargin = 0;
|
qreal legendBottomMargin = 0;
|
||||||
|
qreal legendLeftMargin = 0;
|
||||||
|
|
||||||
|
bool isVertical = true;
|
||||||
switch (m_chartItem->legendAlign()) {
|
switch (m_chartItem->legendAlign()) {
|
||||||
case ChartItem::LegendAlignTop:
|
case ChartItem::LegendAlignRightTop:
|
||||||
legendTopMargin = titleOffset+borderMargin;
|
legendTopMargin = titleOffset + borderMargin;
|
||||||
legendBottomMargin = parentRect.height()-(legendSize.height()+titleOffset);
|
legendBottomMargin = parentRect.height() - (legendSize.height() + titleOffset);
|
||||||
|
isVertical = true;
|
||||||
break;
|
break;
|
||||||
case ChartItem::LegendAlignCenter:
|
case ChartItem::LegendAlignRightCenter:
|
||||||
legendTopMargin = titleOffset+(parentRect.height()-titleOffset-legendSize.height())/2;
|
legendTopMargin = titleOffset + (parentRect.height() - titleOffset - legendSize.height()) / 2;
|
||||||
legendBottomMargin = (parentRect.height()-titleOffset-legendSize.height())/2;
|
legendBottomMargin = (parentRect.height() - titleOffset - legendSize.height()) / 2;
|
||||||
|
isVertical = true;
|
||||||
break;
|
break;
|
||||||
case ChartItem::LegendAlignBottom:
|
case ChartItem::LegendAlignRightBottom:
|
||||||
legendTopMargin = parentRect.height()-(legendSize.height()+titleOffset);
|
legendTopMargin = parentRect.height() - (legendSize.height() + titleOffset);
|
||||||
legendBottomMargin = borderMargin;
|
legendBottomMargin = borderMargin;
|
||||||
|
isVertical = true;
|
||||||
|
break;
|
||||||
|
case ChartItem::LegendAlignBottomLeft:
|
||||||
|
legendLeftMargin = QFontMetrics(font).height() / 2;
|
||||||
|
isVertical = false;
|
||||||
|
break;
|
||||||
|
case ChartItem::LegendAlignBottomCenter:
|
||||||
|
legendLeftMargin = (parentRect.width() - legendSize.width()) / 2;
|
||||||
|
isVertical = false;
|
||||||
|
break;
|
||||||
|
case ChartItem::LegendAlignBottomRight:
|
||||||
|
legendLeftMargin = parentRect.width() - legendSize.width() - QFontMetrics(font).height() / 2;
|
||||||
|
isVertical = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
qreal rightOffset = !takeAllRect?((legendSize.width()>parentRect.width()/2-borderMargin)?
|
if (isVertical) {
|
||||||
(parentRect.width()/2):
|
qreal rightOffset = !takeAllRect ? ((legendSize.width() > parentRect.width() / 2 - borderMargin) ?
|
||||||
(parentRect.width()-legendSize.width())):0;
|
(parentRect.width() / 2) :
|
||||||
|
(parentRect.width() - legendSize.width())) : 0;
|
||||||
QRectF legendRect = parentRect.adjusted(
|
return parentRect.adjusted(
|
||||||
rightOffset,
|
rightOffset,
|
||||||
(legendSize.height()>(parentRect.height()-titleOffset))?(titleOffset):(legendTopMargin),
|
(legendSize.height()>(parentRect.height()-titleOffset))?(titleOffset):(legendTopMargin),
|
||||||
-borderMargin,
|
-borderMargin,
|
||||||
(legendSize.height()>(parentRect.height()-titleOffset))?(0):(-legendBottomMargin)
|
(legendSize.height()>(parentRect.height()-titleOffset))?(0):(-legendBottomMargin)
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
return legendRect;
|
const qreal verticalOffset = borderMargin * 2;
|
||||||
|
return parentRect.adjusted(
|
||||||
|
legendLeftMargin,
|
||||||
|
(parentRect.height()) - (legendSize.height() + verticalOffset),
|
||||||
|
-(parentRect.width() - (legendSize.width() + legendLeftMargin)),
|
||||||
|
-verticalOffset
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -618,18 +672,39 @@ void AbstractChart::setTitleFont(const QFont &value)
|
|||||||
void AbstractChart::prepareLegendToPaint(QRectF &legendRect, QPainter *painter)
|
void AbstractChart::prepareLegendToPaint(QRectF &legendRect, QPainter *painter)
|
||||||
{
|
{
|
||||||
QFont tmpFont = painter->font();
|
QFont tmpFont = painter->font();
|
||||||
QSizeF legendSize = calcChartLegendSize(tmpFont);
|
switch(m_chartItem->legendAlign()) {
|
||||||
|
case ChartItem::LegendAlignBottomLeft:
|
||||||
if ((legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width())){
|
case ChartItem::LegendAlignBottomCenter:
|
||||||
while ( (legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width())
|
case ChartItem::LegendAlignBottomRight: {
|
||||||
&& tmpFont.pixelSize()>1)
|
const qreal maxWidth = legendRect.width() * 0.95;
|
||||||
|
qreal legendWidth = std::accumulate(m_legendColumnWidths.cbegin(), m_legendColumnWidths.cend(), 0.0);
|
||||||
|
if (legendWidth < maxWidth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ( (legendWidth > maxWidth) && tmpFont.pixelSize() > 1) {
|
||||||
|
tmpFont.setPixelSize(tmpFont.pixelSize() - 1);
|
||||||
|
calcChartLegendSize(tmpFont, legendRect.width());
|
||||||
|
legendWidth = std::accumulate(m_legendColumnWidths.cbegin(), m_legendColumnWidths.cend(), 0.0);
|
||||||
|
}
|
||||||
|
painter->setFont(tmpFont);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ChartItem::LegendAlignRightTop:
|
||||||
|
case ChartItem::LegendAlignRightCenter:
|
||||||
|
case ChartItem::LegendAlignRightBottom:
|
||||||
|
QSizeF legendSize = calcChartLegendSize(tmpFont, legendRect.width());
|
||||||
|
if ((legendSize.height() <= legendRect.height() && legendSize.width() <= legendRect.width())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while ((legendSize.height() > legendRect.height() || legendSize.width() > legendRect.width())
|
||||||
|
&& tmpFont.pixelSize() > 1)
|
||||||
{
|
{
|
||||||
tmpFont.setPixelSize(tmpFont.pixelSize()-1);
|
tmpFont.setPixelSize(tmpFont.pixelSize() - 1);
|
||||||
painter->setFont(tmpFont);
|
legendSize = calcChartLegendSize(tmpFont, legendRect.width());
|
||||||
legendSize = calcChartLegendSize(tmpFont);
|
|
||||||
}
|
}
|
||||||
painter->setFont(tmpFont);
|
painter->setFont(tmpFont);
|
||||||
legendRect = calcChartLegendRect(tmpFont, legendRect, true, 0, 0);
|
legendRect = calcChartLegendRect(tmpFont, legendRect, true, 0, 0);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -723,28 +798,54 @@ int AbstractSeriesChart::seriesCount()
|
|||||||
return m_chartItem->series().count();
|
return m_chartItem->series().count();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSizeF AbstractSeriesChart::calcChartLegendSize(const QFont &font)
|
QSizeF AbstractSeriesChart::calcChartLegendSize(const QFont &font, const qreal maxWidth)
|
||||||
{
|
{
|
||||||
QFontMetrics fm(font);
|
QFontMetrics fm(font);
|
||||||
|
|
||||||
qreal cw = 0;
|
switch(m_chartItem->legendAlign()) {
|
||||||
qreal maxWidth = 0;
|
case ChartItem::LegendAlignBottomLeft:
|
||||||
|
case ChartItem::LegendAlignBottomCenter:
|
||||||
if (!m_chartItem->series().isEmpty()){
|
case ChartItem::LegendAlignBottomRight: {
|
||||||
foreach(SeriesItem* series, m_chartItem->series()){
|
const qreal seriesCount = m_chartItem->series().isEmpty() ? m_designLabels.size() : m_chartItem->series().size();
|
||||||
cw += fm.height();
|
const qreal indicatorWidth = fm.height() * 1.5;
|
||||||
if (maxWidth<fm.boundingRect(series->name()).width())
|
m_legendColumnWidths.clear();
|
||||||
maxWidth = fm.boundingRect(series->name()).width()+10;
|
while (!calculateLegendColumnWidths(indicatorWidth, maxWidth, fm)) {
|
||||||
|
// Nothing to do here
|
||||||
}
|
}
|
||||||
} else {
|
if (m_legendColumnWidths.isEmpty()) {
|
||||||
foreach(QString label, m_designLabels){
|
m_legendColumnWidths.append(0);
|
||||||
cw += fm.height();
|
|
||||||
if (maxWidth<fm.boundingRect(label).width())
|
|
||||||
maxWidth = fm.boundingRect(label).width()+10;
|
|
||||||
}
|
}
|
||||||
|
const qreal columnCount = m_legendColumnWidths.size();
|
||||||
|
const qreal rowCount = std::ceil(seriesCount / columnCount);
|
||||||
|
QSizeF legendSize(std::accumulate(m_legendColumnWidths.cbegin(), m_legendColumnWidths.cend(), 0.0) + fm.height() / 2,
|
||||||
|
(rowCount + 1) * fm.height());
|
||||||
|
if (legendSize.width() > maxWidth) {
|
||||||
|
legendSize.setWidth(maxWidth);
|
||||||
|
}
|
||||||
|
return legendSize;
|
||||||
}
|
}
|
||||||
cw += fm.height();
|
default: {
|
||||||
return QSizeF(maxWidth+fm.height()*2,cw);
|
qreal cw = 0;
|
||||||
|
qreal maxWidth = 0;
|
||||||
|
|
||||||
|
if (m_chartItem->series().isEmpty()) {
|
||||||
|
foreach(QString label, m_designLabels){
|
||||||
|
cw += fm.height();
|
||||||
|
if (maxWidth<fm.boundingRect(label).width())
|
||||||
|
maxWidth = fm.boundingRect(label).width()+10;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
foreach(SeriesItem* series, m_chartItem->series()){
|
||||||
|
cw += fm.height();
|
||||||
|
if (maxWidth<fm.boundingRect(series->name()).width())
|
||||||
|
maxWidth = fm.boundingRect(series->name()).width()+10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cw += fm.height();
|
||||||
|
return QSizeF(maxWidth+fm.height()*2,cw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return QSizeF();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AbstractSeriesChart::verticalLabels(QPainter* painter, QRectF labelsRect)
|
bool AbstractSeriesChart::verticalLabels(QPainter* painter, QRectF labelsRect)
|
||||||
@ -1028,48 +1129,128 @@ QString AbstractSeriesChart::axisLabel(int i, const AxisData &axisData)
|
|||||||
return QString::number(round(value * 100.0) / 100.0);
|
return QString::number(round(value * 100.0) / 100.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AbstractSeriesChart::calculateLegendColumnWidths(qreal indicatorWidth, qreal maxWidth, const QFontMetrics &fm)
|
||||||
|
{
|
||||||
|
// This method is called in the loop, because to handle case when we get
|
||||||
|
// 3 small series names in first row and then in second row small name and long name.
|
||||||
|
// In this case we need to set maximum column count to 2 and iterate from the start to recalculate
|
||||||
|
// all the sizes
|
||||||
|
qreal currentRowWidth = 0;
|
||||||
|
int currentColumn = 0;
|
||||||
|
// During first iteration it is updated when moving to second row
|
||||||
|
// After first iteration some column width are already calculated and are set as max,
|
||||||
|
// because all rows need to have same column count (except last one)
|
||||||
|
int maxColumnCount = m_legendColumnWidths.size();
|
||||||
|
if (m_chartItem->series().isEmpty()) {
|
||||||
|
for (int i=0 ; i < m_designLabels.size() ; ++i) {
|
||||||
|
const qreal itemWidth = (qreal)(fm.boundingRect(m_designLabels[i]).width()) + indicatorWidth;
|
||||||
|
if (!calculateLegendSingleColumnWidth(currentRowWidth, currentColumn, maxColumnCount, itemWidth, maxWidth)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0 ; i < m_chartItem->series().size() ; ++i) {
|
||||||
|
SeriesItem* series = m_chartItem->series().at(i);
|
||||||
|
const qreal itemWidth = (qreal)(fm.boundingRect(series->name()).width()) + indicatorWidth;
|
||||||
|
if (!calculateLegendSingleColumnWidth(currentRowWidth, currentColumn, maxColumnCount, itemWidth, maxWidth)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AbstractSeriesChart::calculateLegendSingleColumnWidth(qreal ¤tRowWidth, int ¤tColumn, int &maxColumnCount,
|
||||||
|
const qreal itemWidth, const qreal maxRowWidth)
|
||||||
|
{
|
||||||
|
const bool maxColumnCountDefined = maxColumnCount > 0;
|
||||||
|
// Check if there is enough space for current item in the row
|
||||||
|
const bool isEnoughSpaceInRowForItem = currentRowWidth + itemWidth > maxRowWidth;
|
||||||
|
// Check if it is last column already
|
||||||
|
const bool lastColumnReached = (maxColumnCountDefined && currentColumn >= maxColumnCount);
|
||||||
|
if (isEnoughSpaceInRowForItem || lastColumnReached) {
|
||||||
|
// Move to next row
|
||||||
|
currentColumn = 0;
|
||||||
|
// Set column count when moving to second row (next rows cannot have more columns)
|
||||||
|
if (!maxColumnCountDefined) {
|
||||||
|
maxColumnCount = currentColumn + 1;
|
||||||
|
}
|
||||||
|
currentRowWidth = itemWidth;
|
||||||
|
} else {
|
||||||
|
// Add next column in the row
|
||||||
|
currentRowWidth += itemWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add new column or update already existing column width
|
||||||
|
if (currentColumn >= m_legendColumnWidths.size()) {
|
||||||
|
// Append new column
|
||||||
|
m_legendColumnWidths.append(itemWidth);
|
||||||
|
} else if (m_legendColumnWidths.at(currentColumn) < itemWidth) {
|
||||||
|
// Update size if item in column is bigger than items in same column in previous rows
|
||||||
|
m_legendColumnWidths[currentColumn] = itemWidth;
|
||||||
|
// After any updating column size we must recheck if all columns fit in the max row width
|
||||||
|
qreal rowWidth = itemWidth;
|
||||||
|
for (int c = 1 ; c < m_legendColumnWidths.size() ; c++) {
|
||||||
|
rowWidth += m_legendColumnWidths.at(c);
|
||||||
|
// When column widths exceed max row width remove columns at the end
|
||||||
|
if (rowWidth > maxRowWidth) {
|
||||||
|
m_legendColumnWidths.remove(c, m_legendColumnWidths.size() - c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Return back and re-iterate from start to make sure everything fits
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
++currentColumn;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<qreal> AbstractChart::legendColumnWidths() const
|
||||||
|
{
|
||||||
|
return m_legendColumnWidths;
|
||||||
|
}
|
||||||
|
|
||||||
void AbstractBarChart::paintChartLegend(QPainter *painter, QRectF legendRect)
|
void AbstractBarChart::paintChartLegend(QPainter *painter, QRectF legendRect)
|
||||||
{
|
{
|
||||||
prepareLegendToPaint(legendRect, painter);
|
prepareLegendToPaint(legendRect, painter);
|
||||||
int indicatorSize = painter->fontMetrics().height()/2;
|
|
||||||
painter->setPen(Qt::black);
|
painter->setPen(Qt::black);
|
||||||
painter->setRenderHint(QPainter::Antialiasing,false);
|
painter->setRenderHint(QPainter::Antialiasing,false);
|
||||||
if (m_chartItem->drawLegendBorder())
|
if (m_chartItem->drawLegendBorder())
|
||||||
painter->drawRect(legendRect);
|
painter->drawRect(legendRect);
|
||||||
painter->setRenderHint(QPainter::Antialiasing,true);
|
painter->setRenderHint(QPainter::Antialiasing,true);
|
||||||
QRectF indicatorsRect = legendRect.adjusted(painter->fontMetrics().height()/2,painter->fontMetrics().height()/2,0,0);
|
|
||||||
|
const qreal halfFontSize = painter->fontMetrics().height() / 2;
|
||||||
|
int indicatorSize = halfFontSize;
|
||||||
|
const QRectF indicatorsRect = legendRect.adjusted(halfFontSize, halfFontSize, 0, 0);
|
||||||
|
|
||||||
|
bool isHorizontal = false;
|
||||||
|
switch(m_chartItem->legendAlign()) {
|
||||||
|
case ChartItem::LegendAlignBottomLeft:
|
||||||
|
case ChartItem::LegendAlignBottomCenter:
|
||||||
|
case ChartItem::LegendAlignBottomRight:
|
||||||
|
isHorizontal = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
isHorizontal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!m_chartItem->series().isEmpty()){
|
if (!m_chartItem->series().isEmpty()){
|
||||||
qreal cw = 0;
|
for (int i = 0 ; i < m_chartItem->series().size() ; ++i) {
|
||||||
foreach(SeriesItem* series, m_chartItem->series()){
|
SeriesItem* series = m_chartItem->series().at(i);
|
||||||
QString label = series->name();
|
if (isHorizontal) {
|
||||||
painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label);
|
drawHorizontalLegendItem(painter, i, series->name(), indicatorSize, indicatorsRect, series->color());
|
||||||
painter->setBrush(series->color());
|
} else {
|
||||||
painter->drawEllipse(
|
drawVerticalLegendItem(painter, i, series->name(), indicatorSize, indicatorsRect, series->color());
|
||||||
indicatorsRect.adjusted(
|
}
|
||||||
0,
|
|
||||||
cw+indicatorSize/2,
|
|
||||||
-(indicatorsRect.width()-indicatorSize),
|
|
||||||
-(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
cw += painter->fontMetrics().height();
|
|
||||||
}
|
}
|
||||||
} else if (m_chartItem->itemMode() == DesignMode){
|
} else if (m_chartItem->itemMode() == DesignMode) {
|
||||||
qreal cw = 0;
|
for (int i = 0 ; i < m_designLabels.size() ; ++i){
|
||||||
for (int i=0;i<m_designLabels.size();++i){
|
if (isHorizontal) {
|
||||||
QString label = m_designLabels.at(i);
|
drawHorizontalLegendItem(painter, i, m_designLabels.at(i), indicatorSize, indicatorsRect, color_map[i]);
|
||||||
painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label);
|
} else {
|
||||||
painter->setBrush(color_map[i]);
|
drawVerticalLegendItem(painter, i, m_designLabels.at(i), indicatorSize, indicatorsRect, color_map[i]);
|
||||||
painter->drawEllipse(
|
}
|
||||||
indicatorsRect.adjusted(
|
|
||||||
0,
|
|
||||||
cw+indicatorSize/2,
|
|
||||||
-(indicatorsRect.width()-indicatorSize),
|
|
||||||
-(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2))
|
|
||||||
)
|
|
||||||
);
|
|
||||||
cw += painter->fontMetrics().height();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -1105,4 +1286,66 @@ QRectF AbstractBarChart::horizontalLabelsRect(QPainter *painter, QRectF labelsRe
|
|||||||
return labelsRect.adjusted(0, (labelsRect.height() - maxWidth), 0, 0);
|
return labelsRect.adjusted(0, (labelsRect.height() - maxWidth), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractBarChart::drawVerticalLegendItem(QPainter *painter, int i, const QString &text, int indicatorSize,
|
||||||
|
const QRectF &indicatorsRect, const QColor &indicatorColor)
|
||||||
|
{
|
||||||
|
const qreal y = i * painter->fontMetrics().height();
|
||||||
|
painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize * 1.5, y, 0, 0),text);
|
||||||
|
switch(m_chartItem->legendStyle()) {
|
||||||
|
case ChartItem::LegendPoints: {
|
||||||
|
painter->setBrush(indicatorColor);
|
||||||
|
painter->drawEllipse(
|
||||||
|
indicatorsRect.adjusted(
|
||||||
|
0,
|
||||||
|
y+indicatorSize/2,
|
||||||
|
-(indicatorsRect.width()-indicatorSize),
|
||||||
|
-(indicatorsRect.height()-(y+indicatorSize+indicatorSize/2))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ChartItem::LegendLines: {
|
||||||
|
const QPen tmpPen = painter->pen();
|
||||||
|
QPen indicatorPen(indicatorColor);
|
||||||
|
indicatorPen.setWidth(4);
|
||||||
|
painter->setPen(indicatorPen);
|
||||||
|
const QPointF linePos = QPointF(indicatorsRect.left(), indicatorsRect.top() + y + painter->fontMetrics().height()/2);
|
||||||
|
painter->drawLine(linePos, linePos + QPointF(indicatorSize, 0));
|
||||||
|
painter->setPen(tmpPen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractBarChart::drawHorizontalLegendItem(QPainter *painter, int i, const QString &text,
|
||||||
|
int indicatorSize, const QRectF &indicatorsRect, const QColor &indicatorColor)
|
||||||
|
{
|
||||||
|
const QVector<qreal> &columnWidths = legendColumnWidths();
|
||||||
|
if (columnWidths.isEmpty())
|
||||||
|
return;
|
||||||
|
const int column = i % columnWidths.size();
|
||||||
|
const int row = std::floor(i / columnWidths.size());
|
||||||
|
const qreal halfTextSize = painter->fontMetrics().height() / 2;
|
||||||
|
|
||||||
|
const qreal x = indicatorsRect.x() + std::accumulate(columnWidths.cbegin(), columnWidths.cbegin() + column, 0.0);
|
||||||
|
const qreal y = indicatorsRect.y() + (row + 1) * painter->fontMetrics().height();
|
||||||
|
painter->drawText(QPointF(x + indicatorSize * 1.5, y), text);
|
||||||
|
switch(m_chartItem->legendStyle()) {
|
||||||
|
case ChartItem::LegendPoints: {
|
||||||
|
painter->setBrush(indicatorColor);
|
||||||
|
painter->drawEllipse(x, y - halfTextSize, indicatorSize, indicatorSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ChartItem::LegendLines: {
|
||||||
|
const QPen tmpPen = painter->pen();
|
||||||
|
QPen indicatorPen(indicatorColor);
|
||||||
|
indicatorPen.setWidth(4);
|
||||||
|
painter->setPen(indicatorPen);
|
||||||
|
painter->drawLine(x, y - halfTextSize * 0.7, x + indicatorSize, y - halfTextSize * 0.7);
|
||||||
|
painter->setPen(tmpPen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace LimeReport
|
} // namespace LimeReport
|
||||||
|
@ -76,12 +76,13 @@ public:
|
|||||||
virtual ~AbstractChart(){}
|
virtual ~AbstractChart(){}
|
||||||
virtual void paintChart(QPainter *painter, QRectF rect) = 0;
|
virtual void paintChart(QPainter *painter, QRectF rect) = 0;
|
||||||
virtual void paintChartLegend(QPainter *painter, QRectF legendRect) =0;
|
virtual void paintChartLegend(QPainter *painter, QRectF legendRect) =0;
|
||||||
virtual QSizeF calcChartLegendSize(const QFont &font) = 0;
|
virtual QSizeF calcChartLegendSize(const QFont &font, qreal maxWidth = 0) = 0;
|
||||||
virtual QRectF calcChartLegendRect(const QFont& font, const QRectF& parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset);
|
virtual QRectF calcChartLegendRect(const QFont& font, const QRectF& parentRect, bool takeAllRect, qreal borderMargin, qreal titleOffset);
|
||||||
|
|
||||||
QFont titleFont();
|
QFont titleFont();
|
||||||
void setTitleFont(const QFont &value);
|
void setTitleFont(const QFont &value);
|
||||||
protected:
|
protected:
|
||||||
|
QVector<qreal> legendColumnWidths() const;
|
||||||
virtual void prepareLegendToPaint(QRectF& legendRect, QPainter *painter);
|
virtual void prepareLegendToPaint(QRectF& legendRect, QPainter *painter);
|
||||||
protected:
|
protected:
|
||||||
// Title font must be placed here instead of CharItem, becuase
|
// Title font must be placed here instead of CharItem, becuase
|
||||||
@ -89,6 +90,7 @@ protected:
|
|||||||
QFont m_titleFont;
|
QFont m_titleFont;
|
||||||
ChartItem* m_chartItem;
|
ChartItem* m_chartItem;
|
||||||
QList<QString> m_designLabels;
|
QList<QString> m_designLabels;
|
||||||
|
QVector<qreal> m_legendColumnWidths;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AbstractSeriesChart: public AbstractChart{
|
class AbstractSeriesChart: public AbstractChart{
|
||||||
@ -103,7 +105,7 @@ protected:
|
|||||||
int valuesCount();
|
int valuesCount();
|
||||||
int seriesCount();
|
int seriesCount();
|
||||||
bool verticalLabels(QPainter* painter, QRectF labelsRect);
|
bool verticalLabels(QPainter* painter, QRectF labelsRect);
|
||||||
QSizeF calcChartLegendSize(const QFont &font);
|
QSizeF calcChartLegendSize(const QFont &font, qreal maxWidth);
|
||||||
qreal* designValues(){ return m_designValues;}
|
qreal* designValues(){ return m_designValues;}
|
||||||
virtual qreal hPadding(QRectF chartRect);
|
virtual qreal hPadding(QRectF chartRect);
|
||||||
virtual qreal vPadding(QRectF chartRect);
|
virtual qreal vPadding(QRectF chartRect);
|
||||||
@ -120,6 +122,9 @@ protected:
|
|||||||
virtual QString axisLabel(int i, const AxisData &axisData);
|
virtual QString axisLabel(int i, const AxisData &axisData);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool calculateLegendColumnWidths(qreal indicatorWidth, qreal maxWidth, const QFontMetrics &fm);
|
||||||
|
bool calculateLegendSingleColumnWidth(qreal ¤tRowWidth, int ¤tColumn, int &maxColumnCount,
|
||||||
|
const qreal itemWidth, const qreal maxRowWidth);
|
||||||
AxisData m_yAxisData, m_xAxisData;
|
AxisData m_yAxisData, m_xAxisData;
|
||||||
qreal m_designValues [9];
|
qreal m_designValues [9];
|
||||||
};
|
};
|
||||||
@ -131,6 +136,11 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
QRectF verticalLabelsRect(QPainter* painter, QRectF horizontalLabelsRect);
|
QRectF verticalLabelsRect(QPainter* painter, QRectF horizontalLabelsRect);
|
||||||
virtual QRectF horizontalLabelsRect(QPainter* painter, QRectF horizontalLabelsRect);
|
virtual QRectF horizontalLabelsRect(QPainter* painter, QRectF horizontalLabelsRect);
|
||||||
|
private:
|
||||||
|
void drawVerticalLegendItem(QPainter *painter, int i, const QString &text,
|
||||||
|
int indicatorSize, const QRectF &indicatorsRect, const QColor &indicatorColor);
|
||||||
|
void drawHorizontalLegendItem(QPainter *painter, int i, const QString &text,
|
||||||
|
int indicatorSize, const QRectF &indicatorsRect, const QColor &indicatorColor);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ChartItem : public LimeReport::ItemDesignIntf
|
class ChartItem : public LimeReport::ItemDesignIntf
|
||||||
@ -141,6 +151,7 @@ class ChartItem : public LimeReport::ItemDesignIntf
|
|||||||
Q_PROPERTY(QString chartTitle READ chartTitle WRITE setChartTitle)
|
Q_PROPERTY(QString chartTitle READ chartTitle WRITE setChartTitle)
|
||||||
Q_PROPERTY(bool drawLegendBorder READ drawLegendBorder WRITE setDrawLegendBorder)
|
Q_PROPERTY(bool drawLegendBorder READ drawLegendBorder WRITE setDrawLegendBorder)
|
||||||
Q_PROPERTY(LegendAlign legendAlign READ legendAlign WRITE setLegendAlign)
|
Q_PROPERTY(LegendAlign legendAlign READ legendAlign WRITE setLegendAlign)
|
||||||
|
Q_PROPERTY(LegendStyle legendStyle READ legendStyle WRITE setLegendStyle)
|
||||||
Q_PROPERTY(TitleAlign titleAlign READ titleAlign WRITE setTitleAlign)
|
Q_PROPERTY(TitleAlign titleAlign READ titleAlign WRITE setTitleAlign)
|
||||||
Q_PROPERTY(ChartType chartType READ chartType WRITE setChartType)
|
Q_PROPERTY(ChartType chartType READ chartType WRITE setChartType)
|
||||||
Q_PROPERTY(QString labelsField READ labelsField WRITE setLabelsField)
|
Q_PROPERTY(QString labelsField READ labelsField WRITE setLabelsField)
|
||||||
@ -160,7 +171,8 @@ class ChartItem : public LimeReport::ItemDesignIntf
|
|||||||
friend class AbstractChart;
|
friend class AbstractChart;
|
||||||
public:
|
public:
|
||||||
|
|
||||||
enum LegendAlign{LegendAlignTop,LegendAlignCenter,LegendAlignBottom};
|
enum LegendAlign{LegendAlignRightTop,LegendAlignRightCenter,LegendAlignRightBottom,
|
||||||
|
LegendAlignBottomLeft,LegendAlignBottomCenter,LegendAlignBottomRight};
|
||||||
enum LegendStyle{LegendPoints, LegendLines};
|
enum LegendStyle{LegendPoints, LegendLines};
|
||||||
enum TitleAlign{TitleAlignLeft, TitleAlignCenter, TitleAlignRight};
|
enum TitleAlign{TitleAlignLeft, TitleAlignCenter, TitleAlignRight};
|
||||||
enum ChartType{Pie, VerticalBar, HorizontalBar, Lines, GridLines};
|
enum ChartType{Pie, VerticalBar, HorizontalBar, Lines, GridLines};
|
||||||
@ -172,11 +184,13 @@ public:
|
|||||||
};
|
};
|
||||||
#if QT_VERSION >= 0x050500
|
#if QT_VERSION >= 0x050500
|
||||||
Q_ENUM(LegendAlign)
|
Q_ENUM(LegendAlign)
|
||||||
|
Q_ENUM(LegendStyle)
|
||||||
Q_ENUM(TitleAlign)
|
Q_ENUM(TitleAlign)
|
||||||
Q_ENUM(ChartType)
|
Q_ENUM(ChartType)
|
||||||
Q_ENUM(LineType)
|
Q_ENUM(LineType)
|
||||||
#else
|
#else
|
||||||
Q_ENUMS(LegendAlign)
|
Q_ENUMS(LegendAlign)
|
||||||
|
Q_ENUMS(LegendStyle)
|
||||||
Q_ENUMS(TitleAlign)
|
Q_ENUMS(TitleAlign)
|
||||||
Q_ENUMS(ChartType)
|
Q_ENUMS(ChartType)
|
||||||
Q_ENUMS(LineType)
|
Q_ENUMS(LineType)
|
||||||
@ -203,6 +217,9 @@ public:
|
|||||||
LegendAlign legendAlign() const;
|
LegendAlign legendAlign() const;
|
||||||
void setLegendAlign(const LegendAlign &legendAlign);
|
void setLegendAlign(const LegendAlign &legendAlign);
|
||||||
|
|
||||||
|
LegendStyle legendStyle() const;
|
||||||
|
void setLegendStyle(const LegendStyle &legendStyle);
|
||||||
|
|
||||||
TitleAlign titleAlign() const;
|
TitleAlign titleAlign() const;
|
||||||
void setTitleAlign(const TitleAlign &titleAlign);
|
void setTitleAlign(const TitleAlign &titleAlign);
|
||||||
|
|
||||||
@ -269,6 +286,7 @@ private:
|
|||||||
QString m_xAxisField;
|
QString m_xAxisField;
|
||||||
bool m_horizontalAxisOnTop;
|
bool m_horizontalAxisOnTop;
|
||||||
GridChartLines m_gridChartLines;
|
GridChartLines m_gridChartLines;
|
||||||
|
LegendStyle m_legendStyle;
|
||||||
};
|
};
|
||||||
} //namespace LimeReport
|
} //namespace LimeReport
|
||||||
#endif // LRCHARTITEM_H
|
#endif // LRCHARTITEM_H
|
||||||
|
Loading…
Reference in New Issue
Block a user