PowerMaster/dataPanel/dpBarsChart.cpp

402 lines
14 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "dpBarsChart.h"
#include "dataManager.h"
CustomBars::CustomBars(QCPAxis* keyAxis, QCPAxis* valueAxis)
: QCPBars(keyAxis, valueAxis),
m_textVisible(false),
m_textAlignment(Qt::AlignCenter),
m_spacing(5),
m_font(QFont(QLatin1String("sans serif"), 12))
{}
void CustomBars::setTextVisible(bool visible)
{
m_textVisible = visible;
}
void CustomBars::setTextAlignment(Qt::Alignment alignment)
{
m_textAlignment = alignment;
}
void CustomBars::setSpacing(double spacing)
{
m_spacing = spacing;
}
void CustomBars::setFont(QFont font)
{
m_font = font;
}
void CustomBars::draw(QCPPainter* painter)
{
///源码拷贝
if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
if (mDataContainer->isEmpty()) return;
QCPBarsDataContainer::const_iterator visibleBegin, visibleEnd;
getVisibleDataBounds(visibleBegin, visibleEnd);
// loop over and draw segments of unselected/selected data:
QList<QCPDataRange> selectedSegments, unselectedSegments, allSegments;
getDataSegments(selectedSegments, unselectedSegments);
allSegments << unselectedSegments << selectedSegments;
for (int i=0; i<allSegments.size(); ++i)
{
bool isSelectedSegment = i >= unselectedSegments.size();
QCPBarsDataContainer::const_iterator begin = visibleBegin;
QCPBarsDataContainer::const_iterator end = visibleEnd;
mDataContainer->limitIteratorsToDataRange(begin, end, allSegments.at(i));
if (begin == end)
continue;
for (QCPBarsDataContainer::const_iterator it=begin; it!=end; ++it)
{
// check data validity if flag set:
#ifdef QCUSTOMPLOT_CHECK_DATA
if (QCP::isInvalidData(it->key, it->value))
qDebug() << Q_FUNC_INFO << "Data point at" << it->key << "of drawn range invalid." << "Plottable name:" << name();
#endif
// draw bar:
if (isSelectedSegment && mSelectionDecorator)
{
mSelectionDecorator->applyBrush(painter);
mSelectionDecorator->applyPen(painter);
} else
{
painter->setBrush(mBrush);
painter->setPen(mPen);
}
applyDefaultAntialiasingHint(painter);
painter->drawPolygon(getBarRect(it->key, it->value));
///---自定义逻辑-start---
//draw text
if(m_textVisible)
{
QRectF barRect = getBarRect(it->key, it->value);
painter->setFont(m_font);
QString text = QString::number(it->value, 'g', 2); //获取当前value值保留两位精度
QRectF textRect = painter->fontMetrics().boundingRect(0, 0, 0, 0, Qt::TextDontClip | m_textAlignment, text); //计算文字占用大小
if(mKeyAxis.data()->orientation() == Qt::Horizontal) //水平轴为keyAxis
{
if(mKeyAxis.data()->axisType() == QCPAxis::atTop) //上轴,文字放到柱图下方
textRect.moveTopLeft(barRect.bottomLeft() + QPointF(0, m_spacing));
else //下轴,文字放到柱图上方
textRect.moveBottomLeft(barRect.topLeft() - QPointF(0, m_spacing));
textRect.setWidth(barRect.width());
}
else //垂直轴为keyAxis
{
if(mKeyAxis.data()->axisType() == QCPAxis::atLeft) //左轴,文字放到柱图右侧
textRect.moveTopLeft(barRect.topRight() + QPointF(m_spacing, 0));
else //右轴,文字放到柱图左侧
textRect.moveTopRight(barRect.topLeft() - QPointF(m_spacing, 0));
textRect.setHeight(barRect.height());
}
painter->drawText(textRect, Qt::TextDontClip | m_textAlignment, text);
}
///---自定义逻辑-end---
}
}
///源码拷贝
// draw other selection decoration that isn't just line/scatter pens and brushes:
if (mSelectionDecorator)
mSelectionDecorator->drawDecoration(painter, selection());
}
dpBarsChart::dpBarsChart(QWidget* parent)
:dpBaseChart(parent)
{
setAttribute(Qt::WA_TranslucentBackground,true);
m_pCustomPlot = new QCustomPlot(this);
/* m_pBarsGroup = new QCPBarsGroup(m_pCustomPlot);
m_pBarsGroup->setSpacingType(QCPBarsGroup::stAbsolute);
m_pBarsGroup->setSpacing(2); */
initQCP();
QBoxLayout* mainLayout = new QBoxLayout(QBoxLayout::LeftToRight);
mainLayout->setContentsMargins(0, 1, 0, 0);
mainLayout->addWidget(m_pCustomPlot);
setLayout(mainLayout);
m_updateData = false;
connect(DataManager::instance(), &DataManager::dataUpdated, this, &dpBarsChart::onSignal_dataUpdated);
}
dpBarsChart::~dpBarsChart()
{
}
void dpBarsChart::initQCP()
{
m_chartStyle.bgColor = Qt::transparent;
m_chartStyle.axisColor = QColor(87, 100, 120);
m_chartStyle.labelColor = QColor(250, 250, 250);
m_chartStyle.labelFont = QFont("黑体", 12);
m_chartStyle.tickColor = QColor(87, 100, 120);
m_chartStyle.tickLabelColor = QColor(250, 250, 250);
m_chartStyle.tickLabelFont = QFont("黑体", 12);
m_chartStyle.gridPen = QPen(QColor(87, 100, 120), 1, Qt::DotLine);
m_pCustomPlot->setInteractions(QCP::iNone);
/*m_pCustomPlot->axisRect()->setRangeDrag(Qt::Horizontal); //只允许x轴方向的拖拽
double zoomFactor = m_pCustomPlot->axisRect()->rangeZoomFactor(Qt::Horizontal);
m_pCustomPlot->axisRect()->setRangeZoomFactor(zoomFactor, 1); //只做x轴的缩放*/
//m_pCustomPlot->xAxis->setTicks(false);
m_pCustomPlot->xAxis->setSubTicks(false);
//m_pCustomPlot->yAxis->setTicks(false);
m_pCustomPlot->yAxis->setSubTicks(false);
//m_pCustomPlot->yAxis->setVisible(false);
//m_pCustomPlot->yAxis2->setTicks(false);
m_pCustomPlot->yAxis2->setSubTicks(false);
m_pCustomPlot->yAxis2->setVisible(false);
//背景颜色
m_pCustomPlot->setBackground(QBrush(m_chartStyle.bgColor));
//坐标轴颜色
m_pCustomPlot->xAxis->setBasePen(m_chartStyle.axisColor);
m_pCustomPlot->xAxis2->setBasePen(m_chartStyle.axisColor);
m_pCustomPlot->yAxis->setBasePen(m_chartStyle.axisColor);
m_pCustomPlot->yAxis2->setBasePen(m_chartStyle.axisColor);
//坐标刻度颜色
m_pCustomPlot->xAxis->setTickPen(QPen(m_chartStyle.tickColor));
m_pCustomPlot->yAxis->setTickPen(QPen(m_chartStyle.tickColor));
m_pCustomPlot->yAxis2->setTickPen(QPen(m_chartStyle.tickColor));
//坐标刻度Label颜色
m_pCustomPlot->xAxis->setTickLabels(false);
m_pCustomPlot->xAxis->setTickLabelColor(m_chartStyle.tickLabelColor);
m_pCustomPlot->xAxis->setTickLabelFont(m_chartStyle.tickLabelFont);
m_pCustomPlot->yAxis->setTickLabels(false);
m_pCustomPlot->yAxis->setTickLabelColor(m_chartStyle.tickLabelColor);
m_pCustomPlot->yAxis->setTickLabelFont(m_chartStyle.tickLabelFont);
m_pCustomPlot->yAxis2->setTickLabelColor(m_chartStyle.tickLabelColor);
m_pCustomPlot->yAxis2->setTickLabelFont(m_chartStyle.tickLabelFont);
//网格线颜色
m_pCustomPlot->xAxis->grid()->setVisible(false);
m_pCustomPlot->xAxis->grid()->setPen(m_chartStyle.gridPen);
m_pCustomPlot->xAxis->grid()->setZeroLinePen(m_chartStyle.gridPen);
//m_pCustomPlot->xAxis2->grid()->setPen(m_chartStyle.gridPen);
m_pCustomPlot->yAxis->grid()->setVisible(false);
m_pCustomPlot->yAxis->grid()->setPen(m_chartStyle.gridPen);
m_pCustomPlot->yAxis->grid()->setZeroLinePen(m_chartStyle.gridPen);
m_pCustomPlot->yAxis2->grid()->setPen(m_chartStyle.gridPen);
//Legend
m_pCustomPlot->legend->setBrush(QBrush(QColor(255,255,255,12))); //背景透明
m_pCustomPlot->legend->setBorderPen(QPen(QColor(255,255,255,0))); //边框透明
m_pCustomPlot->legend->setFont(m_chartStyle.labelFont);
m_pCustomPlot->legend->setTextColor( m_chartStyle.labelColor);
}
void dpBarsChart::setTimeRange(TimeUnit unit)
{}
void dpBarsChart::setDateTime(const QDateTime& dateTime)
{
if(m_updateData)
{
for(auto it = m_bars.begin(); it != m_bars.end(); ++it)
DataManager::instance()->requestData(it.key(), this);
m_pCustomPlot->replot();
}
}
void dpBarsChart::viewHistoricalData(const QDateTime& dateTime)
{}
void dpBarsChart::synchronizeConfigData(const configurationResults& cfg)
{
m_updateData = false; //停止更新数据
//先清除现有图形(直方图不像曲线一样有连续的过程展现,所以不采用动态更新,每次都清除、重新创建)
//m_pBarsGroup->clear();
m_pCustomPlot->clearPlottables();
m_bars.clear();
m_barsGroups.clear();
bool groupByType = cfg.groupByType;
//设定朝向
QCPAxis* keyAxis = nullptr;
QCPAxis* valueAxis = nullptr;
if(cfg.barOrientataion == Vertical)
{
keyAxis = m_pCustomPlot->xAxis;
valueAxis = m_pCustomPlot->yAxis;
}
else
{
keyAxis = m_pCustomPlot->yAxis;
valueAxis = m_pCustomPlot->xAxis;
}
if(!keyAxis || !valueAxis)
return;
QVector<double> ticks;
int tick = 0;
QVector<QString> tickLabels;
QHash<RealTimeDataType, QSet<QString>> groupedBars; //按数据类型对bar进行分组以实现可以按组放置以及设置颜色等操作
for(int i = 0; i < cfg.m_pModel_dataSource->rowCount(); i++)
{
QString itemText = cfg.m_pModel_dataSource->item(i, 0)->text();
QString stationID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_stationID).toString();
QString compoentID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_componentID).toString();
QString pointID = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_pointID).toString();
QString dataID = stationID + "-" + compoentID + "-" + pointID;
QVariant colorData = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::DecorationRole);
RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt();
Bars bars;
bars.name = itemText;
bars.dataID = dataID;
bars.dataType = dataType;
bars.color = colorData.value<QColor>();
CustomBars* qBars = new CustomBars(keyAxis, valueAxis);
qBars->setTextVisible(true);
qBars->setName(bars.name);
qBars->setPen(bars.color); //边框颜色
qBars->setBrush(bars.color); //填充颜色
bars.qBars = qBars;
if(groupByType)
{
groupedBars[dataType].insert(dataID);
//每一个类型创建一个QCPBarsGroup对象
QCPBarsGroup* barsGroup = nullptr;
if(!m_barsGroups.contains(dataType))
{
barsGroup = new QCPBarsGroup(m_pCustomPlot);
m_barsGroups.insert(dataType, barsGroup);
}
}
else
{
ticks << ++tick;
tickLabels << itemText;
bars.keys << tick;
}
m_bars.insert(dataID, bars);
//实时模拟数据
DataManager::instance()->registerDataSource(dataID, [](){
static double min = 0, max = 10.0;
double randomFloat = min + QRandomGenerator::global()->generateDouble() * (max - min);
return QVariant::fromValue(randomFloat);
});
}
if(groupByType)
{
for(auto it = groupedBars.begin(); it != groupedBars.end(); ++it)
{
ticks.push_back(++tick);
switch(it.key())
{
case power:
tickLabels.push_back("功率");
break;
case voltage:
tickLabels.push_back("电压");
break;
case current:
tickLabels.push_back("电流");
break;
case temperature:
tickLabels.push_back("温度");
break;
default:
tickLabels.push_back("未定义");
break;
}
for(auto bars_it = it.value().begin(); bars_it != it.value().end(); ++bars_it)
{
QString dataID = *bars_it;
if(m_bars.contains(dataID))
m_bars[dataID].keys.push_back(tick);
}
}
}
//Axis
if(groupByType)
keyAxis->setTickLabels(true);
else
keyAxis->setTickLabels(false);
QSharedPointer<QCPAxisTickerText> textTicker(new QCPAxisTickerText);
textTicker->addTicks(ticks, tickLabels);
keyAxis->setTicker(textTicker);
keyAxis->setRange(0, ticks.count() + 1);
valueAxis->setTickLabels(true);
QSharedPointer<QCPAxisTickerFixed > fixedTicker(new QCPAxisTickerFixed);
valueAxis->setTicker(fixedTicker);
valueAxis->setRange(0, 11);
for(auto it = m_bars.begin(); it != m_bars.end(); ++it)
{
if(it.value().qBars.isNull())
continue;
//随机模拟值
QVector<double> values;
//double randomVaule = 1 + QRandomGenerator::global()->generateDouble() * (8 - 1);
values << 0;
Bars bar = it.value();
bar.qBars->setData(bar.keys, values);
if(groupByType && m_barsGroups.value(bar.dataType))
{
bar.qBars->setWidthType(QCPBars::wtPlotCoords);
//bar.qBars->setWidth(bar.qBars->width() / groupedBars.value(bar.dataType).count());
bar.qBars->setWidth(bar.qBars->width() * ticks.count() / m_bars.count());
bar.qBars->setBarsGroup(m_barsGroups.value(bar.dataType));
}
}
//Legend
if(cfg.showLegend && m_bars.count() > 0)
m_pCustomPlot->legend->setVisible(true);
else
m_pCustomPlot->legend->setVisible(false);
//m_pCustomPlot->replot();
m_updateData = true;
}
void dpBarsChart::onSignal_dataUpdated(const QString& dataID, const QVariant& data, const QDateTime& timestamp)
{
auto it = m_bars.find(dataID);
if(it != m_bars.end())
{
static double marginFactor = 1.0;
double dData = data.toDouble();
Bars bar = it.value();
//调整所在轴的范围
QCPRange range = bar.qBars->valueAxis()->range();
if(dData > range.upper)
{
double upper = dData + marginFactor;
bar.qBars->valueAxis()->setRangeUpper(upper);
}
else if(dData < range.lower)
{
double lower = dData - marginFactor;
bar.qBars->valueAxis()->setRangeLower(lower);
}
//更新值
QVector<double> values;
values << dData;
bar.qBars->setData(bar.keys, values);
}
}