一、前言
在現在很多的應用系統中,會提供一個地圖模塊,地圖相關的應用和app也是非常多,最廣泛的應用就屬於導航,地圖基本上分在線的和離線的兩種,在線的一般都是實時的,數據也是最新的,速度很快路線很准,缺點是耗費流量,一直需要收發數據,而離線的需要先把地圖包和對應的文件下載到本地,直接讀取本地的地圖數據進行交互。
用Qt做過很多個商業項目,其中有幾個涉及到加載地圖用於展示設備的分布,之前做的是在線的地圖,通過網頁的交互來獲取和設置數據,最近幾年越來越多需要離線地圖的需求,離線地圖最核心的就是地圖數據包,也叫瓦片地圖,需要通過下載器下載到本地使用,網上查了下,還非常多公司專門做這個離線瓦片地圖的下載器,絕大部分都是收費的。
越來越多的地圖服務用到瓦片技術,例如我國實行發布的天地圖服務就運用了地圖瓦片技術。其實切片之后的地圖瓦片是柵格圖像,並不具備定位信息,不過切片運用了相關切片算法之后,可以計算出具體定位的位置。例如采用WGS84大地坐標系為空間參考,對地圖進行切片,采用一定的切片算法,例如用經緯度步長等比例分割形成地圖瓦片,當需要對一個具體地方進行定位時,可以根據經緯度步長來計算具體位置,以此來達到定位的功能。
近期抽空特意將大屏系統中常用的區域地圖以及地圖功能模塊重新封裝了下,使得支持在線和離線兩種模式,同時支持webkit、webengine、ie 三種方式,支持閃爍點圖、遷徙圖、區域地圖、儀表盤,還帶有交互功能。
echart儀表盤帶交互demo開源地址:https://gitee.com/feiyangqingyun/QWidgetDemo https://github.com/feiyangqingyun/QWidgetDemo
文件名稱:echartgauge
體驗地址:https://gitee.com/feiyangqingyun/QWidgetExe https://github.com/feiyangqingyun/QWidgetExe
文件名稱:bin_map.zip
二、功能特點
Echarts地圖封裝類功能特點
- 同時支持閃爍點圖、遷徙圖、區域地圖、儀表盤等。
- 可以設置標題、提示信息、背景顏色、文字顏色、線條顏色、區域顏色等各種顏色。
- 可設置城市的名稱、值、經緯度 集合。
- 可設置地圖的放大倍數、是否允許鼠標滾輪縮放。
- 內置世界地圖、全國地圖、省份地圖、地區地圖,可以精確到縣,所有地圖全部離線使用。
- 內置了各省市json數據文件轉js文件功能,如有數據更新自行轉換即可,支持單個文件轉換和一鍵轉換所有文件。
- 內置了從json文件或者js文件獲取該區域的所有名稱和經緯度信息集合的功能,可以通過該方法獲取到信息用來顯示。
- 依賴瀏覽器組件顯示地圖,提供的demo支持webkit、webengine、ie 三種方式加載網頁。
- 拓展性極強,可以依葫蘆畫瓢自行增加各種精美的echarts組件,做出牛逼的效果。
- 內置的儀表盤組件提供交互功能,demo演示中包含了對應的代碼。
- 函數接口友好和統一,使用簡單方便,就一個類。
- 支持任意Qt版本、任意系統、任意編譯器。
百度地圖封裝類功能特點
- 同時支持在線地圖和離線地圖兩種模式。
- 同時支持webkit內核、webengine內核、IE內核。
- 支持設置多個標注點,信息包括名稱、地址、經緯度。
- 可設置地圖是否可單擊、拖動、鼠標滾輪縮放。
- 可設置協議版本、秘鑰、主題樣式、中心坐標、中心城市、地理編碼位置等。
- 可設置地圖縮放比例和級別,縮略圖、比例尺、路況信息等控件的可見。
- 支持地圖交互,比如鼠標按下獲取對應位置的經緯度。
- 支持查詢路線,可設置起點位置、終點位置、路線模式、路線方式、路線方案(最少時間、最少換乘、最少步行、不乘地鐵、最短距離、避開高速)。
- 可顯示點線面工具,可直接在地圖上划線、點、矩形、圓形等。
- 可設置行政區划,指定某個城市區域繪制圖層,在線地圖自動輸出行政區划邊界點集合到js文件給離線地圖使用。
- 可添加多個覆蓋物。支持點、折線、多邊形、矩形、圓形、弧線、點聚合等。
- 函數接口友好和統一,使用簡單方便,就一個類。
- 支持任意Qt版本、任意系統、任意編譯器。
三、效果圖
四、使用代碼
void frmEcharts::loadMap()
{
timer->stop();
Echarts::Instance()->reset();
Echarts::Instance()->setHeight(ui->widget->height());
QStringList cityName, cityValue, cityPoint;
cityName << "上海" << "北京" << "成都" << "武漢" << "廈門" << "廣州";
cityPoint << "121.48,31.22" << "116.46,39.92" << "104.06,30.67" << "114.31,30.52" << "118.1,24.46" << "113.23,23.16";
Echarts::Instance()->setCityName(cityName);
Echarts::Instance()->setCityPoint(cityPoint);
Echarts::Instance()->setZoom(1.0);
//全國地圖是 china 世界地圖可以換成 world
Echarts::Instance()->setMapJsName("china");
Echarts::Instance()->setMapAreaName("china");
QString text = ui->cboxType->currentText();
if (text == "閃爍點圖") {
cityValue << "250" << "220" << "150" << "180" << "140" << "170";
Echarts::Instance()->setCityValue(cityValue);
} else if (text == "遷徙圖") {
cityValue << "1" << "0" << "0" << "0" << "0" << "0";
Echarts::Instance()->setCityValue(cityValue);
} else if (text == "儀表盤") {
} else if (text == "區域地圖") {
QStringList cityName, cityValue, cityPoint;
QString dirName = ui->cboxDir->currentText();
QString areaName = ui->cboxJson->currentText();
QString jsName = dirName + "/" + areaName;
#if 1
//根據文件獲取名稱+經緯度集合
QString jsonFile = QString("%1/areajson/%2/%3.json").arg(AppPath).arg(dirName).arg(areaName);
QString jsFile = QString("%1/areajs/%2/%3.js").arg(AppPath).arg(dirName).arg(areaName);
//QStringList infos = EchartJs::getInfoFromJson(jsonFile);
QStringList infos = EchartJs::getInfoFromJs(jsFile);
foreach (QString info, infos) {
QStringList list = info.split("|");
cityName << list.at(0);
cityValue << QString("%1").arg((qrand() % 100) + 100);
cityPoint << list.at(1);
}
#else
//固定寫死
if (areaName == "上海") {
cityName << "浦東新區" << "閔行區" << "金山區" << "奉賢區" << "嘉定區";
cityValue << "250" << "100" << "200" << "150" << "220";
cityPoint << "121.567706,31.245944" << "121.375972,31.111658" << "121.330736,30.724697" << "121.458472,30.912345" << "121.250333,31.383524";
}
#endif
Echarts::Instance()->setCityName(cityName);
Echarts::Instance()->setCityValue(cityValue);
Echarts::Instance()->setCityPoint(cityPoint);
Echarts::Instance()->setMapJsName(jsName);
Echarts::Instance()->setMapAreaName(areaName);
} else if (text == "世界地圖") {
QStringList cityName, cityValue, cityPoint;
Echarts::Instance()->setCityName(cityName);
Echarts::Instance()->setCityValue(cityValue);
Echarts::Instance()->setCityPoint(cityPoint);
Echarts::Instance()->setMapJsName("world");
Echarts::Instance()->setMapAreaName("world");
}
loadMap(ui->cboxType->currentIndex());
}
void frmEcharts::loadMap(int type)
{
QString content;
QString fileName = QString("%1/map_echarts.html").arg(AppPath);
QString url = "file:///" + fileName;
//如果采用加載內容方式則需要先設置不存儲文件
//在linux上需要用load的方式加載
#ifdef Q_OS_WIN
Echarts::Instance()->setSaveFile(false);
#else
Echarts::Instance()->setSaveFile(true);
#endif
Echarts::Instance()->setFileName(fileName);
if (type == 1) {
content = Echarts::Instance()->newChartMove("上海");
} else if (type == 2) {
content = Echarts::Instance()->newChartGauge("完成率", 65);
} else {
content = Echarts::Instance()->newChartPoint();
}
//下面為兩種方式加載網頁,如果內容為空則加載網頁文件否則加載內容
//一般為了保密建議加載內容,這樣看不到生成的網頁文件
if (Echarts::Instance()->getSaveFile()) {
#ifdef webkit
webView->load(QUrl(url));
#elif webengine
webView->load(QUrl(url));
#elif webie
webView->dynamicCall("Navigate(const QString&)", url);
#endif
} else {
QUrl baseUrl(QString("%1/").arg(AppPath));
#ifdef webkit
webView->setHtml(content, baseUrl);
#elif webengine
webView->setHtml(content, baseUrl);
#endif
}
}
void frmEcharts::on_btnSaveJs_clicked()
{
QString dirName = ui->cboxDir->currentText();
QString cityName = ui->cboxJson->currentText();
QString jsonFile = QString("%1/areajson/%2/%3.json").arg(AppPath).arg(dirName).arg(cityName);
QString jsFile = QString("%1/areajs/%2/%3.js").arg(AppPath).arg(dirName).arg(cityName);
EchartJs::saveJs(jsonFile, jsFile, cityName);
}
void frmEcharts::on_btnSaveAll_clicked()
{
ui->btnSaveJs->setEnabled(false);
ui->btnSaveAll->setEnabled(false);
qApp->processEvents();
QString dirPath = QString("%1/areajson").arg(AppPath);
QDir dir(dirPath);
if (dir.exists()) {
QStringList dirNames = dir.entryList(QDir::Dirs | QDir::NoSymLinks | QDir::NoDotAndDotDot);
ui->progressBar->setValue(0);
ui->progressBar->setRange(0, dirNames.count());
foreach (QString dirName, dirNames) {
QString strPath = QString("%1/areajson/%2").arg(AppPath).arg(dirName);
QDir path(strPath);
if (path.exists()) {
QStringList fileNames = path.entryList(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
foreach (QString fileName, fileNames) {
fileName = fileName.replace(".json", "");
QString jsonFile = QString("%1/areajson/%2/%3.json").arg(AppPath).arg(dirName).arg(fileName);
QString jsFile = QString("%1/areajs/%2/%3.js").arg(AppPath).arg(dirName).arg(fileName);
EchartJs::saveJs(jsonFile, jsFile, fileName);
}
}
ui->progressBar->setValue(ui->progressBar->value() + 1);
}
}
ui->btnSaveJs->setEnabled(true);
ui->btnSaveAll->setEnabled(true);
}
void frmEcharts::on_cboxType_currentIndexChanged(const QString &arg1)
{
if (isVisible()) {
this->loadMap();
}
}
void frmEcharts::on_cboxDir_currentIndexChanged(const QString &arg1)
{
//取出目錄下的所有文件名稱作為市
ui->cboxJson->clear();
QString dirPath = QString("%1/areajson/%2").arg(AppPath).arg(arg1);
QDir dir(dirPath);
if (dir.exists()) {
QStringList fileNames = dir.entryList(QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot);
foreach (QString fileName, fileNames) {
fileName = fileName.replace(".json", "");
ui->cboxJson->addItem(fileName);
}
}
}
void frmEcharts::on_cboxJson_currentIndexChanged(const QString &arg1)
{
if (isVisible() && ui->cboxType->currentText() == "區域地圖") {
this->loadMap();
}
}
void frmEcharts::on_horizontalSlider_valueChanged(int value)
{
if (isVisible() && ui->cboxType->currentText() == "儀表盤") {
QString js = QString("setGaugeValue(%1)").arg(value);
#ifdef webkit
webView->page()->mainFrame()->evaluateJavaScript(js);
#elif webengine
webView->page()->runJavaScript(js);
#endif
}
}