**
前言:
**
最近一直在做數據可視化方面的工作,其中平面可視化沒什麼難度,畢竟已經有很多成熟的可供使用的框架,比如百度的echart.js,highcharts.js等。還有就是3D可視化了,整體來說難度也還好,通過WEBGL技術一般的可視化效果還是很好實現,如果對於WEBGL光線渲染力不從心的話直接通過three.js來做也是很方便。
其實真正困擾我開發的是可視化項目中一般會存在很多基於地圖方面的開發工作,只要是涉及到地圖的可視化必然會跟經緯度相關聯。如果是單純獲取地圖上某個特定城市或者特定點的經緯度這個很好實現,通過 百度地圖經緯度拾取系統 便可以很方便的獲取到,但是這個系統只能是獲取單個點的經緯度,並不能根據地圖上的特定軌跡來拾取軌跡對應的經緯度信息。因爲在實際開發過程中,地圖可視化項目最多的還是在地圖上繪製軌跡的需求。舉個實際工作中遇到的需求,需要在某城市的地圖上繪製出該城市所有地鐵線路圖,並且在對應站點展示高峯流量。這個需求中特定站點的繪製相對簡單,可以通過上述講的百度地圖經緯度拾取系統來獲取,但是對應的地鐵軌跡的經緯度信息獲取就蛋疼了,在網上查詢了好久都沒能夠查詢到(可以肯定的是網上肯定有,但是我就是查不到)。
針對上面所講的困惑,我就有了想自己製作一個工具的想法,這個工具可以根據用戶在地圖上繪製的軌跡對應的將軌跡的經緯度信息保存並提供給用戶,先不說這個想法是否能夠幫助到其他人,至少能夠滿足我工作的需求。
工具原理說明:
1 用戶在工具集成地圖上繪製軌跡(點軌跡,圓軌跡,線軌跡,多邊形軌跡,四邊形軌跡);
2 工具內部調用集成地圖API獲取繪製軌跡的經緯度信息;
3 將集成地圖API返回的經緯度信息展示在工具對應的位置中,每次繪製玩一個軌跡就生成一條經緯度信息;
4 用戶通過工具提供的查看軌跡詳情按鈕可以查看經緯度信息並且可以直接複製到自己項目中使用;
5 爲了滿足項目中一個需求包含多個軌跡的可能性,因此增加了一個合併軌跡經緯度信息的功能。
集成地圖選型:
目前用戶羣體最大的兩個地圖是百度和阿里旗下的高德地圖,經過比對最終還是選擇了百度地圖,因爲百度地圖API中有提供鼠標繪製工具DrawingManager,並且使用簡單,API文檔也比較完善。
工具界面設計:
既然集成地圖選擇了百度地圖,那工具界面也就同百度地圖界面,界面效果圖具體如下:
工具實現代碼說明:
1 dom結構說明:
1.1 main-div 爲整體顯示框架;
2.2 search-frame 用於存放搜索內容;
2.3 travel-frame 用於存放軌跡;
2.4 setting-frame 用於存放地圖皮膚和鼠標繪製工具配置項內容;
2.5 allmap 用於存放百度地圖。
1 <div class="main-div">
2 <div class="search-frame">
3 <div class="search">
4 <input class="search-input" placeholder="請輸入搜索關鍵字">
5 <button class="search-btn"><i class="fa fa-search"></i></button>
6 </div>
7 <div class="search-info" style="max-height: 122px;"></div>
8 </div>
9 <!-- 軌跡 -->
10 <div class="travel-frame">
11
12 </div>
13 <!-- 配置項 -->
14 <div class="setting-frame">
15 <div class="setting-content" style="">
16 <div class="setting-list map-theme">
17 <p>地圖皮膚配置</p>
18 <div class="theme-content clearfix">
19
20 </div>
21 </div>
22 <div class="setting-list">
23 <p>地圖繪製工具參數配置</p>
24 <div class="list-content">
25 <label>邊線顏色</label>
26 </div>
27 <div class="list-content">
28 <label>填充顏色</label>
29 </div>
30 <div class="list-content">
31 <label>邊線寬度</label>
32 </div>
33 <div class="list-content">
34 <label>邊線類型</label>
35 </div>
36 </div>
37 <div class="setting-operate"><i class="fa fa-chevron-down"></i></div>
38 </div>
39 <div id="allmap"></div>
40 </div>
2 js代碼說明:
2.1 首先在代碼中引入百度地圖API js文件,鼠標操作工具css文件和js文件,具體引用代碼如下;
1 <link rel="stylesheet" href="http://api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.css" />
2 <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=您在百度申請的key值"></script>
3 <script type="text/javascript" src="http://api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.js"></script>
2.2 百度地圖初始化,地圖開啓滾輪縮放,默認展示區域爲北京。因爲實現的工具不需要展示具體點的詳情信息,所以需要禁止點擊地圖的詳情彈窗,通過設置enableMapClick = false
實現。
1 // 百度地圖初始化,其中allmap爲頁面中需要展示地圖的id值
2 var map = new BMap.Map("allmap", {
3 enableMapClick: false
4 })
5 // 開啓滾輪縮放
6 map.enableScrollWheelZoom(true);
7 // 初始化地圖默認顯示地點爲北京
8 var point = new BMap.Point(120.12, 30.16);
9 map.centerAndZoom(point, 13);
2.3 地圖初始化完成後,需要根據用戶當前所在地對應的進行地圖顯示位置切換,該操作需要獲取位置信息,需要用戶授權。
1 // 獲取當前用戶所在位置信息
2 var geolocation = new BMap.Geolocation();
3 // 獲取定位,如果獲取成功則定位到當前位置,定位不成功使用默認的位置
4 geolocation.getCurrentPosition(function (r) {
5 if (this.getStatus() == BMAP_STATUS_SUCCESS) {
6 map.panTo(r.point);
7 map.enableScrollWheelZoom(true);
8 } else {
9 layer.alert('failde' + this.getStatus());
10 }
11 }, {enableHighAccuracy: true})
2.4 鼠標繪製工具參數說明及鼠標繪製工具實例化。
1 // 鼠標繪製鞏固配置項及說明
2 var styleOptions = {
3 strokeColor: '#ff0000', // 邊線顏色。
4 fillColor: ‘#ff0000’, // 填充顏色,當該參數爲空時,圓形/多邊形/正方形將沒有填充效果。
5 strokeWeight: 1, // 邊線的寬度,以像素爲單位,默認爲1。
6 strokeOpacity: 0.8, // 邊線的透明度,取值範圍爲0~1。
7 fillOpacity: 0.6, // 填充的透明度,取值範圍爲0~1。
8 strokeStyle: 'solid' // 邊線的樣式,可選solid和dashed。
9 }
10 // 鼠標繪製工具實例化
11 var drawingManger = new BMapLib.DrawingManager(map, {
12 isOpen: false, // 表示是否開啓繪製模式
13 enableDrawingTool: true, // 是否顯示工具欄
14 drawingToolOptions: {
15 anchor: BMAP_ANCHOR_TOP_RIGHT, // 工具欄顯示在右上角
16 offset: new BMap.Size(5,5) // 工具欄偏移右上角位置
17 },
18 circleOptions: styleOptions, // 圓的樣式
19 polylineOptions: styleOptions, // 線的樣式
20 polygonOptions: styleOptions, // 多邊形的樣式
21 rectangleOptions: styleOptions, // 矩形的樣式
22 })
2.5 鼠標繪製工具樣式更改和地圖皮膚更換。鼠標繪製工具樣式更改通過重定義 styleOptions
對應參數來實現,其中邊框顏色和填充顏色需要把顏色和透明度分開,地圖皮膚切換通過 map.setMapStyle
來實現。
1 // 地圖皮膚更改代碼
2 $('.theme-list').click(function () {
3 // 獲取地圖皮膚類型
4 var themeName = $(this).data('type');
5 // 將皮膚類型保存到本地
6 localStorage.setItem('themeType', themeName);
7 // 執行更改皮膚操作
8 map.setMapStyle({
9 style: themeName
10 })
11 })
12 // 鼠標操作工具配置項更改方法
13 function changeOptionFun () {
14 var strokeColorArray = mapOption.borderColor.split(',');
15 var strokeColor = mapOption.borderColor.indexOf('rgba') != -1 ? 'rgb(' + [strokeColorArray[0].split('(')[1],strokeColorArray[1],strokeColorArray[2]].join(',') + ')' : mapOption.borderColor;
16 var strokeOpacity = strokeColorArray[3].split(')')[0];
17 var fillColor = mapOption.fillColor.indexOf('rgba') != -1 ? 'rgb(' + [fillColorArray[0].split('(')[1],fillColorArray[1],fillColorArray[2]].join(',') + ')' : mapOption.fillColor;
18 var fillOpacity = fillColorArray[3].split(')')[0];
19 // 參數更新
20 styleOptions.strokeColor = strokeColor;
21 styleOptions.fillColor = fillColor;
22 styleOptions.strokeWeight = Number(mapOption.borderWidth);
23 styleOptions.strokeOpacity = Number(mapOption.strokeOpacity );
24 styleOptions.fillOpacity= Number(mapOption.fillOpacity);
25 styleOptions.strokeStyle= Number(mapOption.borderType);
26 }
2.6 鼠標繪製工具添加軌跡繪製完成方法overlaycomplete
,該方法中執行軌跡繪製完成後保存繪製軌跡數據到 markerArray
中,對應的需要更新頁面中軌跡彈窗中的數據,軌跡新增完成後需要先輸入保存軌跡的名稱,然後才能執行以後的步驟,如果不輸入名稱默認不保存該軌跡。
1 // 鼠標繪製工具監聽事件,用於獲取繪製結果並同步繪製結果到頁面
2 var overlaycomplete = function () {
3 // 需要添加鼠標工具繪製完成之後的邏輯
4 var removeBool = true;
5 selectArray = [];
6 layer.prompt({title: '輸入軌跡名稱,並確認', formType: 3}, function(text, index){
7 layer.close(index); 9 if (e.overlay.ia) {
10 markersArray[new Date().getTime()] = {
11 location: [{
12 locationInfo: e.overlay.ia,
13 name: text
14 }],
15 name: text,
16 overlay: e.overlay
17 }
18 } else {
19 markersArray[new Date().getTime()] = {
20 location: [{
21 locationInfo: [e.overlay.point],
22 name: text
23 }],
24 name:text,
25 overlay: e.overlay
26 }
27 }
28 removeBool = false;
29 // 賦值軌跡
30 $('.travle-general b').html(Object.keys(markersArray).length);
31 // 軌跡循環
32 var html = '';
33 for (var list in markersArray) {
34 var travelNum = 0;
35 markersArray[list].location.forEach(function (item, index) {
36 travelNum += item.locationInfo.length;
37 })
38 html += '<div class="info-list clearfix">'
39 +'<div class="info-list-l">'
40 +' <div class="checkbox-bg"></div>'
41 +' <input class="checkbox" data-key=' + list + ' type="checkbox" />'
42 +' <i></i>'
43 +'</div>'
44 +'<div class="info-list-r">'
45 +' <p class="title">' + markersArray[list].name + '</p>'
46 +' <div class="info-frame clearfix">'
47 +' <p class="info">共有<span>' + travelNum + '</span>個位置經緯度信息</p>'
48 +' <button class="travel-info" data-key=' + list + '>詳情</button>'
49 +' <button class="travel-delete" data-key=' + list + '>刪除</button>'
50 +' </div>'
51 +'</div>'
52 +'</div>';
53 }
54 if (Object.keys(markersArray).length > 1) {
55 html += '<div class="combine-btn"><button>合併查看詳情</button></div>'
56 }
57 $('.travle-info').html(html);
58 });
59 }
60 // 鼠標繪製工具添加監聽事件
61 drawingManager.addEventListener('overlaycomplete', overlaycomplete);
2.7 地圖搜索功能實現,通過百度地圖API中的BMap.LocalSearch
來搜索數據,自定義setSearchCompleteCallback
方法來實現搜索後頁面數據展示的邏輯,搜索數據最多顯示十條,需要過濾掉名稱一樣的數據。
1 // 開啓百度地圖搜索功能
2 var localSearch = new BMap.LocalSearch(map);
3 //搜索成功後回調函數定義
4 localSearch.setSearchCompleteCallback(function (searchResult) {
5 // 用於存放過濾後的搜索數據
6 var filterSearchResult = [];
7 // 存放搜索數據title值,主要用於過濾重複數據使用
8 var filterSearchResultTitle = [];
9 // 循環處理獲取到的數據,過濾title重複的數據
10 searchResult.Ar.forEach(function (item) {
11 if (filterSearchResultTitle.indexOf(item.title) == -1) {
12 filterSearchResultTitle.push(item.title);
13 filterSearchResult.push(item);
14 }
// 此處需要補充代碼
15 })
16 })
17 // 搜索方法
18 function searchByStationName(keyword) {
19 localSearch.search(keyword);
20 }
2.8 已有軌跡刪除方法,軌跡刪除成功之後需要在對應的軌跡彈窗中將需要刪除的軌跡移除,並且如果地圖中有該軌跡也需要調用 map.removeOverlay
方法移除地圖中的軌跡。
1 // 刪除軌跡事件
2 $('.travel-delete').on('click', function () {
3 var element = $(this);
4 var key = element.data('key');
5 layer.confirm('軌跡刪除不可恢復,是否刪除?', {
6 btn: ['確認','取消'],
7 title: '刪除軌跡'
8 }, function(index){
9 layer.close(index);10 map.removeOverlay(markersArray[key].overlay);
11 delete markersArray[key];
12 element.parents('.info-list').remove();
13 // 重新賦值軌跡
14 $('.travle-general b').html(Object.keys(markersArray).length);
15 }, function(index){
16 layer.close(index);
17 });
18 })
2.9 查看軌跡詳情和合並查看詳情需要選中至少兩條軌跡,點擊之後會彈出軌跡詳情彈窗,會將選擇的需要合併的軌跡中的數據合併到一起展示,並且通過複製粘貼便可以使用.
1 // 合併查看詳情事件
2 $('.combine-btn').off().click(function () {
3 if (selectArray.length < 2) {
4 layer.alert('軌跡合併請至少選擇兩條軌跡');
5 return false;
6 }
7 layer.open({
8 type: 1,
9 title: '軌跡經緯度詳情(<span style="color:#ff0000;">左邊爲格式化,右邊爲未格式化</span>),使用請直接進行復制粘貼操作',
10 skin: 'layui-layer-rim', //加上邊框
11 area: ['100%', '100%'], //寬高
12 content: infoHtml
13 });
14 var _markersArray = [];
15 for (var key in markersArray) {
16 if (selectArray.indexOf(parseInt(key)) != -1) {
17 _markersArray.push(markersArray[key].location[0]);
18 }
19 }20 $('#code-content-str').html(JSON.stringify(_markersArray));
21 aceInitFun(formatJson(_markersArray).trim());
22 })
工具項目預覽及體驗地址:
基於百度地圖API實現在地圖上繪製軌跡並拾取軌跡對應經緯度工具
後話:
由於平時只有下班時間才能夠開發,所以開發這個工具前前後後花費了有將近兩週的時間,中間還有個幾次通宵的情況,如果工具對您的工作有幫助,或者您對該工具有什麼好的建議歡迎留言。