一、前言說明
無論哪一家的地圖,都提供了呼叫函式繪製各種覆蓋物,但是有時候的場景是希望進入新增覆蓋物模式,然後每次在地圖上按下都自動生成對應的覆蓋物比如圓形,這樣就不需要使用者提前知道經緯度座標等引數,而是讓使用者自己在地圖上拾取即可,這樣靈活性就極大的提高了。百度地圖和騰訊地圖是提供了繪圖工具欄來實現,高德和天地圖提供了對應的函式介面,函式介面名基本上是在對應覆蓋物末尾加上tool字樣,比如折線覆蓋物是polyline,折線工具是polylinetool,一旦進入某一種覆蓋物新增模式,則每次在地圖上新增的都是該種型別的覆蓋物,如果需要新增其他覆蓋物,需要重新切換覆蓋物的型別。
新增好的覆蓋物,有時候又需要重新編輯調整,比如標註點調整位置,圓形調整半徑,多邊形調整座標等,所以需要讓各種覆蓋物進入編輯狀態,於是新增通用函式介面,用於將介面上的所有覆蓋物進入和退出編輯狀態。不同地圖廠家對應提供的介面都不同,有些是呼叫enableEdit,有些是enableEditing,甚至還有是enableDragging,而且有些是拖動和編輯都需要單獨呼叫函式,比如setDraggable和setEditable,因為多邊形既可以拖動位置,也可以調整邊邊角角拉伸座標。所有就封裝了這麼個通用的函式來處理。
二、功能特點
2.1 地圖功能
- 支援多種地圖核心,預設採用百度地圖,可選高德地圖、天地圖、騰訊地圖、谷歌地圖等。
- 同時支援線上地圖和離線地圖兩種模式,離線地圖方便在不聯網的場景中使用。
- 支援各種地圖控制元件的啟用,比如地圖導航、地圖型別、縮圖、比例尺、全景導航、實時路況、繪圖工具、結果皮膚等。
- 支援多種地圖功能的動態啟用禁用,比如地圖拖曳、鍵盤操作、滾輪縮放、雙擊放大、連續縮放、地圖測距等。
- 提供眾多js函式介面用於互動,引數極其豐富,能夠想到的應用場景需求都有。
- 統一的訊號槽機制,地圖中的結果統一訊號傳送出去,收到後根據type型別區分。
- 支援地圖互動,比如滑鼠按下獲取對應位置的經緯度。單擊標註點彈出對應點的資訊。
- 支援新增標註、刪除標註、移動標註、清空標註。
- 標註點可以指定圖示圖片和尺寸,支援gif動圖,支援指定以圖片中心對齊還是底部中心對齊。可以設定旋轉角度,帶富文字提示資訊。
- 標註點事件支援單擊發訊號通知和自己彈框顯示資訊。
- 提供地址轉座標和座標轉地址介面。
- 支援各種圖形繪製,包括折線圖、多邊形、矩形、圓形、弧線等。
- 可顯示懸浮的繪圖工具欄,直接在地圖上劃線、標註點、矩形、圓形等。
- 支援各種區域搜尋,比如矩形區域、圓形區域,可以按照關鍵字匹配將搜尋結果顯示在地圖中。
- 可動態新增離線的行政區邊界點資料。可以搜尋行政區劃並獲取該區域的邊界點資料。資料可以儲存到檔案以便離線使用。
- 支援點聚合功能,多個小標註點合併到一個大標註點,防止點密集導致互動不友好。
- 可以新增海量點,每個點都可以單擊獲取對應座標和資訊。
- 所有的覆蓋物資訊比如標註點、矩形、多邊形、折線圖等,都可以主動獲取對應的資訊比如座標點和路徑等。
- 支援路徑規劃,支援公交路線、自駕路線、步行路線、騎行路線,不同查詢支援不同策略,可選最少時間、最少換乘、不走高架等。
- 路徑規劃結果可以顯示在地圖中,也可以獲取到路徑點座標集合。這個資料可以儲存到檔案,以便發給機器人或者無人機做導航用來軌跡移動。
- 可以設定不同的地圖檢視比如街道圖、衛星圖、混合圖。
- 可以設定不同的樣式,比如午夜藍、青草綠等樣式風格。
- 可以設定地圖的旋轉角度和傾斜角度。
- 提供經緯度座標糾偏轉換功能,比如傳入的GPS座標需要轉換到百度地圖座標或者高德地圖座標。各種座標系轉換全部離線函式,支援地球座標系WGS-84、火星座標系GCJ-02、百度座標系BD-09之間的互相轉換,涵蓋了各種地圖的座標系。
- 提供動態軌跡點移動功能,按照給定的經緯度座標集合平滑移動。
- 同時支援qwidget和qml,支援編譯到安卓系統執行。
2.2 其他功能
- 提供離線地圖下載模組,可以選擇不同的地圖核心比如百度地圖或者谷歌地圖,不同的地圖型別比如下載街道圖還是衛星圖,不同的地圖層級,多執行緒極速下載。
- 表格行實時顯示對應的瓦片下載進度,有下載超時時間,重試次數,每個瓦片下載完成都傳送訊號通知,引數包括下載用時。
- 提供省市輪廓圖下載模組,自動下載各個地區的輪廓圖,儲存到指令碼檔案或者文字檔案。
- 支援手動調整不同區域的輪廓邊界,調整後可以主動獲取調整後的邊界點集合。
- 提供動態點位示例,手動在地圖上選點並新增標註,附帶自定義的資訊比如速度和時間等。
- 提供海量點位示例,批次新增標註點、點聚合、海量點。用於測試環境中支援的最大點位效能。
- 提供動態軌跡示例,在地圖上滑鼠按下選擇起點和終點後,查詢路線,獲取路徑軌跡點,模擬軌跡平滑移動。可以篩選資料將過多的路徑點篩選到設定的點數。
- 提供軌跡回放示例,按照指定的軌跡點列表回放,也可以匯入軌跡點資料進行回放。同時支援在街道圖、衛星圖、混合圖中回放軌跡。
- 提供省市區域地圖示例,採用echart元件,同時支援閃爍點圖、遷徙圖、區域地圖、世界地圖、儀表盤等。可以設定標題、提示資訊、背景顏色、文字顏色、線條顏色、區域顏色等各種顏色。
- 省市區域地圖示例,內建世界地圖、全國地圖、省份地圖、地區地圖,可以精確到縣,所有地圖全部離線使用。可設定城市的名稱、值、經緯度集合。
- 內建通用瀏覽器元件,同時支援webkit/webengine/miniblink等核心。提供網頁控制元件示例,演示開啟網頁和本地網頁檔案。
- 支援任意Qt版本、任意系統、任意編譯器。
三、相關連結
- 體驗地址:https://pan.baidu.com/s/1ZxG-oyUKe286LPMPxOrO2A 提取碼:o05q 檔名:bin_map.zip
- 國內站點:https://gitee.com/feiyangqingyun
- 國際站點:https://github.com/feiyangqingyun
四、效果圖
五、相關程式碼
void MapObjBaiDu::addDrawingTool()
{
if (!(mapControl & MapControl_Drawing)) {
return;
}
//初始化繪圖工具欄
html << QString(" var styleOptions = getOverlayProperty();");
html << QString(" var drawingManager = new BMapLib.DrawingManager(map, {");
html << QString(" isOpen:false,");
html << QString(" enableDrawingTool:true,");
html << QString(" drawingToolOptions:{anchor:BMAP_ANCHOR_TOP_RIGHT, offset:new BMap.Size(100, 5)},");
html << QString(" circleOptions:styleOptions, polylineOptions:styleOptions, polygonOptions:styleOptions, rectangleOptions:styleOptions");
html << QString(" });");
//新增監聽事件獲取繪製結果
html << QString(" drawingManager.addEventListener('overlaycomplete', function(e) {");
html << QString(" overlays.push(e.overlay);");
html << QString(" receiveData('overlaycomplete');");
html << QString(" });");
//執行指定的繪製動作
html << QString(" function doDraw(type) {");
html << QString(" drawingManager.close();");
html << QString(" if (type == 'marker') {");
html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_MARKER);");
html << QString(" } else if (type == 'polyline') {");
html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_POLYLINE);");
html << QString(" } else if (type == 'polygon') {");
html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_POLYGON);");
html << QString(" } else if (type == 'rectangle') {");
html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_RECTANGLE);");
html << QString(" } else if (type == 'circle') {");
html << QString(" drawingManager.setDrawingMode(BMAP_DRAWING_CIRCLE);");
html << QString(" }");
html << QString(" if (type != 'cancel') {");
html << QString(" drawingManager.open();");
html << QString(" }");
html << QString(" }");
}
#include "frmmapdemodraw.h"
#include "ui_frmmapdemodraw.h"
#include "qthelper.h"
#include "maphelper.h"
#include "webview.h"
frmMapDemoDraw::frmMapDemoDraw(QWidget *parent) : QWidget(parent), ui(new Ui::frmMapDemoDraw)
{
ui->setupUi(this);
this->initForm();
on_btnLoadMap_clicked();
}
frmMapDemoDraw::~frmMapDemoDraw()
{
delete ui;
}
void frmMapDemoDraw::initForm()
{
//設定右側固定寬度
ui->frameRight->setFixedWidth(AppData::RightWidth / 2);
//單選框訊號槽
QList<QRadioButton *> rbtns = ui->frameRight->findChildren<QRadioButton *>();
foreach (QRadioButton *rbtn, rbtns) {
connect(rbtn, SIGNAL(toggled(bool)), this, SLOT(toggled(bool)));
}
//例項化瀏覽器控制元件並加入到佈局
webView = new WebView(this);
webView->setLayout(ui->gridLayout);
connect(webView, SIGNAL(loadSuccess()), this, SLOT(loadSuccess()));
connect(webView, SIGNAL(receiveDataFromJs(QString, QVariant)), this, SLOT(receiveDataFromJs(QString, QVariant)));
//例項化地圖類
mapObj = MapHelper::getMapObj(this, AppConfig::MapDemoCore);
mapObj->setWebView(webView);
mapObj->setSaveFile(SaveFile);
mapObj->setMapControl(MapControl_Drawing);
mapObj->setMapLocal(AppConfig::MapDemoLocal);
}
void frmMapDemoDraw::toggled(bool checked)
{
if (!checked) {
return;
}
//判斷按下了哪個單選框
QRadioButton *rbtn = (QRadioButton *)sender();
QString type = rbtn->objectName().replace("rbtn", "").toLower();
this->runJs(QString("doDraw('%1')").arg(type));
}
void frmMapDemoDraw::loadSuccess()
{
//禁用雙擊放大
mapObj->setEnable(EnableType_DoubleClickZoom, false);
}
void frmMapDemoDraw::runJs(const QString &js)
{
//非繪製指令則先要取消繪製
if (!js.startsWith("doDraw")) {
ui->rbtnCancel->setChecked(true);
this->runJs("doDraw('cancel')");
}
mapObj->runJs(js);
}
void frmMapDemoDraw::receiveDataFromJs(const QString &type, const QVariant &data)
{
QString result = data.toString();
if (type == "rightclick") {
//識別滑鼠右鍵自動取消繪製
ui->rbtnCancel->setChecked(true);
} else if (type == "overlayinfo") {
QtHelper::showMessageBoxInfo("覆蓋物資訊\n" + result);
//如果是矩形可以取出四個點繪製標註點看下位置
if (result.startsWith("rectangle")) {
QString rect = result.split("|").at(1);
QStringList points = rect.split(";");
for (int i = 0; i < points.count(); ++i) {
//this->runJs(QString("addMarker('%1', '%2', '%1')").arg(i).arg(points.at(i)));
}
}
} else if (type == "overlaycomplete") {
//ui->rbtnCancel->setChecked(true);
}
}
void frmMapDemoDraw::on_btnLoadMap_clicked()
{
ui->rbtnCancel->setChecked(true);
mapObj->load();
}
void frmMapDemoDraw::on_btnStartEdit_clicked()
{
//高德地圖用的方式比較特別
if (mapObj->getMapCore() == MapCore_GaoDe) {
this->runJs("enableEdit(true)");
} else {
this->runJs("editOverlays(true)");
}
}
void frmMapDemoDraw::on_btnStopEdit_clicked()
{
//高德地圖用的方式比較特別
if (mapObj->getMapCore() == MapCore_GaoDe) {
this->runJs("enableEdit(false)");
} else {
this->runJs("editOverlays(false)");
}
}
void frmMapDemoDraw::on_btnGetOverlay_clicked()
{
//獲取前先要停止編輯
on_btnStopEdit_clicked();
this->runJs("getOverlayInfo()");
}
void frmMapDemoDraw::on_btnClearOverlay_clicked()
{
this->runJs("clearOverlay()");
}