PowerMaster/dataPanel/dpLineChart.cpp

333 lines
12 KiB
C++
Raw Normal View History

2024-12-25 08:34:51 +08:00
#include "dpLineChart.h"
//#define useDefaultAxis_Y //默认轴不可删除、不可左右移动所以做动态管理尤其是动态排列时要考虑的比较复杂可以采用不使用的策略全部以自定义轴替代默认轴yAxis只在初始化和没有实际数据轴自定义时显示用来做外观展示
2024-12-25 08:34:51 +08:00
dpLineChart::dpLineChart(QWidget* parent)
:dpBaseChart(parent)
2024-12-25 08:34:51 +08:00
{
setAttribute(Qt::WA_TranslucentBackground,true);
m_pCustomPlot = new QCustomPlot(this);
initQCP();
m_timeRange = 60 * 1000;
m_axisArrangementMode = AlternateSides;
2024-12-25 08:34:51 +08:00
QBoxLayout* mainLayout = new QBoxLayout(QBoxLayout::LeftToRight);
mainLayout->setContentsMargins(0, 1, 0, 0);
mainLayout->addWidget(m_pCustomPlot);
setLayout(mainLayout);
}
dpLineChart::~dpLineChart()
{
}
void dpLineChart::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->axisRect()->setupFullAxesBox();
m_pCustomPlot->setInteractions(QCP::iRangeDrag | QCP::iRangeZoom);
m_pCustomPlot->axisRect()->setRangeDrag(Qt::Horizontal); //只允许x轴方向的拖拽
double zoomFactor = m_pCustomPlot->axisRect()->rangeZoomFactor(Qt::Horizontal);
m_pCustomPlot->axisRect()->setRangeZoomFactor(zoomFactor, 1); //只做x轴的缩放
2024-12-25 08:34:51 +08:00
m_pCustomPlot->xAxis->setSubTicks(false);
m_pCustomPlot->xAxis2->setTicks(false);
m_pCustomPlot->xAxis2->setSubTicks(false);
m_pCustomPlot->yAxis->setSubTicks(false);
//m_pCustomPlot->yAxis->setVisible(false);
//m_pCustomPlot->yAxis2->setTicks(false);
2024-12-25 08:34:51 +08:00
m_pCustomPlot->yAxis2->setSubTicks(false);
m_pCustomPlot->yAxis2->setVisible(false);
connect(m_pCustomPlot->xAxis, qOverload<const QCPRange &>(&QCPAxis::rangeChanged), //rangeChanged有两个版本qOverload可以指定版本
this, &dpLineChart::onSignal_rangeChanged_xAxis);
2024-12-25 08:34:51 +08:00
//背景颜色
m_pCustomPlot->setBackground(QBrush(m_chartStyle.bgColor));
2024-12-25 08:34:51 +08:00
//坐标轴颜色
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);
2024-12-25 08:34:51 +08:00
//坐标刻度颜色
m_pCustomPlot->xAxis->setTickPen(QPen(m_chartStyle.tickColor));
m_pCustomPlot->yAxis->setTickPen(QPen(m_chartStyle.tickColor));
m_pCustomPlot->yAxis2->setTickPen(QPen(m_chartStyle.tickColor));
2024-12-25 08:34:51 +08:00
//坐标刻度Label颜色
m_pCustomPlot->xAxis->setTickLabelColor(m_chartStyle.tickLabelColor);
m_pCustomPlot->xAxis->setTickLabelFont(m_chartStyle.tickLabelFont);
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);
2024-12-25 08:34:51 +08:00
//网格线颜色
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()->setPen(m_chartStyle.gridPen);
m_pCustomPlot->yAxis->grid()->setZeroLinePen(m_chartStyle.gridPen);
m_pCustomPlot->yAxis2->grid()->setPen(m_chartStyle.gridPen);
//x轴用时间格式
QSharedPointer<QCPAxisTickerDateTime> timeTicker(new QCPAxisTickerDateTime);
timeTicker->setDateTimeFormat("hh:mm:ss:zzz\nyyyy/MM/dd");
//qDebug() << timeTicker->dateTimeFormat();
m_pCustomPlot->xAxis->setTicker(timeTicker);
//qDebug() << m_pCustomPlot->xAxis->range();
2024-12-25 08:34:51 +08:00
}
void dpLineChart::arrangeAxes()
{
QMap<QCPAxis::AxisType, int> axisTypeCounter;
for(int i = 0; i < m_axes.size(); i++)
{
Axis& axis = m_axes[i];
QCPAxis::AxisType position = axis.qAxis->axisType();
if(m_axisArrangementMode == AlternateSides)
position = (i % 2 == 0) ? QCPAxis::atLeft : QCPAxis::atRight;
else if(m_axisArrangementMode == AllRight)
{
if(i == 0)
position = QCPAxis::atLeft;
else
position = QCPAxis::atRight;
}
//更新位置因为QCPAxis没有更新位置的结构只能采用从plot中移除再添加的方式
if(axis.qAxis->axisType() != position)
{
bool bRemoved = m_pCustomPlot->axisRect()->removeAxis(axis.qAxis);
if(bRemoved) //removeAxis执行成功被删除的axis会被delete
{
QCPAxis* qcpAxis = m_pCustomPlot->axisRect()->addAxis(position);
axis.setQCPAxis(qcpAxis, false);
}
}
//计算偏移量
int offset = axisTypeCounter.value(position, 0) * 30;
axis.qAxis->setOffset(offset);
axisTypeCounter[position] = axisTypeCounter.value(position, 0) + 1;
}
}
2024-12-25 08:34:51 +08:00
void dpLineChart::setTimeRange(TimeUnit unit)
{
switch(unit)
{
case TU_Year:
m_timeRange = m_curDateTime.date().daysInYear() * 24 * 60 * 60 * (qint64)1000;
break;
case TU_Month:
m_timeRange = m_curDateTime.date().daysInMonth() * 24 * 60 * 60 * (qint64)1000;
break;
case TU_Day:
m_timeRange = 24 * 60 * 60 * 1000;
break;
case TU_Hour:
m_timeRange = 60 * 60 *1000;
break;
case TU_Minute_30:
m_timeRange = 30 * 60 *1000;
break;
case TU_Minute_20:
m_timeRange = 20 * 60 *1000;
break;
case TU_Minute_15:
m_timeRange = 15 * 60 *1000;
break;
case TU_Minute_10:
m_timeRange = 10 * 60 *1000;
break;
case TU_Minute_5:
m_timeRange = 5 * 60 *1000;
break;
case TU_Minute_3:
m_timeRange = 3 * 60 *1000;
break;
case TU_Minute_1:
m_timeRange = 60 * 1000;
break;
case TU_Second_30:
m_timeRange = 30 * 1000;
break;
case TU_Second_10:
m_timeRange = 10 * 1000;
break;
case TU_Second_1:
m_timeRange = 1 * 1000;
break;
case TU_MSecond_500:
m_timeRange = 500;
break;
case TU_MSecond_100:
m_timeRange = 100;
break;
case TU_MSecond_50:
m_timeRange = 50;
break;
case TU_MSecond_10:
m_timeRange = 10;
break;
default:
break;
}
}
2024-12-25 08:34:51 +08:00
void dpLineChart::setDateTime(const QDateTime& dateTime)
{
qint64 timeValue = dateTime.toMSecsSinceEpoch() / 1000.0;
//qint64 timeValue = QCPAxisTickerDateTime::dateTimeToKey(dateTime);
m_pCustomPlot->xAxis->setRange(timeValue, m_timeRange / 1000.0, Qt::AlignRight);
m_pCustomPlot->replot();
m_curDateTime = dateTime;
2024-12-25 08:34:51 +08:00
}
void dpLineChart::viewHistoricalData(const QDateTime& dateTime)
2024-12-25 08:34:51 +08:00
{
}
2025-07-14 15:02:29 +08:00
void dpLineChart::synchronizeConfigData(const configurationResults& cfg)
{
//Y坐标轴的数量由数据类型决定
//将最新配置信息中的坐标轴相关数据存储在QHash中有助于更好的判断当前坐标轴是否需要发生同步更新
QHash<RealTimeDataType, AxisConfig> axisCfgMap;
/*for(int i = 0; i< cfg.m_pModel_dataType->rowCount(); i++)
2025-07-14 15:02:29 +08:00
{
AxisConfig axisConfig;
2025-07-14 15:02:29 +08:00
RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataType->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt();
axisConfig.dataType = dataType;
axisCfgMap.insert(dataType, axisConfig);
}*/
for(auto it = cfg.axisCfgMap.begin(); it != cfg.axisCfgMap.end(); ++it)
{
AxisConfig axisConfig;
axisConfig.dataType = it.key();
axisConfig.name = it.value().name;
axisConfig.unit = it.value().unit;
axisCfgMap.insert(it.key(), axisConfig);
2025-07-14 15:02:29 +08:00
}
//QHash::insert()的第二个参数接收的是副本(引起拷贝),所以采用指针可以减少拷贝从而提升效率
QHash<RealTimeDataType, Axis*> axesMap;
for(auto& axis : m_axes)
{
axesMap.insert(axis._cfg.dataType, &axis);
}
//删除轴
for(int i = 0; i < m_axes.size();)
{
#ifdef useDefaultAxis_Y
Axis& axis = m_axes[i];
if(!axisCfgMap.contains(axis._cfg.dataType))
{
if(axis.qAxis != m_pCustomPlot->yAxis && axis.qAxis != m_pCustomPlot->yAxis2)
m_pCustomPlot->axisRect()->removeAxis(axis.qAxis);
else
axis.qAxis->setVisible(false);
m_axes.remove(i);
}
else
i++;
#else
Axis& axis = m_axes[i];
if(!axisCfgMap.contains(axis._cfg.dataType))
{
m_pCustomPlot->axisRect()->removeAxis(axis.qAxis);
m_axes.remove(i);
}
else
i++;
#endif
}
if(m_axes.isEmpty()) //若所有轴(数据类型)全部清楚,将默认左轴xAxis显示出来
m_pCustomPlot->xAxis->setVisible(true);
//处理应用配置(新增或更新)
for(int i = 0; i < cfg.m_pModel_dataType->rowCount(); i++) //能保证和选取顺序一致
//for(auto it = axisCfgMap.begin(); it != axisCfgMap.end(); ++it)
{
RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataType->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt();
//RealTimeDataType dataType = it.key();
if(axesMap.contains(dataType)) //更新配置
{
}
else //新增轴
{
#ifdef useDefaultAxis_Y
AxisConfig cfg = axisCfgMap.value(dataType);
Axis axis;
if(m_axes.isEmpty()) //使用默认轴yAxis
{
axis.setQCPAxis(m_pCustomPlot->yAxis, true);
}
else if(m_axes.count() == 1 && m_axes.at(0).qAxis == m_pCustomPlot->yAxis) //默认轴yAxis被使用使用yAxis2
{
axis.setQCPAxis(m_pCustomPlot->yAxis2, true);
m_pCustomPlot->yAxis2->setVisible(false);
}
else
{
QCPAxis* pAxis = new QCPAxis(m_pCustomPlot->axisRect(), QCPAxis::atRight);
axis.setQCPAxis(pAxis, false);
axis.setStyle(m_chartStyle);
}
axis.applyConfig(cfg);
m_axes.append(axis);
#else
AxisConfig axisCfg = axisCfgMap.value(dataType);
Axis axis;
axis.applyConfig(axisCfg);
axis.setStyle(m_chartStyle);
if(m_axes.isEmpty())
{
//隐藏默认左轴
m_pCustomPlot->yAxis->setVisible(false);
//创建自定义轴代替
//QCPAxis* pAxis = new QCPAxis(m_pCustomPlot->axisRect(), QCPAxis::atLeft);
QCPAxis* pAxis = m_pCustomPlot->axisRect()->addAxis(QCPAxis::atLeft);
if(!pAxis)
continue;
//qDebug() << "add axis on:" << QCPAxis::atLeft << ", name: " << axisCfg.name;
axis.setQCPAxis(pAxis, false);
}
else
{
//默认放在右边
//QCPAxis* pAxis = new QCPAxis(m_pCustomPlot->axisRect(), QCPAxis::atRight);
QCPAxis* pAxis = m_pCustomPlot->axisRect()->addAxis(QCPAxis::atRight);
if(!pAxis)
continue;
axis.setQCPAxis(pAxis, false);
}
m_axes.append(axis);
#endif
}
}
//重新排列坐标轴
m_axisArrangementMode = cfg.arrangement;
arrangeAxes();
2025-07-14 15:02:29 +08:00
}
void dpLineChart::onSignal_rangeChanged_xAxis(const QCPRange& range)
{
// qDebug() << "m_timeRange: " << m_timeRange;
// qDebug() << "range size: " << range.size();
if(m_timeRange != range.size() * 1000)
m_timeRange = range.size() * 1000;
}