首页| 论坛| 消息
主题:纯QWidget绘制打造地图组件/极速加载瓦片地图/放大缩小地图过渡效果
liudianwu发表于 2026-08-16 11:00
## 一、前言说明
在联网加载瓦片地图文件的过程中,当缩放切换的时候,需要一个过渡效果,如果没有这个过渡,可能会先出现一个空白界面,然后才是一张张瓦片返回来进行绘制,这样给用户的感觉是很慢,肉眼可见的在空白区域有一张图片进行加载,后面大量参考了许多gis软件,比如著名的qgc,他是在切换的过程中,如果地图放大,先将上一张整体绘制好的瓦片完整图片放大一倍,然后取中间部分,绘制到界面上作为底图,然后再慢慢加载各个区域的瓦片地图进行重新绘制,给人的感觉就是瞬间拿到了瓦片,其实不是的,仅仅是原来的放大的图片,恰好将要下载的最终生成的也是这块区域的,只是强制放大的会模糊一点,不影响使用,而且给人的感官非常好,以为瞬间下载好了,然后慢慢调整了清晰度。于是在这个地图组件中也使用了这个策略,感觉非常棒,用户终于不再抱怨说对比其他gis软件怎么感觉我的要慢一些了。
## 二、效果图

## 三、相关代码
```cpp
//缩放动画/正弦缓出曲线
m_zoom_anim.setDuration(300);
m_zoom_anim.setTargetObject(this);
m_zoom_anim.setEasingCurve(QEasingCurve::OutSine);
connect(&m_zoom_anim, SIGNAL(valueChanged(QVariant)), this, SLOT(onZoomAnimValueChanged(QVariant)));
connect(&m_zoom_anim, SIGNAL(finished()), this, SLOT(stopZoomAnim()));
void MapControl::startZoomAnim(int target_zoom, const QPointF &anchor)
{
//先取消瓦片下载
m_image_manager->abortLoading();
//未启用缩放动画/直接切换缩放级别
if (!m_zoom_anim_enabled || !this->isVisible()) {
m_cur_zoom = target_zoom;
this->changeZoom();
return;
}
//停止正在进行的动画
if (m_zoom_anim_active) {
m_zoom_anim.stop();
}
//直接使用主屏幕缓冲作为动画素材/记录绘制偏移量
m_zoom_anim_screen = m_screen_primary;
m_zoom_anim_offset = -(m_viewport_center_px + mapFocusPointWorldPx() - m_screen_focus_point).rawPoint();
//设置缩放锚点/滚轮缩放为鼠标位置/按钮缩放为视口中心
m_zoom_anim_anchor = anchor.isNull() ? QPointF(m_viewport_center_px.x(), m_viewport_center_px.y()) : anchor;
//计算目标缩放比例/每级差2倍
int diff = target_zoom - m_cur_zoom;
m_zoom_anim_target = qPow(2.0, diff);
m_zoom_anim_scale = 1.0;
m_zoom_anim_active = true;
//启动动画/从1.0插值到目标比例
m_zoom_anim.setStartValue(1.0);
m_zoom_anim.setEndValue(m_zoom_anim_target);
m_zoom_anim.start();
//立即更新缩放级别/触发新瓦片加载
m_cur_zoom = target_zoom;
m_screen_primary.fill(Qt::transparent);
this->changeZoom();
}
void MapControl::stopZoomAnim()
{
if (m_zoom_anim_active) {
m_zoom_anim_active = false;
m_zoom_anim.stop();
m_zoom_anim_scale = 1.0;
this->update();
}
}
void MapControl::drawZoomAnim(QPainter *painter)
{
qreal cx = m_zoom_anim_anchor.x();
qreal cy = m_zoom_anim_anchor.y();
painter->save();
painter->translate(cx, cy);
painter->scale(m_zoom_anim_scale, m_zoom_anim_scale);
painter->translate(-cx, -cy);
painter->drawPixmap(m_zoom_anim_offset, m_zoom_anim_screen);
painter->restore();
}
void MapControl::onZoomAnimValueChanged(const QVariant &value)
{
//从1.0插值到目标比例
m_zoom_anim_scale = value.toReal();
this->update();
}
```
## 四、相关地址
1. 国内站点:[https://gitee.com/feiyangqingyun](https://gitee.com/feiyangqingyun)
2. 国际站点:[https://github.com/feiyangqingyun](https://github.com/feiyangqingyun)
3. 个人作品:[https://blog.csdn.net/feiyangqingyun/article/details/97565652](https://blog.csdn.net/feiyangqingyun/article/details/97565652)
4. 文件地址:[https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A](https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A) 提取码:o05q文件名:bin_mapwidget.zip
## 五、功能特点
1. 支持各种地图源,包括天地图、高德地图、腾讯地图、谷歌地图、微软地图、ArcGis、OpenStreet、360地图等。
2. 同时支持WGS-84地球坐标系和GCJ-02火星坐标系,如果是天地图、谷歌地图,自动应用WGS-84坐标系,如果是高德地图、腾讯地图,自动应用GCJ-02坐标系。也可以主动设置在WGS-84坐标系加载高德地图,内部会自动处理坐标偏移。
3. 同时支持默卡托投影和经纬度投影,比如天地图的

浏览大图
下一页 (1/3)
回帖(0):

全部回帖(0)»
最新回帖
收藏本帖
发新帖