2024-12-25 08:34:51 +08:00
|
|
|
|
#include "dpLineChart.h"
|
2025-08-21 17:23:52 +08:00
|
|
|
|
#include "dataManager.h"
|
2024-12-25 08:34:51 +08:00
|
|
|
|
|
2025-07-25 17:42:15 +08:00
|
|
|
|
//#define useDefaultAxis_Y //默认轴不可删除、不可左右移动,所以做动态管理尤其是动态排列时要考虑的比较复杂,可以采用不使用的策略,全部以自定义轴替代,默认轴(yAxis)只在初始化和没有实际数据轴(自定义)时显示用来做外观展示
|
2024-12-25 08:34:51 +08:00
|
|
|
|
dpLineChart::dpLineChart(QWidget* parent)
|
2025-07-09 14:29:29 +08:00
|
|
|
|
:dpBaseChart(parent)
|
2024-12-25 08:34:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
setAttribute(Qt::WA_TranslucentBackground,true);
|
|
|
|
|
|
|
|
|
|
|
|
m_pCustomPlot = new QCustomPlot(this);
|
|
|
|
|
|
initQCP();
|
|
|
|
|
|
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 60 * 1000;
|
2025-07-25 17:42:15 +08:00
|
|
|
|
m_axisArrangementMode = AlternateSides;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
//m_showLegend = false;
|
2025-07-31 15:47:32 +08:00
|
|
|
|
m_updateData = false;
|
2025-01-04 18:18:19 +08:00
|
|
|
|
|
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);
|
2025-08-21 17:23:52 +08:00
|
|
|
|
|
|
|
|
|
|
connect(DataManager::instance(), &DataManager::dataUpdated, this, &dpLineChart::onSignal_dataUpdated);
|
2024-12-25 08:34:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
dpLineChart::~dpLineChart()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void dpLineChart::initQCP()
|
|
|
|
|
|
{
|
2025-07-09 10:58:52 +08:00
|
|
|
|
m_chartStyle.bgColor = Qt::transparent;
|
|
|
|
|
|
m_chartStyle.axisColor = QColor(87, 100, 120);
|
2025-07-25 17:42:15 +08:00
|
|
|
|
m_chartStyle.labelColor = QColor(250, 250, 250);
|
|
|
|
|
|
m_chartStyle.labelFont = QFont("黑体", 12);
|
2025-07-09 10:58:52 +08:00
|
|
|
|
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);
|
|
|
|
|
|
|
2025-01-04 18:18:19 +08:00
|
|
|
|
//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);
|
2025-07-25 17:42:15 +08:00
|
|
|
|
//m_pCustomPlot->yAxis->setVisible(false);
|
2025-07-09 10:58:52 +08:00
|
|
|
|
//m_pCustomPlot->yAxis2->setTicks(false);
|
2024-12-25 08:34:51 +08:00
|
|
|
|
m_pCustomPlot->yAxis2->setSubTicks(false);
|
2025-07-25 17:42:15 +08:00
|
|
|
|
m_pCustomPlot->yAxis2->setVisible(false);
|
2025-07-09 10:58:52 +08:00
|
|
|
|
connect(m_pCustomPlot->xAxis, qOverload<const QCPRange &>(&QCPAxis::rangeChanged), //rangeChanged有两个版本,qOverload可以指定版本
|
|
|
|
|
|
this, &dpLineChart::onSignal_rangeChanged_xAxis);
|
2024-12-25 08:34:51 +08:00
|
|
|
|
//背景颜色
|
2025-07-09 10:58:52 +08:00
|
|
|
|
m_pCustomPlot->setBackground(QBrush(m_chartStyle.bgColor));
|
2024-12-25 08:34:51 +08:00
|
|
|
|
//坐标轴颜色
|
2025-07-09 10:58:52 +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
|
|
|
|
//坐标刻度颜色
|
2025-07-09 10:58:52 +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颜色
|
2025-07-09 10:58:52 +08:00
|
|
|
|
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);
|
2025-08-25 15:10:02 +08:00
|
|
|
|
m_pCustomPlot->yAxis->setTickLabels(false);
|
2024-12-25 08:34:51 +08:00
|
|
|
|
//网格线颜色
|
2025-07-09 10:58:52 +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);
|
2025-01-04 18:18:19 +08:00
|
|
|
|
//x轴用时间格式
|
|
|
|
|
|
QSharedPointer<QCPAxisTickerDateTime> timeTicker(new QCPAxisTickerDateTime);
|
2025-09-05 14:54:34 +08:00
|
|
|
|
timeTicker->setDateTimeFormat("hh:mm:ss");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
//qDebug() << timeTicker->dateTimeFormat();
|
|
|
|
|
|
m_pCustomPlot->xAxis->setTicker(timeTicker);
|
|
|
|
|
|
//qDebug() << m_pCustomPlot->xAxis->range();
|
2025-08-07 11:48:08 +08:00
|
|
|
|
|
|
|
|
|
|
//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);
|
2025-08-13 10:44:23 +08:00
|
|
|
|
//m_pCustomPlot->axisRect()->insetLayout()->setInsetAlignment(0, Qt::AlignRight|Qt::AlignTop);
|
2024-12-25 08:34:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-25 17:42:15 +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)
|
|
|
|
|
|
{
|
2025-07-31 15:47:32 +08:00
|
|
|
|
//因为要进行轴的移除再添加工作,所以其上相关的graph也要同步处理
|
|
|
|
|
|
QVector<QCPGraph*> affectedGraphs;
|
|
|
|
|
|
for(int j = 0; j < m_pCustomPlot->graphCount(); j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
QCPGraph* graph = m_pCustomPlot->graph(j);
|
|
|
|
|
|
if(graph->valueAxis() == axis.qAxis)
|
|
|
|
|
|
affectedGraphs.append(graph);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-25 17:42:15 +08:00
|
|
|
|
bool bRemoved = m_pCustomPlot->axisRect()->removeAxis(axis.qAxis);
|
|
|
|
|
|
if(bRemoved) //removeAxis执行成功,被删除的axis会被delete
|
|
|
|
|
|
{
|
|
|
|
|
|
QCPAxis* qcpAxis = m_pCustomPlot->axisRect()->addAxis(position);
|
|
|
|
|
|
axis.setQCPAxis(qcpAxis, false);
|
2025-07-31 15:47:32 +08:00
|
|
|
|
|
|
|
|
|
|
for(QCPGraph* graph : affectedGraphs)
|
|
|
|
|
|
graph->setValueAxis(qcpAxis);
|
2025-07-25 17:42:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//计算偏移量
|
|
|
|
|
|
int offset = axisTypeCounter.value(position, 0) * 30;
|
|
|
|
|
|
axis.qAxis->setOffset(offset);
|
|
|
|
|
|
axisTypeCounter[position] = axisTypeCounter.value(position, 0) + 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-07 11:48:08 +08:00
|
|
|
|
void dpLineChart::reLayoutLegend()
|
|
|
|
|
|
{
|
2025-08-13 10:44:23 +08:00
|
|
|
|
/*if(!m_showLegend)
|
2025-08-07 11:48:08 +08:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
//图例放在最右侧纵坐标轴的右侧
|
|
|
|
|
|
//1.找到最右侧坐标轴
|
|
|
|
|
|
QCPAxis* rightmostAxis = m_pCustomPlot->yAxis2;
|
|
|
|
|
|
int offset = rightmostAxis->offset();
|
|
|
|
|
|
QList<QCPAxis*> axes = m_pCustomPlot->axisRect()->axes(QCPAxis::atRight);
|
|
|
|
|
|
for(QCPAxis* axis : axes)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(axis->offset() > rightmostAxis->offset())
|
|
|
|
|
|
rightmostAxis = axis;
|
|
|
|
|
|
}
|
|
|
|
|
|
//2.设置图例位置
|
2025-08-13 10:44:23 +08:00
|
|
|
|
QCPLegend* legend = m_pCustomPlot->legend;*/
|
2025-08-07 11:48:08 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-12-25 08:34:51 +08:00
|
|
|
|
void dpLineChart::setTimeRange(TimeUnit unit)
|
|
|
|
|
|
{
|
2025-09-05 14:54:34 +08:00
|
|
|
|
QSharedPointer<QCPAxisTicker> ticker = m_pCustomPlot->xAxis->ticker();
|
|
|
|
|
|
QSharedPointer<QCPAxisTickerDateTime> dateTicker = qSharedPointerCast<QCPAxisTickerDateTime>(ticker);
|
|
|
|
|
|
|
2025-01-04 18:18:19 +08:00
|
|
|
|
switch(unit)
|
|
|
|
|
|
{
|
|
|
|
|
|
case TU_Year:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = m_curDateTime.date().daysInYear() * 24 * 60 * 60 * (qint64)1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("dd/MM\nyyyy");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Month:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = m_curDateTime.date().daysInMonth() * 24 * 60 * 60 * (qint64)1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("dd/MM\nyyyy");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Day:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 24 * 60 * 60 * 1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("dd/MM\nyyyy");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Hour:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 60 * 60 *1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_30:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 30 * 60 *1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_20:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 20 * 60 *1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_15:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 15 * 60 *1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_10:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 10 * 60 *1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_5:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 5 * 60 *1000;
|
|
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_3:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 3 * 60 *1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Minute_1:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 60 * 1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Second_30:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 30 * 1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Second_10:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 10 * 1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_Second_1:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 1 * 1000;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss:zzz");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_MSecond_500:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 500;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss:zzz");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_MSecond_100:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 100;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss:zzz");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_MSecond_50:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 50;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss:zzz");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
case TU_MSecond_10:
|
2025-09-05 14:54:34 +08:00
|
|
|
|
{
|
2025-01-04 18:18:19 +08:00
|
|
|
|
m_timeRange = 10;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
if(!dateTicker.isNull())
|
|
|
|
|
|
dateTicker->setDateTimeFormat("hh:mm:ss:zzz");
|
2025-01-04 18:18:19 +08:00
|
|
|
|
break;
|
2025-09-05 14:54:34 +08:00
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
default:
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2024-12-25 08:34:51 +08:00
|
|
|
|
|
2025-01-04 18:18:19 +08:00
|
|
|
|
void dpLineChart::setDateTime(const QDateTime& dateTime)
|
|
|
|
|
|
{
|
|
|
|
|
|
qint64 timeValue = dateTime.toMSecsSinceEpoch() / 1000.0;
|
|
|
|
|
|
//qint64 timeValue = QCPAxisTickerDateTime::dateTimeToKey(dateTime);
|
|
|
|
|
|
m_curDateTime = dateTime;
|
2025-07-31 15:47:32 +08:00
|
|
|
|
|
|
|
|
|
|
if(m_updateData)
|
2025-08-06 10:23:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
//模拟数据展示
|
2025-08-22 09:21:47 +08:00
|
|
|
|
/*static double min = 0, max = 10.0, marginFactor = 1.0;
|
2025-08-06 10:23:33 +08:00
|
|
|
|
for(auto it = m_graphs.begin(); it != m_graphs.end(); ++it)
|
|
|
|
|
|
{
|
|
|
|
|
|
double randomFloat = min + QRandomGenerator::global()->generateDouble() * (max - min);
|
2025-08-13 10:44:23 +08:00
|
|
|
|
//调整所在轴的范围
|
|
|
|
|
|
QCPRange range = it.value().qGraph->valueAxis()->range();
|
|
|
|
|
|
if(randomFloat > range.upper)
|
|
|
|
|
|
{
|
|
|
|
|
|
double upper = randomFloat + marginFactor;
|
|
|
|
|
|
it.value().qGraph->valueAxis()->setRangeUpper(upper);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(randomFloat < range.lower)
|
|
|
|
|
|
{
|
|
|
|
|
|
double lower = randomFloat - marginFactor;
|
|
|
|
|
|
it.value().qGraph->valueAxis()->setRangeLower(lower);
|
|
|
|
|
|
}
|
2025-08-06 10:23:33 +08:00
|
|
|
|
it.value().qGraph->addData(timeValue, randomFloat);
|
2025-08-22 09:21:47 +08:00
|
|
|
|
}*/
|
2025-08-21 17:23:52 +08:00
|
|
|
|
|
2025-08-22 09:21:47 +08:00
|
|
|
|
for(auto it = m_graphs.begin(); it != m_graphs.end(); ++it)
|
|
|
|
|
|
DataManager::instance()->requestData(it.key(), this);
|
2025-08-06 10:23:33 +08:00
|
|
|
|
}
|
2025-08-13 10:44:23 +08:00
|
|
|
|
|
|
|
|
|
|
m_pCustomPlot->xAxis->setRange(timeValue, m_timeRange / 1000.0, Qt::AlignRight);
|
|
|
|
|
|
m_pCustomPlot->replot();
|
2024-12-25 08:34:51 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-04 18:18:19 +08:00
|
|
|
|
void dpLineChart::viewHistoricalData(const QDateTime& dateTime)
|
2024-12-25 08:34:51 +08:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
}
|
2025-01-04 18:18:19 +08:00
|
|
|
|
|
2025-07-14 15:02:29 +08:00
|
|
|
|
void dpLineChart::synchronizeConfigData(const configurationResults& cfg)
|
|
|
|
|
|
{
|
2025-07-31 15:47:32 +08:00
|
|
|
|
m_updateData = false; //停止更新数据
|
2025-08-25 15:10:02 +08:00
|
|
|
|
//m_pCustomPlot->yAxis->setTickLabels(true);
|
2025-07-31 15:47:32 +08:00
|
|
|
|
|
|
|
|
|
|
//1.Y坐标轴-数量由数据类型决定
|
2025-07-15 19:35:37 +08:00
|
|
|
|
|
|
|
|
|
|
//将最新配置信息中的坐标轴相关数据存储在QHash中,有助于更好的判断当前坐标轴是否需要发生同步更新
|
|
|
|
|
|
QHash<RealTimeDataType, AxisConfig> axisCfgMap;
|
2025-07-25 17:42:15 +08:00
|
|
|
|
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
|
|
|
|
}
|
2025-07-15 19:35:37 +08:00
|
|
|
|
|
|
|
|
|
|
//删除轴
|
|
|
|
|
|
for(int i = 0; i < m_axes.size();)
|
|
|
|
|
|
{
|
2025-07-25 17:42:15 +08:00
|
|
|
|
#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
|
2025-07-15 19:35:37 +08:00
|
|
|
|
Axis& axis = m_axes[i];
|
|
|
|
|
|
if(!axisCfgMap.contains(axis._cfg.dataType))
|
|
|
|
|
|
{
|
2025-08-01 10:42:49 +08:00
|
|
|
|
//先删除轴上的Graph(注意先后顺序,QCustomPlot的removeGraph会析构graph,所以先做m_graphs的删除,或者改为QPointer智能指针可规避此问题)
|
2025-07-31 15:47:32 +08:00
|
|
|
|
// for(auto it = m_graphs.begin(); it != m_graphs.end();)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// if(it.value().qGraph && it.value().qGraph->valueAxis() == axis.qAxis)
|
|
|
|
|
|
// it = m_graphs.erase(it); //使用erase方法可以更新迭代器,从而避免迭代器失效
|
|
|
|
|
|
// else
|
|
|
|
|
|
// ++it;
|
|
|
|
|
|
// }
|
2025-08-04 15:11:35 +08:00
|
|
|
|
for(int j = 0; j < m_pCustomPlot->graphCount();)
|
2025-07-31 15:47:32 +08:00
|
|
|
|
{
|
|
|
|
|
|
QCPGraph* graph = m_pCustomPlot->graph(j);
|
|
|
|
|
|
if(graph->valueAxis() == axis.qAxis)
|
|
|
|
|
|
{
|
2025-08-06 10:23:33 +08:00
|
|
|
|
m_pCustomPlot->removeGraph(graph); //removeGraph时graph会被delete
|
2025-07-31 15:47:32 +08:00
|
|
|
|
}
|
2025-08-04 15:11:35 +08:00
|
|
|
|
else
|
|
|
|
|
|
++j;
|
2025-07-31 15:47:32 +08:00
|
|
|
|
}
|
2025-08-06 10:23:33 +08:00
|
|
|
|
QMutableHashIterator<QString, Graph> it(m_graphs); //使用QMutableHashIterator可以再遍历相关容器的同时安全的修改,例如删除元素
|
|
|
|
|
|
while (it.hasNext())
|
|
|
|
|
|
{
|
|
|
|
|
|
it.next();
|
|
|
|
|
|
if (it.value().qGraph.isNull()/*it.value().qGraph->valueAxis() == axis.qAxis*/) //利用QPointer特性保持数据同步
|
|
|
|
|
|
{
|
|
|
|
|
|
//m_pCustomPlot->removeGraph(it.value().qGraph);
|
|
|
|
|
|
it.remove(); // 直接删除当前项,无需手动管理迭代器
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-07-31 15:47:32 +08:00
|
|
|
|
//删除轴
|
2025-07-15 19:35:37 +08:00
|
|
|
|
m_pCustomPlot->axisRect()->removeAxis(axis.qAxis);
|
2025-07-25 17:42:15 +08:00
|
|
|
|
m_axes.remove(i);
|
2025-07-15 19:35:37 +08:00
|
|
|
|
}
|
|
|
|
|
|
else
|
2025-07-31 15:47:32 +08:00
|
|
|
|
++i;
|
2025-07-25 17:42:15 +08:00
|
|
|
|
#endif
|
2025-07-15 19:35:37 +08:00
|
|
|
|
}
|
2025-07-25 17:42:15 +08:00
|
|
|
|
if(m_axes.isEmpty()) //若所有轴(数据类型)全部清楚,将默认左轴xAxis显示出来
|
|
|
|
|
|
m_pCustomPlot->xAxis->setVisible(true);
|
|
|
|
|
|
|
|
|
|
|
|
//处理应用配置(新增或更新)
|
2025-08-01 10:42:49 +08:00
|
|
|
|
QHash<RealTimeDataType, Axis*> axesMap; //创建map类型变量,方便后续使用.QHash::insert()的第二个参数接收的是副本(引起拷贝),所以采用指针可以减少拷贝从而提升效率
|
|
|
|
|
|
for(auto& axis : m_axes)
|
|
|
|
|
|
{
|
|
|
|
|
|
axesMap.insert(axis._cfg.dataType, &axis);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-07-25 17:42:15 +08:00
|
|
|
|
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)) //更新配置
|
|
|
|
|
|
{
|
2025-08-13 10:44:23 +08:00
|
|
|
|
AxisConfig axisCfg = axisCfgMap.value(dataType);
|
|
|
|
|
|
axesMap.value(dataType)->applyConfig(axisCfg);
|
2025-07-25 17:42:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
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);
|
2025-07-15 19:35:37 +08:00
|
|
|
|
|
2025-07-25 17:42:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
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);
|
2025-08-04 15:11:35 +08:00
|
|
|
|
//axesMap.insert(axis._cfg.dataType, &m_axes.last()); //临时变量axesMap通过做更新,此处不要直接使用&axis,因为axis是局部变量,地址会被自动释放,造成堆错误
|
2025-07-25 17:42:15 +08:00
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-04 15:11:35 +08:00
|
|
|
|
//更新axesMap
|
|
|
|
|
|
axesMap.clear();
|
|
|
|
|
|
for(auto& axis : m_axes)
|
|
|
|
|
|
{
|
|
|
|
|
|
axesMap.insert(axis._cfg.dataType, &axis);
|
|
|
|
|
|
}
|
2025-07-15 19:35:37 +08:00
|
|
|
|
|
2025-07-25 17:42:15 +08:00
|
|
|
|
//重新排列坐标轴
|
2025-09-01 19:57:02 +08:00
|
|
|
|
m_axisArrangementMode = cfg.axisArrangement;
|
2025-07-25 17:42:15 +08:00
|
|
|
|
arrangeAxes();
|
2025-07-31 15:47:32 +08:00
|
|
|
|
|
|
|
|
|
|
//2.曲线-数据源决定
|
2025-08-06 10:23:33 +08:00
|
|
|
|
//qDebug() << "m_graphs before update: " << m_graphs.keys();
|
2025-07-31 15:47:32 +08:00
|
|
|
|
for(int i = 0; i < cfg.m_pModel_dataSource->rowCount(); i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
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 graphID = stationID + "-" + compoentID + "-" + pointID;
|
2025-08-06 10:23:33 +08:00
|
|
|
|
//qDebug() << "update:" << graphID;
|
|
|
|
|
|
|
|
|
|
|
|
QVariant colorData = cfg.m_pModel_dataSource->item(i, 0)->data(Qt::DecorationRole);
|
|
|
|
|
|
|
2025-08-01 10:42:49 +08:00
|
|
|
|
if(!m_graphs.contains(graphID)) //新增数据
|
2025-07-31 15:47:32 +08:00
|
|
|
|
{
|
|
|
|
|
|
RealTimeDataType dataType = (RealTimeDataType)cfg.m_pModel_dataSource->item(i, 0)->data(Qt::UserRole + itemRole_dataType).toInt();
|
2025-08-01 10:42:49 +08:00
|
|
|
|
QCPAxis* valueAxis = axesMap.value(dataType)->qAxis;
|
|
|
|
|
|
if(valueAxis == nullptr)
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
2025-07-31 15:47:32 +08:00
|
|
|
|
Graph graph;
|
|
|
|
|
|
graph.dataID = graphID;
|
|
|
|
|
|
graph.dataType = dataType;
|
2025-08-01 15:25:28 +08:00
|
|
|
|
graph.synchronizeTagging = "new";
|
2025-08-07 11:48:08 +08:00
|
|
|
|
graph.name = cfg.m_pModel_dataSource->item(i, 0)->text();
|
2025-08-01 10:42:49 +08:00
|
|
|
|
QCPGraph* newGraph = m_pCustomPlot->addGraph(m_pCustomPlot->xAxis, valueAxis);
|
|
|
|
|
|
if(newGraph)
|
|
|
|
|
|
{
|
2025-08-07 11:48:08 +08:00
|
|
|
|
newGraph->setName(graph.name);
|
2025-08-01 10:42:49 +08:00
|
|
|
|
if(colorData.isValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
QColor color = colorData.value<QColor>();
|
|
|
|
|
|
newGraph->setPen(QPen(color));
|
|
|
|
|
|
}
|
|
|
|
|
|
graph.qGraph = newGraph;
|
|
|
|
|
|
m_graphs.insert(graphID, graph);
|
2025-09-05 14:54:34 +08:00
|
|
|
|
|
|
|
|
|
|
//实时模拟数据
|
2025-08-22 09:21:47 +08:00
|
|
|
|
DataManager::instance()->registerDataSource(graphID, [](){
|
|
|
|
|
|
static double min = 0, max = 10.0;
|
|
|
|
|
|
double randomFloat = min + QRandomGenerator::global()->generateDouble() * (max - min);
|
|
|
|
|
|
return QVariant::fromValue(randomFloat);
|
|
|
|
|
|
});
|
2025-08-01 10:42:49 +08:00
|
|
|
|
}
|
2025-07-31 15:47:32 +08:00
|
|
|
|
}
|
2025-08-01 15:25:28 +08:00
|
|
|
|
else //更新数据
|
2025-07-31 15:47:32 +08:00
|
|
|
|
{
|
2025-08-04 15:11:35 +08:00
|
|
|
|
//m_graphs.value(graphID).synchronizeTagging = "update";
|
|
|
|
|
|
auto it = m_graphs.find(graphID);
|
|
|
|
|
|
if(it != m_graphs.end())
|
2025-08-06 10:23:33 +08:00
|
|
|
|
{
|
|
|
|
|
|
if(colorData.isValid())
|
|
|
|
|
|
{
|
|
|
|
|
|
QColor color = colorData.value<QColor>();
|
|
|
|
|
|
it.value().qGraph->setPen(QPen(color));
|
|
|
|
|
|
}
|
2025-08-04 15:11:35 +08:00
|
|
|
|
it.value().synchronizeTagging = "update";
|
2025-08-06 10:23:33 +08:00
|
|
|
|
}
|
2025-07-31 15:47:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-08-06 10:23:33 +08:00
|
|
|
|
//qDebug() << "m_graphs after update: " << m_graphs.keys();
|
2025-08-01 15:25:28 +08:00
|
|
|
|
//没有标记的就是需要删除的
|
|
|
|
|
|
QStringList keysToRemove;
|
|
|
|
|
|
for(auto it = m_graphs.begin(); it != m_graphs.end(); ++it)
|
|
|
|
|
|
{
|
|
|
|
|
|
if(it.value().synchronizeTagging =="noTagging") //删除
|
|
|
|
|
|
keysToRemove.append(it.key());
|
|
|
|
|
|
else
|
|
|
|
|
|
it.value().synchronizeTagging = "noTagging";
|
|
|
|
|
|
}
|
|
|
|
|
|
foreach (const QString& key, keysToRemove)
|
|
|
|
|
|
{
|
|
|
|
|
|
Graph g = m_graphs.take(key);
|
|
|
|
|
|
if( !m_pCustomPlot->removeGraph(g.qGraph) )
|
2025-08-04 15:11:35 +08:00
|
|
|
|
qWarning() << "Failed to remove gracloxne ph:" << key;
|
2025-08-01 15:25:28 +08:00
|
|
|
|
}
|
2025-08-06 10:23:33 +08:00
|
|
|
|
//qDebug() << "graph count: " << m_graphs.count() << ", " << m_pCustomPlot->graphCount();
|
2025-08-04 10:57:53 +08:00
|
|
|
|
|
2025-08-07 11:48:08 +08:00
|
|
|
|
//Legend
|
|
|
|
|
|
m_pCustomPlot->legend->setVisible(cfg.showLegend);
|
|
|
|
|
|
|
2025-07-31 15:47:32 +08:00
|
|
|
|
m_updateData = true;
|
2025-07-14 15:02:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-04 18:18:19 +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;
|
|
|
|
|
|
}
|
2025-08-21 17:23:52 +08:00
|
|
|
|
|
2025-08-25 15:10:02 +08:00
|
|
|
|
void dpLineChart::onSignal_dataUpdated(const QString& dataID, const QVariant& data, const QDateTime& timestamp)
|
2025-08-21 17:23:52 +08:00
|
|
|
|
{
|
|
|
|
|
|
auto it = m_graphs.find(dataID);
|
|
|
|
|
|
if(it != m_graphs.end())
|
|
|
|
|
|
{
|
|
|
|
|
|
static double marginFactor = 1.0;
|
|
|
|
|
|
double dData = data.toDouble();
|
|
|
|
|
|
//调整所在轴的范围
|
|
|
|
|
|
QCPRange range = it.value().qGraph->valueAxis()->range();
|
|
|
|
|
|
if(dData > range.upper)
|
|
|
|
|
|
{
|
|
|
|
|
|
double upper = dData + marginFactor;
|
|
|
|
|
|
it.value().qGraph->valueAxis()->setRangeUpper(upper);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if(dData < range.lower)
|
|
|
|
|
|
{
|
|
|
|
|
|
double lower = dData - marginFactor;
|
|
|
|
|
|
it.value().qGraph->valueAxis()->setRangeLower(lower);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
qint64 timeValue = timestamp.toMSecsSinceEpoch() / 1000.0;
|
|
|
|
|
|
it.value().qGraph->addData(timeValue, dData);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|