#include "lrchartitem.h" #include #include #include "lrdesignelementsfactory.h" #include "lrchartitemeditor.h" #include "lrdatasourcemanager.h" #include "lrpagedesignintf.h" #include "lrreportengine_p.h" #include "lrdatadesignintf.h" namespace{ const QString xmlTag = "ChartItem"; LimeReport::BaseDesignIntf * createChartItem(QObject* owner, LimeReport::BaseDesignIntf* parent){ return new LimeReport::ChartItem(owner,parent); } bool registred = LimeReport::DesignElementsFactory::instance().registerCreator( xmlTag, LimeReport::ItemAttribs(QObject::tr("Chart Item"),"Item"), createChartItem ); } namespace LimeReport{ QColor generateColor() { int red = (qrand()%(256 - 1)) + 1; int green = (qrand()%(256 - 1)) + 1; int blue = (qrand()%(256 - 1)) + 1;; return QColor(red,green,blue); } QColor color_map[39] = { QColor(51,102,204), QColor(220,57,18), QColor(225, 153, 0), QColor(16, 150, 24), QColor(153,0,153), QColor(0,153,198), QColor(221, 68, 119), QColor(255,0,0), QColor(0,0,139), QColor(0,205,0), QColor(233,30,99), QColor(255,255,0), QColor(244,67,54), QColor(156,39,176), QColor(103,58,183), QColor(63,81,181), QColor(33,153,243), QColor(0,150,136), QColor(78,175,80), QColor(139,195,74), QColor(205,228,57), QColor(0,139,0), QColor(0,0,255), QColor(255,235,59), QColor(255,193,7), QColor(255,152,0), QColor(255,87,34), QColor(121,85,72), QColor(158,158,158), QColor(96,125,139), QColor(241,153,185), QColor(64,64,64), QColor(188,229,218), QColor(139,0,0), QColor(139,139,0), QColor(171, 130, 255), QColor(139, 123, 139), QColor(255, 0, 255), QColor(139, 69, 19) }; QString SeriesItem::name() const { return m_name; } void SeriesItem::setName(const QString &name) { m_name = name; } QString SeriesItem::valuesColumn() const { return m_valuesColumn; } void SeriesItem::setValuesColumn(const QString &valuesColumn) { m_valuesColumn = valuesColumn; } QString SeriesItem::labelsColumn() const { return m_labelsColumn; } void SeriesItem::setLabelsColumn(const QString &labelsColumn) { m_labelsColumn = labelsColumn; } SeriesItem *SeriesItem::clone() { SeriesItem* result = new SeriesItem(); for (int i = 0; i < this->metaObject()->propertyCount(); ++i){ result->setProperty(this->metaObject()->property(i).name(),property(this->metaObject()->property(i).name())); } return result; } void SeriesItem::fillSeriesData(IDataSource *dataSource) { if (dataSource){ dataSource->first(); int currentColorIndex = 0; while(!dataSource->eof()){ if (!m_labelsColumn.isEmpty()) m_data.labels().append(dataSource->data(m_labelsColumn).toString()); m_data.values().append(dataSource->data(m_valuesColumn).toDouble()); m_data.colors().append((currentColorIndex<32)?color_map[currentColorIndex]:generateColor()); dataSource->next(); currentColorIndex++; } } } QColor SeriesItem::color() const { return m_color; } void SeriesItem::setColor(const QColor &color) { m_color = color; } SeriesItem::SeriesItemPreferredType SeriesItem::preferredType() const { return m_preferredType; } void SeriesItem::setPreferredType(const SeriesItemPreferredType& type) { m_preferredType = type; } ChartItem::ChartItem(QObject *owner, QGraphicsItem *parent) : ItemDesignIntf(xmlTag, owner, parent), m_legendBorder(true), m_legendAlign(LegendAlignCenter), m_titleAlign(TitleAlignCenter), m_chartType(Pie), m_labelsField("") { m_labels<<"First"<<"Second"<<"Thrid"; m_chart = new PieChart(this); } ChartItem::~ChartItem() { foreach (SeriesItem* series, m_series) { delete series; } m_series.clear(); delete m_chart; } ChartItem::TitleAlign ChartItem::titleAlign() const { return m_titleAlign; } void ChartItem::setTitleAlign(const TitleAlign &titleAlign) { if (m_titleAlign != titleAlign){ TitleAlign oldValue = m_titleAlign; m_titleAlign = titleAlign; notify("titleAlign",oldValue,m_titleAlign); update(); } } void ChartItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { painter->save(); setupPainter(painter); painter->setFont(transformToSceneFont(painter->font())); painter->setRenderHint(QPainter::Antialiasing,true); painter->setRenderHint(QPainter::TextAntialiasing,true); qreal borderMargin = (rect().height()*0.01>10)?(10):(rect().height()*0.01); qreal maxTitleHeight = rect().height()*0.2; QFont tmpFont = painter->font(); qreal titleOffset = !m_title.isEmpty()?(((painter->fontMetrics().height()+borderMargin*2)fontMetrics().height()+borderMargin*2): (maxTitleHeight)):0; QRectF titleRect = QRectF(borderMargin,borderMargin,rect().width()-borderMargin*2,titleOffset); QRectF legendRect = m_chart->calcChartLegendRect(painter->font(), rect(), false, borderMargin, titleOffset); QRectF diagramRect = rect().adjusted(borderMargin,titleOffset+borderMargin, -(legendRect.width()+borderMargin*2),-borderMargin); paintChartTitle(painter, titleRect); m_chart->paintChartLegend(painter,legendRect); m_chart->paintChart(painter,diagramRect); painter->restore(); ItemDesignIntf::paint(painter,option,widget); } BaseDesignIntf *ChartItem::createSameTypeItem(QObject *owner, QGraphicsItem *parent) { ChartItem* result = new ChartItem(owner,parent); foreach (SeriesItem* series, m_series) { result->m_series.append(series->clone()); } return result; } QObject *ChartItem::createElement(const QString &collectionName, const QString &elementType) { Q_UNUSED(elementType); if (collectionName.compare("series")==0){ SeriesItem* seriesItem = new SeriesItem(); m_series.append(seriesItem); return seriesItem; } return 0; } int ChartItem::elementsCount(const QString &collectionName) { if (collectionName.compare("series")==0) return m_series.count(); return 0; } QObject *ChartItem::elementAt(const QString &collectionName, int index) { if (collectionName.compare("series")==0) return m_series.at(index); return 0; } void ChartItem::updateItemSize(DataSourceManager *dataManager, RenderPass , int ) { if (dataManager && dataManager->dataSource(m_datasource)){ IDataSource* ds = dataManager->dataSource(m_datasource); foreach (SeriesItem* series, m_series) { series->setLabelsColumn(m_labelsField); series->fillSeriesData(ds); } fillLabels(ds); } } void ChartItem::fillLabels(IDataSource *dataSource) { m_labels.clear(); if (dataSource && !m_labelsField.isEmpty()){ dataSource->first(); while(!dataSource->eof()){ m_labels.append(dataSource->data(m_labelsField).toString()); dataSource->next(); } } } QWidget *ChartItem::defaultEditor() { QSettings* l_settings = (page()->settings() != 0) ? page()->settings() : (page()->reportEditor()!=0) ? page()->reportEditor()->settings() : 0; QWidget* editor = new ChartItemEditor(this,page(),l_settings); editor->setAttribute(Qt::WA_DeleteOnClose); return editor; } QList ChartItem::labels() const { return m_labels; } void ChartItem::setLabels(const QList &labels) { m_labels = labels; } QString ChartItem::labelsField() const { return m_labelsField; } void ChartItem::setLabelsField(const QString &labelsField) { m_labelsField = labelsField; } ChartItem::ChartType ChartItem::chartType() const { return m_chartType; } void ChartItem::setChartType(const ChartType &chartType) { if (m_chartType != chartType){ ChartType oldValue = m_chartType; m_chartType = chartType; delete m_chart; switch (m_chartType) { case Pie: m_chart = new PieChart(this); break; case VerticalBar: m_chart = new VerticalBarChart(this); break; case HorizontalBar: m_chart = new HorizontalBarChart(this); break; } notify("chartType",oldValue,m_chartType); update(); } } QString ChartItem::datasource() const { return m_datasource; } void ChartItem::setDatasource(const QString &datasource) { m_datasource = datasource; } void ChartItem::paintChartTitle(QPainter *painter, QRectF titleRect) { painter->save(); QFont tmpFont = painter->font(); QFontMetrics fm(tmpFont); while ((fm.height()>titleRect.height() || fm.width(m_title)>titleRect.width()) && tmpFont.pixelSize()>1) { tmpFont.setPixelSize(tmpFont.pixelSize()-1); fm = QFontMetrics(tmpFont); } painter->setFont(tmpFont); Qt::AlignmentFlag align = Qt::AlignCenter; switch (m_titleAlign) { case TitleAlignLeft: align = Qt::AlignLeft; break; case TitleAlignCenter: align = Qt::AlignCenter; break; case TitleAlignRight: align = Qt::AlignRight; break; } painter->drawText(titleRect, align, m_title); painter->restore(); } ChartItem::LegendAlign ChartItem::legendAlign() const { return m_legendAlign; } void ChartItem::setLegendAlign(const LegendAlign &legendAlign) { if (m_legendAlign != legendAlign){ LegendAlign oldValue = m_legendAlign; m_legendAlign = legendAlign; notify("legendAlign",oldValue,m_legendAlign); update(); } } bool ChartItem::drawLegendBorder() const { return m_legendBorder; } void ChartItem::setDrawLegendBorder(bool legendBorder) { if (m_legendBorder!=legendBorder){ m_legendBorder = legendBorder; notify("legendBorder",!m_legendBorder,m_legendBorder); update(); } } QString ChartItem::chartTitle() const { return m_title; } void ChartItem::setChartTitle(const QString &title) { if (m_title != title){ QString oldValue = m_title; m_title = title; update(); notify("chartTitle",oldValue,title); } } QList &ChartItem::series() { return m_series; } void ChartItem::setSeries(const QList &series) { m_series = series; } bool ChartItem::isSeriesExists(const QString &name) { foreach (SeriesItem* series, m_series) { if (series->name().compare(name)==0) return true; } return false; } AbstractChart::AbstractChart(ChartItem *chartItem) :m_chartItem(chartItem) { m_designLabels<legendAlign()) { case ChartItem::LegendAlignTop: legendTopMargin = titleOffset+borderMargin; legendBottomMargin = parentRect.height()-(legendSize.height()+titleOffset); break; case ChartItem::LegendAlignCenter: legendTopMargin = titleOffset+(parentRect.height()-titleOffset-legendSize.height())/2; legendBottomMargin = (parentRect.height()-titleOffset-legendSize.height())/2; break; case ChartItem::LegendAlignBottom: legendTopMargin = parentRect.height()-(legendSize.height()+titleOffset); legendBottomMargin = borderMargin; break; } qreal rightOffset = !takeAllRect?((legendSize.width()>parentRect.width()/2-borderMargin)? (parentRect.width()/2): (parentRect.width()-legendSize.width())):0; QRectF legendRect = parentRect.adjusted( rightOffset, (legendSize.height()>(parentRect.height()-titleOffset))?(titleOffset):(legendTopMargin), -borderMargin, (legendSize.height()>(parentRect.height()-titleOffset))?(0):(-legendBottomMargin) ); return legendRect; } void AbstractChart::prepareLegendToPaint(QRectF &legendRect, QPainter *painter) { QFont tmpFont = painter->font(); QSizeF legendSize = calcChartLegendSize(tmpFont); if ((legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width())){ while ( (legendSize.height()>legendRect.height() || legendSize.width()>legendRect.width()) && tmpFont.pixelSize()>1) { tmpFont.setPixelSize(tmpFont.pixelSize()-1); painter->setFont(tmpFont); legendSize = calcChartLegendSize(tmpFont); } painter->setFont(tmpFont); legendRect = calcChartLegendRect(tmpFont, legendRect, true, 0, 0); } } void PieChart::drawPercent(QPainter *painter, QRectF chartRect, qreal startAngle, qreal angle) { painter->save(); QPointF center(chartRect.left()+chartRect.width()/2,chartRect.top()+chartRect.height()/2); qreal percent = angle/3.6; qreal radAngle = qDegreesToRadians(angle/2+startAngle); qreal radius = painter->fontMetrics().width("99,9%"); qreal border = chartRect.height()*0.02; qreal length = (chartRect.height())/2-(radius/2+border); qreal x,y; x = length*qCos(radAngle); y = length*qSin(radAngle); QPointF endPoint(center.x()+x,center.y()-y); painter->setPen(Qt::white); QRectF textRect(endPoint.x()-(radius/2),endPoint.y()-(radius/2),radius,radius); qreal arcLength = 3.14 * length * angle / 180; if (arcLength >= radius) painter->drawText(textRect,Qt::AlignCenter,QString::number(percent,'f',1)+"%"); painter->restore(); } void PieChart::paintChart(QPainter *painter, QRectF chartRect) { painter->save(); QPen pen(Qt::white); pen.setWidthF(2); painter->setPen(pen); QBrush brush(Qt::transparent); painter->setBrush(brush); painter->setBackground(QBrush(Qt::NoBrush)); QRectF tmpRect = chartRect; if (chartRect.height()>chartRect.width()){ tmpRect.setHeight(chartRect.width()); tmpRect.adjust(0,(chartRect.bottom()-tmpRect.bottom())/2, 0,(chartRect.bottom()-tmpRect.bottom())/2); } else { tmpRect.setWidth(chartRect.height()); } chartRect = tmpRect; painter->drawRect(chartRect); if (!m_chartItem->series().isEmpty()&&!m_chartItem->series().at(0)->data()->values().isEmpty()){ SeriesItem* si = m_chartItem->series().at(0); qreal sum = 0; foreach(qreal value, si->data()->values()){ sum+=value; } qreal onePercent = sum / 100; qreal currentDegree = 0; int currentColor = 0; for(int i=0; idata()->values().count();++i){ qreal value = si->data()->values().at(i); qreal sectorDegree = (value/onePercent)*3.6; painter->setBrush(si->data()->colors().at(i)); painter->drawPie(chartRect,currentDegree*16,sectorDegree*16); drawPercent(painter, chartRect, currentDegree, sectorDegree); currentDegree += sectorDegree; currentColor++; } } else { painter->setBrush(color_map[0]); painter->drawPie(chartRect,0,260*16); drawPercent(painter, chartRect, 0, 260); painter->setBrush(color_map[1]); painter->drawPie(chartRect,260*16,40*16); drawPercent(painter, chartRect, 260, 40); painter->setBrush(color_map[2]); painter->drawPie(chartRect,300*16,60*16); drawPercent(painter, chartRect, 300, 60); } pen.setWidthF(1); pen.setColor(Qt::gray); painter->setPen(pen); painter->setBrush(Qt::NoBrush); painter->drawEllipse(chartRect); painter->restore(); } void PieChart::paintChartLegend(QPainter *painter, QRectF legendRect) { prepareLegendToPaint(legendRect, painter); int indicatorSize = painter->fontMetrics().height()/2; painter->setRenderHint(QPainter::Antialiasing,false); if (m_chartItem->drawLegendBorder()) painter->drawRect(legendRect); painter->setRenderHint(QPainter::Antialiasing,true); QRectF indicatorsRect = legendRect.adjusted(painter->fontMetrics().height()/2,painter->fontMetrics().height()/2,0,0); if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ qreal cw = 0; SeriesItem* si = m_chartItem->series().at(0); for (int i=0;idata()->labels().count();++i){ QString label = si->data()->labels().at(i); painter->setPen(Qt::black); painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); painter->setPen(si->data()->colors().at(i)); painter->setBrush(si->data()->colors().at(i)); painter->drawEllipse( indicatorsRect.adjusted( 0, cw+indicatorSize/2, -(indicatorsRect.width()-indicatorSize), -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) ) ); cw += painter->fontMetrics().height(); } } else { qreal cw = 0; for (int i=0;isetPen(Qt::black); painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); painter->setBrush(color_map[i]); painter->setPen(color_map[i]); painter->drawEllipse( indicatorsRect.adjusted( 0, cw+indicatorSize/2, -(indicatorsRect.width()-indicatorSize), -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) ) ); cw += painter->fontMetrics().height(); } } } QSizeF PieChart::calcChartLegendSize(const QFont &font) { QFontMetrics fm(font); qreal cw = 0; qreal maxWidth = 0; if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ SeriesItem* si = m_chartItem->series().at(0); foreach(QString label, si->data()->labels()){ cw += fm.height(); if (maxWidthfontMetrics().width(QString::number(delta))+4; } qreal VerticalBarChart::valuesVMargin(QPainter *painter) { return painter->fontMetrics().height(); } QRectF VerticalBarChart::labelsRect(QPainter *painter, QRectF labelsRect) { qreal maxWidth = 0; foreach (QString label, m_chartItem->labels()) { if (painter->fontMetrics().width(label)>maxWidth) maxWidth = painter->fontMetrics().width(label); } if (maxWidth+vPadding(m_chartItem->rect())> labelsRect.height()) return labelsRect; else return labelsRect.adjusted(0,(labelsRect.height()-(maxWidth+vPadding(m_chartItem->rect()))),0,0); } void VerticalBarChart::paintChart(QPainter *painter, QRectF chartRect) { QRectF calcRect = labelsRect(painter, chartRect.adjusted( hPadding(chartRect)*2+valuesHMargin(painter), chartRect.height()*0.5, -(hPadding(chartRect)*2), -vPadding(chartRect) )); qreal barsShift = calcRect.height(); paintVerticalGrid(painter, chartRect.adjusted( hPadding(chartRect), vPadding(chartRect)+valuesVMargin(painter), -hPadding(chartRect),-(vPadding(chartRect)+barsShift) )); paintVerticalBars(painter, chartRect.adjusted( hPadding(chartRect)*2+valuesHMargin(painter), vPadding(chartRect)+valuesVMargin(painter), -(hPadding(chartRect)*2), -(vPadding(chartRect)+barsShift) )); paintSerialLines(painter, chartRect.adjusted( hPadding(chartRect)*2+valuesHMargin(painter), vPadding(chartRect)+valuesVMargin(painter), -(hPadding(chartRect)*2), -(vPadding(chartRect)+barsShift) )); paintLabels(painter,calcRect); } void VerticalBarChart::paintVerticalGrid(QPainter *painter, QRectF gridRect) { int delta = int(maxValue()-minValue()); delta = genNextValue(delta); painter->setRenderHint(QPainter::Antialiasing,false); qreal vStep = gridRect.height() / 4; for (int i=0;i<5;i++){ painter->drawText(QRectF(gridRect.bottomLeft()-QPointF(0,vStep*i+painter->fontMetrics().height()), QSizeF(valuesHMargin(painter),painter->fontMetrics().height())), QString::number(minValue()+i*delta/4)); painter->drawLine(gridRect.bottomLeft()-QPointF(-valuesHMargin(painter),vStep*i), gridRect.bottomRight()-QPointF(0,vStep*i)); } painter->setRenderHint(QPainter::Antialiasing,true); } void VerticalBarChart::paintVerticalBars(QPainter *painter, QRectF barsRect) { int delta = int(maxValue()-minValue()); delta = genNextValue(delta); int barSeriesCount = 0; foreach(SeriesItem* series, m_chartItem->series()){ if (series->preferredType() == SeriesItem::Bar) barSeriesCount++; } barSeriesCount = (m_chartItem->itemMode()==DesignMode) ? seriesCount() : barSeriesCount; painter->save(); painter->setRenderHint(QPainter::Antialiasing,false); qreal vStep = barsRect.height() / delta; qreal hStep = (barsRect.width() / valuesCount()) / (barSeriesCount == 0 ? 1 : barSeriesCount); qreal topShift = (delta - (maxValue()-minValue())) * vStep +barsRect.top(); if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ int curSeries = 0; foreach (SeriesItem* series, m_chartItem->series()) { if (series->preferredType() == SeriesItem::Bar){ qreal curHOffset = curSeries*hStep+barsRect.left(); painter->setBrush(series->color()); foreach (qreal value, series->data()->values()) { painter->drawRect(QRectF(curHOffset, maxValue()*vStep+topShift, hStep, -value*vStep)); curHOffset+=hStep*barSeriesCount; } curSeries++; } } } else { qreal curHOffset = barsRect.left(); int curColor = 0; for (int i=0; i<9; ++i){ if (curColor==3) curColor=0; painter->setBrush(color_map[curColor]); painter->drawRect(QRectF(curHOffset, maxValue()*vStep+barsRect.top(), hStep, -designValues()[i]*vStep)); curHOffset+=hStep; curColor++; } } painter->restore(); } void VerticalBarChart::paintSerialLines(QPainter* painter, QRectF barsRect) { painter->save(); painter->setRenderHint(QPainter::Antialiasing,true); int delta = int(maxValue()-minValue()); delta = genNextValue(delta); qreal vStep = barsRect.height() / delta; qreal hStep = (barsRect.width() / valuesCount()); qreal topShift = (delta - (maxValue()-minValue())) * vStep +barsRect.top(); if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ int curSeries = 0; foreach (SeriesItem* series, m_chartItem->series()) { if (series->preferredType() == SeriesItem::Line){ QPen pen(series->color()); pen.setWidth(4); painter->setPen(pen); for (int i = 0; i < series->data()->values().count()-1; ++i ){ QPoint startPoint = QPoint((i+1)*hStep + barsRect.left()-hStep/2, (maxValue()*vStep+topShift) - series->data()->values().at(i)*vStep ); QPoint endPoint = QPoint((i+2)*hStep + barsRect.left()-hStep/2, (maxValue()*vStep+topShift) - series->data()->values().at(i+1)*vStep ); painter->drawLine(startPoint, endPoint); QRect startPointRect(startPoint,startPoint); QRect endPointRect(endPoint,endPoint); int radius = 4; painter->setBrush(series->color()); painter->drawEllipse(startPointRect.adjusted(radius,radius,-radius,-radius)); painter->drawEllipse(endPointRect.adjusted(radius,radius,-radius,-radius)); } } curSeries++; } } painter->restore(); } void VerticalBarChart::paintLabels(QPainter *painter, QRectF labelsRect) { painter->save(); qreal hStep = (labelsRect.width() / valuesCount()); int curLabel = 0; if (!m_chartItem->labels().isEmpty()){ painter->rotate(270); painter->translate(-(labelsRect.top()+labelsRect.height()),labelsRect.left()); foreach (QString label, m_chartItem->labels()) { painter->drawText(QRectF(QPoint(0,0), QSize(labelsRect.height()-4,hStep)),Qt::AlignVCenter|Qt::AlignRight,label); curLabel++; painter->translate(0,hStep); } painter->rotate(-270); } painter->restore(); } AbstractSeriesChart::AbstractSeriesChart(ChartItem *chartItem) :AbstractChart(chartItem) { m_designValues[0] = 10; m_designValues[1] = 35; m_designValues[2] = 15; m_designValues[3] = 5; m_designValues[4] = 20; m_designValues[5] = 10; m_designValues[6] = 40; m_designValues[7] = 20; m_designValues[8] = 5; } qreal AbstractSeriesChart::maxValue() { if (m_chartItem->itemMode()==DesignMode) return 40; qreal maxValue = 0; foreach(SeriesItem* series, m_chartItem->series()){ foreach(qreal value, series->data()->values()){ if (value>maxValue) maxValue=value; } } return maxValue; } qreal AbstractSeriesChart::minValue() { if (m_chartItem->itemMode()==DesignMode) return 0; qreal minValue = 0; foreach(SeriesItem* series, m_chartItem->series()){ foreach(qreal value, series->data()->values()){ if (valueitemMode()==DesignMode) return 3; return (m_chartItem->series().isEmpty())?(0):(m_chartItem->series().at(0)->data()->labels().count()); } int AbstractSeriesChart::seriesCount() { if (m_chartItem->itemMode()==DesignMode) return 3; return m_chartItem->series().count(); } QSizeF AbstractSeriesChart::calcChartLegendSize(const QFont &font) { QFontMetrics fm(font); qreal cw = 0; qreal maxWidth = 0; if (!m_chartItem->series().isEmpty()){ foreach(SeriesItem* series, m_chartItem->series()){ cw += fm.height(); if (maxWidthname())) maxWidth = fm.width(series->name())+10; } } else { foreach(QString label, m_designLabels){ cw += fm.height(); if (maxWidthfontMetrics().width(QString::number(delta))+4; } qreal HorizontalBarChart::valuesVMargin(QPainter *painter) { return painter->fontMetrics().height(); } void HorizontalBarChart::paintChart(QPainter *painter, QRectF chartRect) { QRectF calcRect = labelsRect(painter, chartRect.adjusted( hPadding(chartRect), vPadding(chartRect)*2, -(chartRect.width()*0.5), -(vPadding(chartRect)*2+valuesVMargin(painter)) )); qreal barsShift = calcRect.width(); paintHorizontalGrid(painter, chartRect.adjusted( hPadding(chartRect)+barsShift, vPadding(chartRect), -(hPadding(chartRect)),-vPadding(chartRect))); paintHorizontalBars(painter, chartRect.adjusted( hPadding(chartRect)+barsShift, vPadding(chartRect)*2, -(hPadding(chartRect)), -(vPadding(chartRect)*2) )); paintLabels(painter,calcRect); } void HorizontalBarChart::paintHorizontalGrid(QPainter *painter, QRectF gridRect) { painter->save(); int delta = int(maxValue()-minValue()); delta = genNextValue(delta); painter->setRenderHint(QPainter::Antialiasing,false); qreal hStep = (gridRect.width()-painter->fontMetrics().width(QString::number(maxValue()))) / 4; painter->setFont(adaptValuesFont(hStep-4,painter->font())); for (int i=0;i<5;i++){ painter->drawText(QRectF(gridRect.left()+4+hStep*i,gridRect.bottom()-painter->fontMetrics().height(), hStep,painter->fontMetrics().height()), QString::number(minValue()+i*delta/4)); painter->drawLine( gridRect.left()+hStep*i, gridRect.bottom(), gridRect.left()+hStep*i, gridRect.top()); } painter->restore(); } void HorizontalBarChart::paintHorizontalBars(QPainter *painter, QRectF barsRect) { painter->save(); painter->setRenderHint(QPainter::Antialiasing,false); int delta = int(maxValue()-minValue()); delta = genNextValue(delta); qreal vStep = (barsRect.height()-painter->fontMetrics().height()) / valuesCount() / seriesCount(); qreal hStep = (barsRect.width()-painter->fontMetrics().width(QString::number(maxValue()))) / delta; if (!m_chartItem->series().isEmpty() && !m_chartItem->series().at(0)->data()->labels().isEmpty()){ int curSeries = 0; foreach (SeriesItem* series, m_chartItem->series()) { qreal curVOffset = curSeries*vStep+barsRect.top(); painter->setBrush(series->color()); foreach (qreal value, series->data()->values()) { painter->drawRect(QRectF((-minValue()*hStep)+barsRect.left(), curVOffset, value*hStep, vStep)); curVOffset+=vStep*seriesCount(); } curSeries++; } } else { qreal curVOffset = barsRect.top(); int curColor = 0; for (int i=0; i<9; ++i){ if (curColor==3) curColor=0; painter->setBrush(color_map[curColor]); painter->drawRect(QRectF(barsRect.left(), curVOffset, designValues()[i]*hStep, vStep)); curVOffset+=vStep; curColor++; } } painter->restore(); } QRectF HorizontalBarChart::labelsRect(QPainter *painter, QRectF labelsRect) { qreal maxWidth = 0; foreach (QString label, m_chartItem->labels()) { if (painter->fontMetrics().width(label)>maxWidth) maxWidth = painter->fontMetrics().width(label); } if (maxWidth+hPadding(m_chartItem->rect())*2> labelsRect.width()) return labelsRect; else return labelsRect.adjusted(0,0,-(labelsRect.width()-(maxWidth+hPadding(m_chartItem->rect())*2)),0); } QFont HorizontalBarChart::adaptLabelsFont(QRectF rect, QFont font) { QString maxWord; QFontMetrics fm(font); foreach(QString label, m_chartItem->labels()){ foreach (QString currentWord, label.split(QRegExp("\\W+"))){ if (fm.width(maxWord)rect.width() && tmpFont.pixelSize()>1){ tmpFont.setPixelSize(tmpFont.pixelSize()-1); QFontMetricsF tmpFM(tmpFont); curWidth = tmpFM.width(maxWord); } return tmpFont; } QFont HorizontalBarChart::adaptValuesFont(qreal width, QFont font) { QString strValue = QString::number(maxValue()); QFont tmpFont = font; QScopedPointer fm(new QFontMetricsF(tmpFont)); qreal curWidth = fm->width(strValue); while (curWidth>width && tmpFont.pixelSize()>1){ tmpFont.setPixelSize(tmpFont.pixelSize()-1); fm.reset(new QFontMetricsF(tmpFont)); curWidth = fm->width(strValue); } return tmpFont; } void HorizontalBarChart::paintLabels(QPainter *painter, QRectF labelsRect) { painter->save(); painter->setFont(adaptLabelsFont(labelsRect.adjusted(0,0,-hPadding(m_chartItem->rect()),0), painter->font())); qreal vStep = (labelsRect.height() / valuesCount()); int curLabel = 0; painter->translate(labelsRect.topLeft()); if (!m_chartItem->labels().isEmpty()){ foreach (QString label, m_chartItem->labels()) { painter->drawText(QRectF(QPoint(0,vStep*curLabel), QSize(labelsRect.width()-hPadding(m_chartItem->rect()),vStep)), Qt::AlignVCenter | Qt::AlignRight | Qt::TextWordWrap,label); curLabel++; } } painter->restore(); } qreal AbstractBarChart::hPadding(QRectF chartRect) { return (chartRect.width()*0.02); } qreal AbstractBarChart::vPadding(QRectF chartRect) { return (chartRect.height()*0.02); } void AbstractBarChart::paintChartLegend(QPainter *painter, QRectF legendRect) { prepareLegendToPaint(legendRect, painter); int indicatorSize = painter->fontMetrics().height()/2; painter->setPen(Qt::black); painter->setRenderHint(QPainter::Antialiasing,false); if (m_chartItem->drawLegendBorder()) painter->drawRect(legendRect); painter->setRenderHint(QPainter::Antialiasing,true); QRectF indicatorsRect = legendRect.adjusted(painter->fontMetrics().height()/2,painter->fontMetrics().height()/2,0,0); if (!m_chartItem->series().isEmpty()){ qreal cw = 0; foreach(SeriesItem* series, m_chartItem->series()){ QString label = series->name(); painter->drawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); painter->setBrush(series->color()); painter->drawEllipse( indicatorsRect.adjusted( 0, cw+indicatorSize/2, -(indicatorsRect.width()-indicatorSize), -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) ) ); cw += painter->fontMetrics().height(); } } else { qreal cw = 0; for (int i=0;idrawText(indicatorsRect.adjusted(indicatorSize+indicatorSize/2,cw,0,0),label); painter->setBrush(color_map[i]); painter->drawEllipse( indicatorsRect.adjusted( 0, cw+indicatorSize/2, -(indicatorsRect.width()-indicatorSize), -(indicatorsRect.height()-(cw+indicatorSize+indicatorSize/2)) ) ); cw += painter->fontMetrics().height(); } } } } // namespace LimeReport