perf/fix(ui): 详情懒加载(双击只拉散点~0.8s,网格4s推迟) + 实时拖动平移(LivePanner替换像素抓取) + 横纵网格线
This commit is contained in:
parent
525c123211
commit
1054c227e1
|
|
@ -32,6 +32,7 @@ add_executable(geopro_desktop WIN32
|
||||||
panels/chart/ColorMapService.cpp
|
panels/chart/ColorMapService.cpp
|
||||||
panels/chart/ColorBarWidget.cpp
|
panels/chart/ColorBarWidget.cpp
|
||||||
panels/chart/ScatterPlotItem.cpp
|
panels/chart/ScatterPlotItem.cpp
|
||||||
|
panels/chart/LivePanner.cpp
|
||||||
panels/AnomalyTablePanel.cpp
|
panels/AnomalyTablePanel.cpp
|
||||||
panels/DatasetDetailPage.cpp
|
panels/DatasetDetailPage.cpp
|
||||||
panels/DatasetDetailPanel.cpp
|
panels/DatasetDetailPanel.cpp
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
#include "panels/chart/LivePanner.hpp"
|
||||||
|
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <qwt_plot.h>
|
||||||
|
#include <qwt_scale_div.h>
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
LivePanner::LivePanner(QwtPlot* plot, int xAxis, int yAxis, QObject* parent)
|
||||||
|
: QObject(parent), plot_(plot), xAxis_(xAxis), yAxis_(yAxis) {
|
||||||
|
if (plot_ && plot_->canvas()) plot_->canvas()->installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LivePanner::eventFilter(QObject* obj, QEvent* ev) {
|
||||||
|
if (!plot_ || obj != plot_->canvas()) return QObject::eventFilter(obj, ev);
|
||||||
|
|
||||||
|
switch (ev->type()) {
|
||||||
|
case QEvent::MouseButtonPress: {
|
||||||
|
auto* me = static_cast<QMouseEvent*>(ev);
|
||||||
|
if (me->button() == Qt::LeftButton) {
|
||||||
|
panning_ = true;
|
||||||
|
startPos_ = me->pos();
|
||||||
|
x0Min_ = plot_->axisScaleDiv(xAxis_).lowerBound();
|
||||||
|
x0Max_ = plot_->axisScaleDiv(xAxis_).upperBound();
|
||||||
|
y0Min_ = plot_->axisScaleDiv(yAxis_).lowerBound();
|
||||||
|
y0Max_ = plot_->axisScaleDiv(yAxis_).upperBound();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case QEvent::MouseMove: {
|
||||||
|
if (!panning_) break;
|
||||||
|
auto* me = static_cast<QMouseEvent*>(ev);
|
||||||
|
const int W = plot_->canvas()->width();
|
||||||
|
const int H = plot_->canvas()->height();
|
||||||
|
if (W <= 0 || H <= 0) break;
|
||||||
|
const double dxData = (me->pos().x() - startPos_.x()) * (x0Max_ - x0Min_) / W;
|
||||||
|
const double dyData = (me->pos().y() - startPos_.y()) * (y0Max_ - y0Min_) / H;
|
||||||
|
// 拖右(dx>0)→窗口左移(xmin/xmax 减),内容随光标右移;
|
||||||
|
// 拖下(像素 dy>0)→yLeft 数据向上→窗口上移(ymin/ymax 增),内容随光标下移。
|
||||||
|
plot_->setAxisScale(xAxis_, x0Min_ - dxData, x0Max_ - dxData);
|
||||||
|
plot_->setAxisScale(yAxis_, y0Min_ + dyData, y0Max_ + dyData);
|
||||||
|
plot_->replot();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case QEvent::MouseButtonRelease: {
|
||||||
|
auto* me = static_cast<QMouseEvent*>(ev);
|
||||||
|
if (me->button() == Qt::LeftButton) {
|
||||||
|
panning_ = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return QObject::eventFilter(obj, ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
#pragma once
|
||||||
|
#include <QObject>
|
||||||
|
#include <QPoint>
|
||||||
|
|
||||||
|
class QwtPlot;
|
||||||
|
|
||||||
|
namespace geopro::app {
|
||||||
|
|
||||||
|
// 实时拖动平移:左键拖动时连续平移两轴并 replot(坐标轴 + 内容一起实时移动),
|
||||||
|
// 区别于 QwtPlotPanner 的"像素抓取"(拖动中轴不动、边缘空白、松手才定稿)。
|
||||||
|
// 平移为纯平移,不改变纵横比(与 QwtPlotRescaler 锁定的真实比尺兼容)。
|
||||||
|
class LivePanner : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
LivePanner(QwtPlot* plot, int xAxis, int yAxis, QObject* parent = nullptr);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QwtPlot* plot_;
|
||||||
|
int xAxis_;
|
||||||
|
int yAxis_;
|
||||||
|
bool panning_ = false;
|
||||||
|
QPoint startPos_;
|
||||||
|
double x0Min_ = 0, x0Max_ = 0, y0Min_ = 0, y0Max_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace geopro::app
|
||||||
|
|
@ -10,11 +10,13 @@
|
||||||
|
|
||||||
#include <qwt_plot.h>
|
#include <qwt_plot.h>
|
||||||
#include <qwt_plot_canvas.h>
|
#include <qwt_plot_canvas.h>
|
||||||
#include <qwt_plot_panner.h>
|
|
||||||
#include <qwt_plot_magnifier.h>
|
#include <qwt_plot_magnifier.h>
|
||||||
#include <qwt_plot_marker.h>
|
#include <qwt_plot_marker.h>
|
||||||
|
#include <qwt_plot_grid.h>
|
||||||
#include <qwt_plot_rescaler.h>
|
#include <qwt_plot_rescaler.h>
|
||||||
|
|
||||||
|
#include "panels/chart/LivePanner.hpp"
|
||||||
|
|
||||||
namespace geopro::app {
|
namespace geopro::app {
|
||||||
|
|
||||||
RawDataChartView::RawDataChartView(QWidget* parent) : QWidget(parent) {
|
RawDataChartView::RawDataChartView(QWidget* parent) : QWidget(parent) {
|
||||||
|
|
@ -71,6 +73,16 @@ RawDataChartView::RawDataChartView(QWidget* parent) : QWidget(parent) {
|
||||||
plot_->setPalette(pal);
|
plot_->setPalette(pal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 横纵网格线(对齐原版浅灰网格)。
|
||||||
|
auto* grid = new QwtPlotGrid();
|
||||||
|
grid->setMajorPen(QColor(225, 225, 225), 1.0, Qt::SolidLine);
|
||||||
|
grid->setMinorPen(QColor(240, 240, 240), 1.0, Qt::DotLine);
|
||||||
|
grid->enableXMin(false);
|
||||||
|
grid->enableYMin(false);
|
||||||
|
grid->setXAxis(QwtPlot::xTop);
|
||||||
|
grid->setYAxis(QwtPlot::yLeft);
|
||||||
|
grid->attach(plot_);
|
||||||
|
|
||||||
// 过原点零线(对齐原版 zeroline:x=0 竖线 + y=0 横线 → "四象限"观感)。
|
// 过原点零线(对齐原版 zeroline:x=0 竖线 + y=0 横线 → "四象限"观感)。
|
||||||
auto* zeroX = new QwtPlotMarker();
|
auto* zeroX = new QwtPlotMarker();
|
||||||
zeroX->setLineStyle(QwtPlotMarker::VLine);
|
zeroX->setLineStyle(QwtPlotMarker::VLine);
|
||||||
|
|
@ -84,9 +96,8 @@ RawDataChartView::RawDataChartView(QWidget* parent) : QWidget(parent) {
|
||||||
zeroY->setLinePen(QColor(180, 180, 180), 1.0);
|
zeroY->setLinePen(QColor(180, 180, 180), 1.0);
|
||||||
zeroY->attach(plot_);
|
zeroY->attach(plot_);
|
||||||
|
|
||||||
// 交互:Panner(左键拖动平移)+ Magnifier(滚轮缩放)
|
// 交互:LivePanner(左键拖动实时平移,坐标轴+内容一起动)+ Magnifier(滚轮缩放)
|
||||||
auto* panner = new QwtPlotPanner(plot_->canvas());
|
new LivePanner(plot_, QwtPlot::xTop, QwtPlot::yLeft, this);
|
||||||
panner->setMouseButton(Qt::LeftButton);
|
|
||||||
|
|
||||||
auto* magnifier = new QwtPlotMagnifier(plot_->canvas());
|
auto* magnifier = new QwtPlotMagnifier(plot_->canvas());
|
||||||
// 反转滚轮方向:Qwt 默认 wheelFactor=0.9 → 上滚缩小;取倒数使「上滚=放大」(常规习惯)。
|
// 反转滚轮方向:Qwt 默认 wheelFactor=0.9 → 上滚缩小;取倒数使「上滚=放大」(常规习惯)。
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ void DatasetDetailController::openDataset(const QString& dsId, const QString& dd
|
||||||
ChartData d;
|
ChartData d;
|
||||||
d.dsId = dsId;
|
d.dsId = dsId;
|
||||||
d.ddCode = ddCode;
|
d.ddCode = ddCode;
|
||||||
|
// 仅拉原数据视图所需(scatter + 散点色阶 + 异常,~0.8s)。
|
||||||
|
// 网格数据(inversion/rows 服务端网格化 ~4s)推迟到切「网格数据」页时按需加载。
|
||||||
d.scatter = repo_.loadScatter(id);
|
d.scatter = repo_.loadScatter(id);
|
||||||
d.scatterScale = repo_.loadScatterColorScale(id);
|
d.scatterScale = repo_.loadScatterColorScale(id);
|
||||||
d.grid = repo_.loadGrid(id);
|
|
||||||
d.gridScale = repo_.loadColorScale(id);
|
|
||||||
d.anomalies = repo_.loadAnomalies(id);
|
d.anomalies = repo_.loadAnomalies(id);
|
||||||
busy_ = false;
|
busy_ = false;
|
||||||
emit chartReady(d);
|
emit chartReady(d);
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,9 @@ namespace {
|
||||||
struct StubRepo : data::IDatasetRepository {
|
struct StubRepo : data::IDatasetRepository {
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
std::vector<data::GsNode> loadStructure() override { return {}; }
|
std::vector<data::GsNode> loadStructure() override { return {}; }
|
||||||
core::Grid loadGrid(const std::string&) override { if (fail) throw std::runtime_error("x"); core::Grid g(2,2); g.x={0,1}; g.y={0,1}; return g; }
|
core::Grid loadGrid(const std::string&) override { core::Grid g(2,2); g.x={0,1}; g.y={0,1}; return g; }
|
||||||
core::ScatterField loadScatter(const std::string&) override { return {}; }
|
// openDataset 现只拉 scatter/scatterScale/anomalies(网格懒加载),失败路径由 loadScatter 抛出触发。
|
||||||
|
core::ScatterField loadScatter(const std::string&) override { if (fail) throw std::runtime_error("x"); return {}; }
|
||||||
core::ColorScale loadColorScale(const std::string&) override { return {}; }
|
core::ColorScale loadColorScale(const std::string&) override { return {}; }
|
||||||
core::ColorScale loadScatterColorScale(const std::string&) override { return {}; }
|
core::ColorScale loadScatterColorScale(const std::string&) override { return {}; }
|
||||||
std::vector<core::Anomaly> loadAnomalies(const std::string&) override { return {}; }
|
std::vector<core::Anomaly> loadAnomalies(const std::string&) override { return {}; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue