這一篇,記錄一下我調用的地圖API實現的功能。下面介紹的都是一些片段的節選,不能直接復制就運行。在實現之前肯定要加載地圖,先放一個webbroser控件,然后如下:
private void Form1_Load(object sender, EventArgs e) { string str_url = Application.StartupPath + "\\最終合並版本(昨晚修改).html"; Uri url = new Uri(str_url); webBrowser1.Url = url; webBrowser1.ObjectForScripting = this; }
而為了能與JS交互,首先引入using System.Security.Permissions;,然后在namespace下必須加入兩行:
namespace WebBroser_Test_V1._0 { [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] [System.Runtime.InteropServices.ComVisibleAttribute(true)] public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { string str_url = Application.StartupPath + "\\最終合並版本(昨晚修改).html"; Uri url = new Uri(str_url); webBrowser1.Url = url; webBrowser1.ObjectForScripting = this; // timer1.Enabled = true; } }
有了上面的基礎,就可以實現以下功能了。
1.鼠標放在屏幕上移動時,實時的顯示坐標。
放入一個timer和一個StatusScrip:
private void timer1_Tick(object sender, EventArgs e) { try { string tag_lng = webBrowser1.Document.GetElementById("mouselng").InnerText; string tag_lat = webBrowser1.Document.GetElementById("mouselat").InnerText; double dou_lng, dou_lat; if (double.TryParse(tag_lng, out dou_lng) && double.TryParse(tag_lat, out dou_lat)) { toolstatus_CurrentLocation.Text ="當前坐標:"+ dou_lng.ToString("F5") + "," + dou_lat.ToString("F5"); } } catch (Exception ee) { MessageBox.Show(ee.Message); } }
放入一個button命名及代碼如下:
private void btnGetLocation_Click(object sender, EventArgs e) { if (btnGetLocation.Text == "開啟實時坐標") { timer1.Enabled = true; btnGetLocation.Text = "關閉實時坐標"; } else { btnGetLocation.Text = "開啟實時坐標"; timer1.Enabled = false; } }
JS腳本如下:
var map =new BMap.Map("allmap"); var first_locate=new BMap.Point(108.953098,34.2778); map.centerAndZoom(first_locate,15); map.enableScrollWheelZoom(true); map.addEventListener("mousemove",GetlngAndlat); function GetlngAndlat(e) {if(e.point.lng!=null) { document.getElementById("mouselng").innerHTML=e.point.lng; document.getElementById("mouselat").innerHTML=e.point.lat; } }
2.開啟測距工具(百度自己開發的)
拖一個按鈕:
//開啟測距工具按鈕 private void btnOpenDistance_Click(object sender, EventArgs e) { webBrowser1.Document.InvokeScript("openGetDistance"); }
為了加載這個工具,是需要引入百度的另一個工具庫:
JS如下:
<script type="text/javascript" src="./JScript/DistanceTool_min.js"></script> function openGetDistance() { var myDis=new BMapLib.DistanceTool(map);//map為上面已經初始化好的地圖實例 myDis.open(); }
//上面這個DistanceTool_min.js在百度的DEMO里有,我只是把它考到我的DEBUG下了,具體路徑自己解決。
3.右擊鼠標給地圖上放marker,每一個marker的icon換成小汽車,並且顯示坐標編號和坐標值,然后每放置一次,將數據存入數據庫。
//放標注
private void btnPutMarker_Click(object sender, EventArgs e) { if (radioButton1.Checked || radioButton2.Checked || radioButton3.Checked || radioButton4.Checked) webBrowser1.Document.InvokeScript("PUTANDSEND"); else { MessageBox.Show("至少選擇一項!"); } } //得到Radiobutton的值 public string setWhichCar() { if (radioButton1.Checked) return "1"; if (radioButton2.Checked) return "2"; if (radioButton3.Checked) return "3"; if (radioButton4.Checked) return "4"; return "Erro"; } //將從JS里得到的汽車數據顯示到文本框內,並且存入數據庫 public void PutIntotextBox(object markerIndex,object carNumber,object JSlng,object JSlat) { text_index.Text =markerIndex.ToString(); text_num.Text = (string)carNumber; text_lng.Text = JSlng.ToString(); text_lat.Text = JSlat.ToString(); string sql = "insert into 汽車軌跡數據 values ('"+text_num.Text+"','"+text_index.Text+"','"+text_lng.Text+"','"+text_lat.Text+"','"+DateTime.Now.ToString()+"')"; DBfunction.getcom(sql); }
JS腳本如下:
//---------------放標注,並且將JS的數據傳送給WINFORM------------ function PUTANDSEND() { map.addEventListener("rightclick",putAndsend); } function putAndsend(e) { //放標注 var p1=new BMap.Point(e.point.lng,e.point.lat); var marker = new BMap.Marker(p1,{icon:myIcon});//將標注的圖標改為小汽車 map.addOverlay(marker); marker_num++;//標注索引,這個是個全局變量 var whichCar=window.external.setWhichCar(); var label=new BMap.Label(whichCar+"號車-坐標"+marker_num+":"+ "("+e.point.lng+","+e.point.lat+")",{offset:new BMap.Size(20,-10)}); marker.setLabel(label); //給WINFORM傳值 window.external.PutIntotextBox(marker_num,whichCar,e.point.lng,e.point.lat); }
4.根據上面已經模擬的汽車歷史坐標,可以查詢具體車輛的歷史軌跡(即從數據庫里提取數據,畫軌跡)
private void btnDrawOrit_Click(object sender, EventArgs e) { string ss = "^[0-9]*$"; //正則表達式 string cc = text_whichCar.Text.Trim().ToString(); bool match = Regex.IsMatch(cc, ss); if (Convert.ToInt32(text_whichCar.Text) > 4 || !match||text_whichCar.Text.Trim().Equals(String.Empty)) // webBrowser1.Document.InvokeScript("PUTANDSEND"); { MessageBox.Show("您輸入的不是數字,或者編號不在范圍內!"); } else { string getdata_sql = "select * from 汽車軌跡數據 where 汽車編號=" + text_whichCar.Text; whichCarData(getdata_sql); } }
//從數據庫里的取出經緯度傳送給JS
public void whichCarData(string limit_sql) { OleDbDataReader DR = DBfunction.getread(limit_sql); ArrayList a = new ArrayList(); while (DR.Read()) { a.Add(DR[2]);//經度 a.Add(DR[3]);//緯度 Rows_Num++; } if (Rows_Num == 0) MessageBox.Show("該車輛,無歷史信息!"); else { for (int i = 0; i <= 2 * Rows_Num - 1; i++) { pointArr[i] = Convert.ToDouble(a[i]); } webBrowser1.Document.InvokeScript("DrawOrit1"); } } //輔助方法 //獲取計數 public int getRowsNumber() { return Rows_Num; } //根據索引獲取特定坐標 public double Getpoints(int index) { return pointArr[index]; }
JS腳本如下:
//------------從后台數據庫獲得點集合來畫軌跡(無參數版本),測試可用
function DrawOrit1() { var Array=[]; var total_num= window.external.getRowsNumber(); for(var i=0;i<=2*total_num-1;i++) { Array.push(window.external.Getpoints(i)); } var PointArr=[]; for(var i=0;i<=Array.length-1;i+=2) {//偶數索引存經度,奇數存維度 PointArr.push(new BMap.Point(Array[i],Array[i+1])); } var polyline = new BMap.Polyline(PointArr, {strokeColor:"blue", strokeWeight:6, strokeOpacity:0.5}); //定義折線 map.addOverlay(polyline); window.external.ClearRows_num();//重置窗體計數器 }
5.打開繪圖工具,這個工具可以畫直線,圓,矩形等等,其中我這里用的主要是畫圓的方法,畫好圓后,可以得到哪些車輛在這個圓內,並將其標注出來(其實就是一個預警范圍)。 //開啟畫圖工具按鈕
private void btnDrawPicture_Click(object sender, EventArgs e) { if (radio_Circle.Checked) { webBrowser1.Document.InvokeScript("drawCircle"); } else { webBrowser1.Document.InvokeScript("drawRec"); } }
//搜索當前車輛位置,返回各個車輛的坐標
public double SearchAllCars(int index) { string sql="select * from 汽車軌跡數據"; OleDbDataReader dr= DBfunction.getread(sql); ArrayList allCars = new ArrayList(); while (dr.Read()) { allCars.Add(dr[2]); allCars.Add(dr[3]); } Danger_Num = allCars.Count; double[] sendto_JS = new double[allCars.Count]; allCars.CopyTo(sendto_JS); return sendto_JS[index]; } //全局變量,返回有危險的車輛個數 public int GetdangerNum() { return Danger_Num; }
JS腳本如下:
<!--加載鼠標繪制工具--> <script type="text/javascript" src="http://api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.js"></script> <link rel="stylesheet" href="http://api.map.baidu.com/library/DrawingManager/1.4/src/DrawingManager_min.css" /> //回調獲得覆蓋物的信息(修改后的版本,已測試可用) var complete=function(e) { overlays.push(e.overlay); if (e.drawingMode == BMAP_DRAWING_CIRCLE) { //隨便賦值,刷新一遍數據庫(此方法只為演示,實際中要另考慮算法) var test= window.external.SearchAllCars(0); var circle_radius=e.overlay.getRadius();//半徑 //圓心 var circle_point=new BMap.Point(e.overlay.getCenter().lng,e.overlay.getCenter().lat); //從WINFORM里取出數據 var dangerCars=[]; var pointlen=window.external.GetdangerNum(); for(var k=0;k<=pointlen-1;k++) { dangerCars.push(window.external.SearchAllCars(k)); } var BMappoints=[];//創建百度地圖接口規定的數組 for(var j=0;j<=dangerCars.length-1;j+=2) { BMappoints.push(new BMap.Point(dangerCars[j],dangerCars[j+1])); } for(var i=0;i<=BMappoints.length-1;i++) { if(map.getDistance(circle_point,BMappoints[i])<=circle_radius) { AddMarker(BMappoints[i]);//調用添加標注版本V3.0 } } } }; //線條樣式 var styleOptions = { strokeColor:"blue", //邊線顏色。 fillColor:"blue", //填充顏色。當參數為空時,圓形將沒有填充效果。 strokeWeight: 3, //邊線的寬度,以像素為單位。 strokeOpacity: 1, //邊線透明度,取值范圍0 - 1。 fillOpacity: 0.3, //填充的透明度,取值范圍0 - 1。 strokeStyle: 'solid' //邊線的樣式,solid或dashed。 } //實例化鼠標繪制工具 var drawingManager = new BMapLib.DrawingManager(map, { isOpen: true, //是否開啟繪制模式 enableDrawingTool: true, //是否顯示工具欄 drawingToolOptions: { anchor: BMAP_ANCHOR_TOP_RIGHT, //位置 offset: new BMap.Size(5, 5), //偏離值 scale: 0.8, //工具欄縮放比例 drawingTypes : [ BMAP_DRAWING_CIRCLE, BMAP_DRAWING_RECTANGLE ] }, circleOptions: styleOptions, //圓的樣式 rectangleOptions: styleOptions //矩形的樣式 }); //添加鼠標繪制工具監聽事件,用於獲取繪制結果 drawingManager.addEventListener('overlaycomplete',complete); //drawingManager.enableCalculate(); //----------------------公用方法,用元素id獲取元素的值------------------- function $(id){ return document.getElementById(id); } //------------------畫矩形,讓WINFORM調用--------------- function drawRec(){ drawingManager.setDrawingMode(BMAP_DRAWING_RECTANGLE);} //------------------畫圓,讓WINFORM調用---------------- function drawCircle(){ drawingManager.setDrawingMode(BMAP_DRAWING_CIRCLE);} //------------------清除所有已畫圖形,讓WINFORM調用-------------------- function clearAll() { for(var i = 0; i < overlays.length; i++){ map.removeOverlay(overlays[i]); } overlays.length = 0 }
這個功能比較復雜,必須要加入前兩行的庫連接才可以。因為畫圓可以得到圓心和半徑,所以我只需要從數據庫里取出點,然后一一測量其與圓心的距離,然后和半徑比較,只要小於半徑則就在圓內標注。起初頭讓我畫矩形,畫矩形的DEMO如下:
//回調獲得覆蓋物信息,未使用該版本 var overlaycomplete = function(e){ overlays.push(e.overlay); var result = ""; result += e.drawingMode + ":"; if (e.drawingMode == BMAP_DRAWING_CIRCLE) { var circle_radius=e.overlay.getRadius(); var circle_point=new BMap.Point(e.overlay.getCenter().lng,e.overlay.getCenter().lat); alert(map.getDistance(circle_point,tests[1])); for(var i=0;i<3;i++) { if(map.getDistance(circle_point,tests[i])<=circle_radius) { AddMarker(tests[i]); } } alert(result); } if (e.drawingMode == BMAP_DRAWING_POLYLINE || e.drawingMode == BMAP_DRAWING_POLYGON || e.drawingMode == BMAP_DRAWING_RECTANGLE) { result += ' 所畫的點個數:' + e.overlay.getPath()[1].lng; alert(result); } };
這里是修改的百度DEMO,其中有一行result += ' 所畫的點個數:' + e.overlay.getPath()[1].lng;在百度原有的demo里是這樣寫的result += ' 所畫的點個數:' + e.overlay.getPath().length;只會返回一個數據,我仔細看了下函數名,getPath(),而且還有length的屬性,那么 肯定是數組,而且是返回的邊或者點的個數,而邊一定是由點組成的,根據之前的Ployline函數可以推測,這個函數必定是一個存放多邊形點的數組,那么 我就試了試e.overlay.getPath()[1].lng,看能不能取到某個點的經度值,果然不出我所料,可以的,當時興奮了好一陣子,有了這個 方法,矩形的四個點就都能記錄,那么就可以跟數據庫里取出的點直接進行經緯度比較,也可以標注預警范圍,不過還是沒有用圓方便。
由於時間確實很緊,手頭還有事要做,只能寫到這里了,歡迎交流,噴也行,哈哈。