很多时候, 我们手中有一些数据, 它可以是人物/车辆/等等移动轨迹。
现在我们想要实现一个动态移动的效果。
同样的, 因为涉及到更改节点位置, 所以需要自定义一个事件:
详细见: SkeyeGisMap 自定义事件
class MoveEvent : public MapEvent
{
public:
const static MapEvent::EventType MoveEventType = MapEvent::EventType::UserEvent + 1;
MoveEvent(const QPointF &position, bool isClean) : MapEvent(MoveEventType), m_position(position), m_cleanTrack(isClean) { }
QPointF m_position;
bool m_cleanTrack = false;
};
因为我们需要持续更新位置, 所有这里的事件携带了一个位置和是否清除轨迹的标志。
接着, 我们使用 QVariantAnimation
模拟一个移动的效果。
AddDynamicTarget()
{
setFlag(ItemIsFocusScope);
setProcessFlags(ProcessFlag::UsePreLoadProcess | ProcessFlag::UseUserEvent);
setFocus(true);
m_animation = new QVariantAnimation(this);
connect(m_animation, &QVariantAnimation::valueChanged, this, [this](const QVariant &value){
pushEvent(new MoveEvent(value.toPointF(), false));
});
}
virtual void preLoadProcess() override
{
auto assistant = rootMap()->assistant();
auto startPosition = assistant->mapToDisplay(CoordinateReference::lonlatToWorld(QPointF(32.5810, 118.5970)));
auto controlPosition1 = assistant->mapToDisplay(CoordinateReference::lonlatToWorld(QPointF(32.2133, 119.1839)));
auto controlPosition2 = assistant->mapToDisplay(CoordinateReference::lonlatToWorld(QPointF(31.6718, 118.4196)));
auto endPosition = assistant->mapToDisplay(CoordinateReference::lonlatToWorld(QPointF(31.2316, 118.9032)));
m_busTrackNode = new MapLineNode(QVector<QPointF>{ startPosition }, 5, Qt::red);
m_busNode = new MapImageNode(this, QImage(QQmlFile::urlToLocalFileOrQrc("qrc:/bus.png")), QPointF(startPosition), QSizeF(12000, 6000));
auto lastLayer = rootMap()->lastLayer();
if (lastLayer) {
lastLayer->appendShape(m_busTrackNode);
lastLayer->appendShape(m_busNode);
}
m_animation->setStartValue(startPosition);
m_animation->setEndValue(endPosition);
m_animation->setKeyValueAt(0.33, controlPosition1);
m_animation->setKeyValueAt(0.66, controlPosition2);
m_animation->setDuration(15000);
}
这里用一张大巴的图片 MapImageNode
用作动态目标, 然后使用 MapLineNode
用作其轨迹。
我们连接 QVariantAnimation::valueChanged
信号, 即动画值更新时推送一个移动事件。
最后只需要处理该事件即可:
virtual void processUserEvent(MapEvent *event) override
{
switch (event->type()) {
case MoveEvent::MoveEventType:
{
auto moveEvent = static_cast<MoveEvent *>(event);
if (moveEvent->m_cleanTrack) {
m_busTrackNode->setPoints({});
} else {
auto position = m_busNode->position();
auto targetPosition = moveEvent->m_position;
QLineF line1(targetPosition, targetPosition - QPointF(0, 10));
QLineF line2(position, targetPosition);
m_busNode->setRotation(line2.angleTo(line1) - 90);
m_busNode->setPosition(targetPosition);
m_busTrackNode->appendPoint(targetPosition);
}
} break;
default:
break;
}
}
这里仅仅设置图片位置和添加轨迹点到线条中即可。
然后我们还简单计算了一下方向, 将大巴旋转到正确的角度。
为了清空轨迹和重置动画, 还增加了一个按键的事件 MapItem::keyPressEvent()
:
virtual void keyPressEvent(QKeyEvent *ev) override
{
if (ev->key() == Qt::Key_Space) {
if (m_animation->state() == QAbstractAnimation::Running)
m_animation->stop();
pushEvent(new MoveEvent(QPointF(), true));
m_animation->start();
}
}
源码地址(dynamictarget): https://gitee.com/visual-opening/skeyegismap/tree/master/coremap/example