83 lines
3.3 KiB
C++
83 lines
3.3 KiB
C++
#include "panels/chart/LivePanner.hpp"
|
||
|
||
#include <QEvent>
|
||
#include <QMouseEvent>
|
||
#include <QWheelEvent>
|
||
#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;
|
||
}
|
||
case QEvent::Wheel: {
|
||
// 滚轮缩放(以光标为中心,上滚=放大),并 **消费事件**(return true)避免冒泡到外层
|
||
// 滚动区域触发滚动条。两轴同因子缩放→保持锁定的真实比尺。
|
||
auto* we = static_cast<QWheelEvent*>(ev);
|
||
const int d = we->angleDelta().y();
|
||
if (d == 0) return true;
|
||
const double f = (d > 0) ? (1.0 / 1.15) : 1.15; // 上滚→区间缩小→放大
|
||
const QPointF pos = we->position();
|
||
const double cx = plot_->invTransform(xAxis_, pos.x());
|
||
const double cy = plot_->invTransform(yAxis_, pos.y());
|
||
const double xMin = plot_->axisScaleDiv(xAxis_).lowerBound();
|
||
const double xMax = plot_->axisScaleDiv(xAxis_).upperBound();
|
||
const double yMin = plot_->axisScaleDiv(yAxis_).lowerBound();
|
||
const double yMax = plot_->axisScaleDiv(yAxis_).upperBound();
|
||
plot_->setAxisScale(xAxis_, cx - (cx - xMin) * f, cx + (xMax - cx) * f);
|
||
plot_->setAxisScale(yAxis_, cy - (cy - yMin) * f, cy + (yMax - cy) * f);
|
||
plot_->replot();
|
||
we->accept();
|
||
return true;
|
||
}
|
||
default:
|
||
break;
|
||
}
|
||
return QObject::eventFilter(obj, ev);
|
||
}
|
||
|
||
} // namespace geopro::app
|