PowerMaster/dataPanel/dpBarsChart.cpp

402 lines
14 KiB
C++
Raw Normal View History

2025-08-25 15:10:02 +08:00
#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());
}
2025-08-25 15:10:02 +08:00
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); */
2025-09-01 19:57:02 +08:00
initQCP();
2025-08-25 15:10:02 +08:00
QBoxLayout* mainLayout = new QBoxLayout(QBoxLayout::LeftToRight);
mainLayout->setContentsMargins(0, 1, 0, 0);
mainLayout->addWidget(m_pCustomPlot);
setLayout(mainLayout);
m_updateData = false;
2025-08-25 15:10:02 +08:00
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轴的缩放*/
2025-09-01 19:57:02 +08:00
//m_pCustomPlot->xAxis->setTicks(false);
2025-08-25 15:10:02 +08:00
m_pCustomPlot->xAxis->setSubTicks(false);
2025-09-01 19:57:02 +08:00
//m_pCustomPlot->yAxis->setTicks(false);
2025-08-25 15:10:02 +08:00
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();
}
}
2025-08-25 15:10:02 +08:00
void dpBarsChart::viewHistoricalData(const QDateTime& dateTime)
{}
void dpBarsChart::synchronizeConfigData(const configurationResults& cfg)
2025-09-01 19:57:02 +08:00
{
m_updateData = false; //停止更新数据
2025-09-01 19:57:02 +08:00
//先清除现有图形(直方图不像曲线一样有连续的过程展现,所以不采用动态更新,每次都清除、重新创建)
//m_pBarsGroup->clear();
2025-09-01 19:57:02 +08:00
m_pCustomPlot->clearPlottables();
m_bars.clear();
m_barsGroups.clear();
2025-09-01 19:57:02 +08:00
bool groupByType = cfg.groupByType;
2025-09-01 19:57:02 +08:00
//设定朝向
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)
2025-09-01 19:57:02 +08:00
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);
2025-09-01 19:57:02 +08:00
qBars->setName(bars.name);
qBars->setPen(bars.color); //边框颜色
qBars->setBrush(bars.color); //填充颜色
bars.qBars = qBars;
if(groupByType)
{
2025-09-01 19:57:02 +08:00
groupedBars[dataType].insert(dataID);
//每一个类型创建一个QCPBarsGroup对象
QCPBarsGroup* barsGroup = nullptr;
if(!m_barsGroups.contains(dataType))
{
barsGroup = new QCPBarsGroup(m_pCustomPlot);
m_barsGroups.insert(dataType, barsGroup);
}
}
2025-09-01 19:57:02 +08:00
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);
});
2025-09-01 19:57:02 +08:00
}
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
2025-09-01 19:57:02 +08:00
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);
2025-09-01 19:57:02 +08:00
valueAxis->setTickLabels(true);
QSharedPointer<QCPAxisTickerFixed > fixedTicker(new QCPAxisTickerFixed);
valueAxis->setTicker(fixedTicker);
2025-09-01 19:57:02 +08:00
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;
2025-09-01 19:57:02 +08:00
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));
}
2025-09-01 19:57:02 +08:00
}
//Legend
if(cfg.showLegend && m_bars.count() > 0)
m_pCustomPlot->legend->setVisible(true);
else
m_pCustomPlot->legend->setVisible(false);
2025-09-01 19:57:02 +08:00
//m_pCustomPlot->replot();
m_updateData = true;
2025-09-01 19:57:02 +08:00
}
2025-08-25 15:10:02 +08:00
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);
}
}