本博客文章为转载,请勿用于商业目的!
本博客文章为转载,请勿用于商业目的!

必应地图中国API入门讲座

原文地址: http://www.htchen.com/post/2.html
必应地图中国API入门讲座之一:显示地图                                       

微软必应地图中国地图API发布已经有10天了,考虑到网上现有的SDK不利于新手入门,我尝试着以简单易懂的方式给大家讲解一下VE API。希望能都对那些开发不怎么熟悉的人都能够有所帮助。
首先是两个链接,大家一定要记下来:
http://msdn.microsoft.com/zh-cn/library/aa905677.aspx(中国地图的API)
http://dev.live.com/virtualearth/sdk/全球地图API)
全球地图API是一个交互式SDK,描述的也比较全面且容易掌握,它是对中国地图API的有益补充。虽然两个API基本上是一致的,且全球地图API包含的功能更丰富,但是我们主要还是以中国地图API为准。因为考虑到中国的一些具体情况,有些功能不能开放。

下面开始第一讲的内容:显示地图。
成功显示地图是所有工作的第一步,而且也能给人很大的成就感及信心。首先,建立一个html文件,用记事本(Notepad)打开这个文件并将下面的代码粘贴到记事本,保存文件并用IE打开html文件。大功告成,你已经成功的开发出第一个地图应用如果浏览器设置了禁止运行ActiveX控件,则点击浏览器上方弹出的浮动栏,设置为允许运行本程序内容。
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

      <script type="text/javascript" src="http://dev.ditu.live.com/mapcontrol/mapcontrol.ashx?v=6.1"></script>
      <script type="text/javascript">
         var map = null;

                  
         function GetMap()
         {
            map = new VEMap('myMap');
            map.LoadMap();
         }
         
      </script>
   </head>
   <body>
      <div id='myMap' style="position:relative; width:800px; height:600px;"></div>
       <br/>
   </body>
</html>

现在我们再回头看看这段程序所包含的内容。关于HTML的语法我就不作说明了,大家可以上网找一下。
首先是<script type="text/javascript" src="http://dev.ditu.live.com/mapcontrol/mapcontrol.ashx?v=6.1"></script>,这段代码指示了我们采用的地图控件所在的URL位置及版本。切记不能做任何修改,除非微软官方发布新的版本或者更改URL地址。

然后定义了一个函数来装载地图:
         function GetMap()
         {
            map = new VEMap('myMap');
            map.LoadMap();
         }

此处调用了VEMap.LoadMap()方法。关于LoadMap()方法的更详细的说明,参见http://msdn.microsoft.com/zh-cn/library/bb412546.aspx。可以设置初始地图显示的中心位置、地图级别(全国、省、市)等等。

最后在html的body域加载GetMap函数<body>并设置地图区域的大小<div id='myMap' style="position:relative; width:800px; height:600px;"></div>

通过第一讲,我们成功的显示微软地图并对微软地图API有了初步印象。下一讲我们将介绍一些基本的操作。

 
必应地图中国API入门讲座之二:放大、缩小功能                                                               
                                                                                                   
                               
                                                                        上一讲的内容告诉大家如何显示地图,让大家对微软中国地图API有一个基本的认识。这一讲的内容我还是希望能够简单一些,主要介绍放大、缩小功能。
有些时候我们不希望通过默认的控制栏来控制地图,而是希望能够自定义放大、缩小按钮。比如在显示某公司的位置时,公司老总只希望别人能够以公司位置为中心放大、缩小地图。

所需要做的很简单,增加两个函数:放大和缩小。
     function DoZoomIn(c)
      {
         map.ZoomIn();
      }
   
      function DoZoomOut()
      {
         map.ZoomOut();
      }
然后在html boy中增加两个按钮:
     <div>
         <input type='button' value='放大' onclick='DoZoomIn();' />
         <input type='button' value='缩小' onclick='DoZoomOut();'/>
      </div>

或者,我们想直接指定地图放大的级别,我们可以另外写一个函数:
     function DoZoom()
      {
         var zoom = document.getElementById('zoomLevel').value;
         map.SetZoomLevel(zoom);
      }
然后在html body中增加一个输入框让用户输入放大级别,以及一个按钮:
     <div>
         放大级别:<input id='zoomLevel' type='text' style='width:15px;' value='10' />
         <input type='button' value='显示' onclick='DoZoom();' />
      </div>

最小放大级别为1,即显示世界地图。最大放大级别为17。此处初始值设置为10,能够显示北京全貌。
最后,完整代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

      <script type="text/javascript" src="http://dev.ditu.live.com/mapcontrol/mapcontrol.ashx?v=6.1"></script>
      <script type="text/javascript">
  var map = null;
                  
         function GetMap()
         {
            map = new VEMap('myMap');
            map.LoadMap();
         }
       function DoZoomIn(c)
        {
            map.ZoomIn();
        }
        function DoZoomOut()
        {
            map.ZoomOut();
        }
        function DoZoom()
        {
            var zoom = document.getElementById('zoomLevel').value;
     map.SetZoomLevel(zoom);
        }        
      </script>
   </head>
   <body>
      <div id='myMap' style="position:relative; width:600px; height:480px;"></div>
      <div>
         <input type='button' value='放大' onclick='DoZoomIn();' />
         <input type='button' value='缩小' onclick='DoZoomOut();'/>
      </div>
      <div>
         放大级别:<input id='zoomLevel' type='text' style='width:15px;' value='10' />
         <input type='button' value='显示' onclick='DoZoom();' />
      </div>
   </body>
</html>
必应地图中国API入门讲座之三:自定义平移功能                                       

                                       
                               
                                                                        关于平移功能,首先要说明的是必应地图API现在不可以准确的平移到以某个经纬度为中心的地图区域。因为中国有关文件规定所有的电子地图都必须经过矢量偏移,因此直接输入经纬度得到的位置是与真实位置存在一定偏差的。

本讲将展现三种平移方式:经纬度直接平移、手动平移,以及连续平移。
首先我们来看一下经纬度直接平移,我们定义一个平移函数:
     function PanLatLong(c)
      {
         var lat =  document.getElementById('txtMapLat').value;
         var lon =  document.getElementById('txtMapLon').value;
         map.PanToLatLong(new VELatLong(lat, lon));
      }
平移的经纬度从输入框获取,因此需要在html body中增加两个输入框,对应ID分别为txtMapLattxtMapLon:
      <div>
         维度:<input id='txtMapLat' style='width: 30px' type='text' value='36' />
         经度:<input id='txtMapLon' style='width: 30px' type='text' value='105' />
         <input type='button' value='经纬度平移' onclick='PanLatLong();' />
      </div>


第二个功能是手动平移,由用户输入以当前地图为中心平移量的大小。同样,我们需要定义一个函数:
      function PanXY()
      {
         var x =  document.getElementById('txtMapX').value;
         var y =  document.getElementById('txtMapY').value;
         map.Pan(x,y);
      }

我们在html body域增加两个输入框,允许用户输入平移量,ID分别为txtMapX和txtMapY:
      <div>
         X:<input id='txtMapX' style='width: 30px' type='text' value='1' />
         Y:<input id='txtMapY' style='width: 30px' type='text' value='1' />
         <input type='button' value='手动平移' onclick='PanXY();' />
      </div>


接下来我们看一下连续平移的实现方法。连续平移在很多地方可以应用,比如在线旅游,显示用户旅游线路的时候可以通过连续平移的方法直观显示用户的足迹。此处我们需要定义两个函数:开始平移和结束平移:
      function StartContinuous()
      {
         var x =  document.getElementById('txtMapXspeed').value;
         var y =  document.getElementById('txtMapYspeed').value;
         map.StartContinuousPan(x,y);
      }
      
      function EndContinuous()
      {
         map.EndContinuousPan();
      }
然后,我们在html body域增加两个按钮,分别对应开始平移和结束平移。并提供一个输入框,允许用户输入连续平移的速度:
      <div>
         X (speed):<input id='txtMapXspeed' style='width: 30px' type='text' value='1' />
         Y (speed):<input id='txtMapYspeed' style='width: 30px' type='text' value='1' />
         <input type='button' value='开始连续平移' onclick='StartContinuous();' />
         <input type='button' value='结束连续平移' onclick='EndContinuous();' />
      </div>


以上三种方法的代码可以一起贴到我们第一讲的显示地图代码中,也可以单独添加某一个方法。完整的代码我就不写出来了,免得文章显得过长,影响读者的耐心。有需要的请联系我的邮箱:acnchen@hotmail.com
必应地图中国API入门讲座之四:显示兴趣点                                       

                                       
                               
                                                                        在地图上显示一个兴趣点,这个应用可以说是最简单但是最广泛的。例如,一个公司希望在自己的主页上加上一个简单的地图显示公司所在位置。
在这一讲中我先简单介绍一下关于形状(shape)的概念:一个shape可以是点、线、多边形等。在初始化shape对象的时候,可以根据初始化函数的不同输入参数来确定shape的具体类型:VEShapeType.Pushpin,VEShapeType.Polygon,VEShapeType.Polyline。
shape的初始化举例:
var shape = new VEShape(VEShapeType.Pushpin, map.GetCenter());此处初始化一个兴趣点(pushpin)的shape
在这个初始化例子中,map.GetCenter()方法得到当前地图的中心位置经纬度,作为所要显示的兴趣点位置。我们也可以自定义一个位置:new VELatLong(39.9012, 116.3902),即:
var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(39.9012, 116.3902));
关于线、多边形的初始化我会在后面的讲座中说明。
下面我们来看一下添加兴趣点的具体实现代码,我们定义一个添加兴趣点的函数:
     function AddPushpin()
      {
          var shape = new VEShape(VEShapeType.Pushpin, new VELatLong(39.9012, 116.3902));
          shape.SetTitle('兴趣点');
          shape.SetDescription('我的兴趣点');
          map.AddShape(shape);
      }

这个函数首先初始化一个shape对象为pushpin,然后设置兴趣点的title和具体描述信息。最后,调用map类的AddShape方法在基础地图上添加shape。

同样,我们需要在html body中增加一个链接(也可以是按钮),让用户来控制增加兴趣点:
<div><a href='#' onclick='AddPushpin();'>添加兴趣点</a></div>

将上述这两段代码加到我们第一讲显示地图的代码中,就可以体验一下增加兴趣点的功能了。
当然有时候我们不希望通过用户手动添加按钮,而是在地图加载的时候自动显示一个兴趣点,这时候我们需要修改一下GetMap这个函数:
    function GetMap()
      {
         map = new VEMap('myMap');
         map.LoadMap();         
         AddPushpin()

      }
大家自己动手分别实现一下这两种方式吧!
必应地图中国API入门讲座之五:画线                                       

                                       
                               
                                                                        在必应地图上画线的功能应用也很广泛:显示从出发地到目的地的行驶路径,或者显示某一辆车的历史行驶轨迹,等等。
上一讲中我们提到shape类可以是点、线或多边形。在初始化shape类的时候,可以通过输入参数VEShapeType.Polyline来实现一个折线示例。需要注意的是,可以通过指定多个经纬度来确定一条折线。例如:
var shape = new VEShape(VEShapeType.Polyline, [new VELatLong(39.9022,116.3321), new VELatLong(39.9833,116.3423),new VELatLong(39.9946,116.3571)]);
这条折线包含了两个线段。
此外,shape类提供了许多方法来设置shape的各种属性,例如:
shape.SetLineWidth(3);     设置折线的宽度
shape.SetLineColor(new VEColor(0,150,100,1.0));     设置折线的颜色

接下来,我们定义一个画线函数来完整的实现这一功能:
function AddPolyline()
         {
            var ll = map.GetCenter();
            var lat = ll.Latitude;
            var lon = ll.Longitude;
            var shape = new VEShape(VEShapeType.Polyline, [new VELatLong(lat-0.1,lon-0.1),
                                                  new VELatLong(lat+0.1,lon-0.1),
                                                  new VELatLong(lat+0.1,lon),
                                                  new VELatLong(lat-0.1,lon),
                                                  new VELatLong(lat-0.1,lon+0.1),
                                                  new VELatLong(lat+0.1,lon+0.1)]);
            shape.SetTitle('我的折线');
            shape.SetDescription('显示一段折线');
            map.AddShape(shape);
         }

这段代码应该很好理解了,首先取屏幕中心经纬度,然后参考这个经纬度分别取6个点,确定一条5折线。

最后,我们在html body中增加一个链接来控制显示折线:
<div><a href='#' onclick='AddPolyline();'>添加折线</a></div>
是不是很简单?更多关于shape类的方法及构造函数,请参考http://msdn.microsoft.com/zh-cn/library/aa905677.aspx
必应地图中国API入门讲座之六:添加多边形                                       

                                       
                               
                                                                        作为必应地图的三项最基本应用之一,添加多边形的作用也非常广泛。例如,在物流、导航、监控领域,设置一个监控区域,或者观察目标状态的变化。如果我们学习了上两讲的内容,那么这一讲的内容应该内度并不大。
首先我们要初始化一个多边形:
var shape = new VEShape(VEShapeType.Polygon, [new VELatLong(lat,lon-0.15),
                                                   new VELatLong(lat+0.1,lon-0.05),
                                                   new VELatLong(lat+0.1,lon+0.05),
                                                   new VELatLong(lat,lon+0.15),
                                                   new VELatLong(lat-0.1,lon+0.05),
                                                   new VELatLong(lat-0.1,lon-0.05)]);

此处lat和lon为当前地图中心的纬度和经度。
可以看到,多边形的初始化参数为VEShapeType.Polygon,至少三个点确定一个多边形。
我们还可以通过shape类的各种方法来指定多边形的属性:线条粗细、颜色,填充颜色,多边形描述信息等等。这一讲我们增加一个新的内容,即多边形的描述可以支持html语法。
var infobox = "<div style='width:309px;'>You can add html codes into the info box or change the style of the info box. You can design and show any info box you want!<br>"
                    +"<a href='http://msdn2.microsoft.com/en-us/library/bb412553.aspx' target='_blank'>Click here to find out more.</a><br></div>"
                    +"<embed src='http://images.soapbox.msn.com/flash/soapbox1_1.swf' quality='high' width='309px' height='272px' wmode='transparent' type='application/x-shockwave-flash' pluginspage='http://macromedia.com/go/getflashplayer' flashvars='c=v&v=a4b53303-d58c-450e-a01d-069c9bcb5fe9' ></embed><br /><a href='http://soapbox.msn.com/video.aspx?vid=a4b53303-d58c-450e-a01d-069c9bcb5fe9' target='_blank' title='Virtual Earth - Bird&#39;s eye view and 3D'>Video: Virtual Earth - Bird&#39;s eye view and 3D</a>";

上面的代码看似很长,其实就是定义了一个包含html语法的字符串。然后通过调用shape.SetDescription(infobox)设置多边形的描述内容。

下面让我们看一下添加多边形函数的完整实现:
  function AddPolygon()
         {
            var ll = map.GetCenter();
            var lat = ll.Latitude;
            var lon = ll.Longitude;
            var shape = new VEShape(VEShapeType.Polygon, [new VELatLong(lat,lon-0.15),                                       

                       new VELatLong(lat+0.1,lon-0.05),                                    
                       new VELatLong(lat+0.1,lon+0.05),                                    
                       new VELatLong(lat,lon+0.15),                                       
                       new VELatLong(lat-0.1,lon+0.05),                                    
                       new VELatLong(lat-0.1,lon-0.05)]);
         
           shape.SetTitle("<h2>Custom Pin</h2>");
           shape.SetDescription(infobox);
           //Add the shape the the map
           map.AddShape(shape);
         }

并且在html body中增加一个控制链接:
<div><a href='#' onclick='AddPolygon();'>增加多边形</a></div>
记住,别忘了在代码中定义infobox字符串。
必应地图中国API入门讲座之七:添加实时交通信息                                       

                                       
                               
                                                                        2009年4月23日,微软必应地图中国API新增实时路况API。第一时间为大家带来这个API的应用例子。
其实,我们完全可以不用修改任何代码就能查看实时交通路况。因为地图导航工具栏就有“实时路况”这个按钮,点击一下就能看路况信息。
但是,有时候我们希望通过程序来控制是否显示实时路况信息,就有必要参考一下这个例子。秉承一贯的风格,我这个例子也很简单。
首先定义两个函数:显示实时路况ShowTraffic()及不显示实时路况ClearTraffic():
        function ShowTraffic() {
            map.LoadTraffic(true);   //显示实时路况
            map.ShowTrafficLegend(x, y); //设置实时路况图例的位置,x、y分别表示距离屏幕坐标左上角的像素位置。如果不设置的话,默认显示在屏幕右下角
            map.SetTrafficLegendText("The traffic dude!"); //设置图例的文字说明,不过好像会被默认的文字覆盖掉,我在研究一下。不影响使用
        }
        function ClearTraffic() {
            map.ClearTraffic();  //不显示实时路况
        }
然后,我们增加两个按钮来触发这两个函数:
<input id="showtraffic"  type="button" value="Show Traffic" />
<input id="cleartraffic" type="button" value="Clear Traffic"/>

大功告成,是不是很简单?
完整代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

      <script type="text/javascript" src="http://dev.ditu.live.com/mapcontrol/mapcontrol.ashx?v=6.1"></script>
      <script type="text/javascript">
  var map = null;
                  
         function GetMap()
         {
            map = new VEMap('myMap');
            map.LoadMap(new VELatLong(39.9, 116.6), 5);
        }
        function ShowTraffic() {
            map.LoadTraffic(true);
            map.ShowTrafficLegend(100, 100);
            map.SetTrafficLegendText("The traffic dude!");
        }
        function ClearTraffic() {
            map.ClearTraffic();
        }
         
      </script>
   </head>
   <body>
      <div id='myMap' style="position:relative; width:600px; height:480px;"></div>
      <input id="showtraffic"  type="button" value="Show Traffic" />
      <input id="cleartraffic" type="button" value="Clear Traffic"/>
   </body>
</html>
必应地图中国API入门讲座之八:显示驾车路线                                       

                                       
                               
                                                                        这篇文章非常值得纪念,因为我是在Google大楼里写的,呵呵。正好过来找一个朋友吃饭,等他开完会议,抽空完成这篇文章。
Google中午提供免费的午餐,居然还有扇贝,外加甜点、水果。其实也不值几个钱,但是给人感觉好像福利很不错的样子。

回到正题。显示驾车路线主要用到了Map.GetDirections(locations, options)方法。关于这个方法的详细说明,参见http://msdn.microsoft.com/en-us/library/bb877838.aspx
这儿简单说明一下Map.GetDirections(locations, options)的用法。locations参数表示整个路线经过的几个位置,至少包括起点和终点,最多可以设置25个点。options用来设置路径的选项,是一个VERouteOptions类,关于这个类的详细说明参见http://msdn.microsoft.com/en-us/library/bb877805.aspx

一个最简单的用法就是:
Map.GetDirections(["三元桥","鸟巢"], options);表示显示从三元桥到鸟巢的路径。当然我们也可以增加两个输入框,让用户输入起点和终点:
    <div>起点:<input id="txtStart" type="text" name="start" /></div>
    <div>终点:<input id="txtEnd" type="text" name="end" /></div>
这样的话,前面的方法应该改成Map.GetDirections([txtStart.value, txtEnd.value], options);
完整代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title></title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

      <script type="text/javascript" src="http://dev.ditu.live.com/mapcontrol/mapcontrol.ashx?v=6.1"></script>
      <script type="text/javascript">
  var map = null;
                  
         function GetMap()
         {
            map = new VEMap('myMap');
            map.LoadMap(new VELatLong(39.9, 116.6), 5);            
        }
        function GetDirection() {
            var options = new VERouteOptions();
            options.RouteCallback = onGotRoute;
            map.GetDirections([txtStart.value,txtEnd.value], options);
        }
        function onGotRoute(route)
        {

        }
      </script>
   </head>
   <body>
      <div id='myMap' style="position:relative; width:600px; height:480px;"></div>
    <div>起点:<input id="txtStart" type="text" name="start" /></div>
    <div>终点:<input id="txtEnd" type="text" name="end" />
    <input id="getdirection" type="button" value="Find" name="find" />
    </div>
   </body>
</html>
上面的代码中,我们用到了options的回调函数,但是并没有制定回调函数的具体操作。其实我们可以自定义一些功能,比如详细输出整个路线的文字描述。只需要把
onGotRoute()函数用下面的代码替换:
         function onGotRoute(route)
         {
             var legs = route.RouteLegs;
             var turns = "Total distance: " + route.Distance.toFixed(1) + " mi\n";
             var numTurns = 0;
             var leg = null;
             // Get intermediate legs
             for (var i = 0; i < legs.length; i++)
             {
                 // Get this leg so we don't have to derefernce multiple times
                 leg = legs;  // Leg is a VERouteLeg object
                 // Unroll each intermediate leg
                 var turn = null;  // The itinerary leg
                 for (var j = 0; j < leg.Itinerary.Items.length; j++)
                 {
                     turn = leg.Itinerary.Items[j];
                     // turn is a VERouteItineraryItem object
                     numTurns++;
                     turns += numTurns + ".\t" + turn.Text + " (" + turn.Distance.toFixed(1) + " mi)\n";
                 }
             }
             alert(turns);
         }

其实options还有很多有意思的属性可以挖掘,比如设置路径的颜色、粗细等等,朋友们自己去研究吧
必应地图中国API入门讲座之九:在地图上画圆                                       

                                       
                               
                                                                       
《变形金刚2》上映4日国内票房过亿,基本上我只能等盗版流出下载观看了。很多时候愿望很小,却不容易实现。比如我一直想写一篇博客,介绍一下在地图上画圆。这个想法来源于不止一个客户问起怎么在必应地图上实现区域搜索,比如搜索一个圆、长方形、多边形内的兴趣点。
于是衍生出来一个问题,微软必应地图为什么不提供更丰富的地图功能,比如测量两点之间的距离,画各种形状等等;
再衍生一个问题,不止一个朋友抱怨微软spcase越来越难用了,比QQ空间做的还差,为什么不这么做,为什么不那么做;
其实,如果微软什么都做了,什么都做得很好的话,就没有别的公司机会了。我常常和别人讲,在美国微软挣10块钱,要分给合作伙伴7块钱,因为我们知道很多事情应该交给合作伙伴去完成。
回到刚才的问题,微软必应地图是没有提供画圆的工具,但是我们提供了画圆的方法,或者画圆方法的方法。但是我们不一定需要在界面上给出这个功能,因为有人需要有人不需要。所以有需要的用户可以自己去实现,或者找合作伙伴去实现。
在地图上画圆更是一个数学算法问题,所以我就直接给出代码,大家直接拷贝下面的代码就行了。
function drawCircle(origin,radius)
{  
      var earthRadius = 6371;
      
      //latitude in radians
        var lat = (origin.Latitude*Math.PI)/180;
        
        //longitude in radians
        var lon = (origin.Longitude*Math.PI)/180;
        
        //angular distance covered on earth's surface
        var d = parseFloat(radius)/earthRadius;  
        
        var points = new Array();
        for (i = 0; i <= 360; i++)
        {
            var point = new VELatLong(0,0)            
            var bearing = i * Math.PI / 180; //rad
            point.Latitude = Math.asin(Math.sin(lat)*Math.cos(d) + Math.cos(lat)*Math.sin(d)*Math.cos(bearing));
            point.Longitude = ((lon + Math.atan2(Math.sin(bearing)*Math.sin(d)*Math.cos(lat), Math.cos(d)-Math.sin(lat)*Math.sin(point.Latitude))) * 180) / Math.PI;
            point.Latitude = (point.Latitude * 180) / Math.PI;
            points.push(point);
        }
        
       var circle = new VEShape(VEShapeType.Polyline, points);
       circle.HideIcon();
       searchShapeLayer.AddShape(circle);
      
       map.SetMapView(points);
    }
上面的算法只是在地图上简单的画一个圆,位置和大小都固定的。有朋友会继续问,如何在地图用鼠标画圆,圆的大小随着鼠标移动而变化。这个问题需要研究一下鼠标事件的响应函数。同学们可以把它当做课后作业吧,呵呵。
进一步探讨如何搜索一个圆形区域内的兴趣点,其实就是判断兴趣点与圆心的距离是否小于半径。所以额外给出地球上两点之间距离的计算方法:
function distance(latlong,latlong2)
    {
      var lat1 = latlong.Latitude;
      var lon1 = latlong.Longitude;
      var lat2 = latlong2.Latitude;
      var lon2 = latlong2.Longitude;
      var earthRadius = 6371;
      
      var factor = Math.PI/180;
      var dLat = (lat2-lat1)*factor;
      var dLon = (lon2-lon1)*factor;
      var a = Math.sin(dLat/2) * Math.sin(dLat/2)+Math.cos(lat1*factor)*Math.cos(lat2*factor)*Math.sin(dLon/2) * Math.sin(dLon/2);
      var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
      var d = earthRadius * c;
      
      return d;
    }
必应地图中国API入门讲座之十:多边形搜索

今天看到一个比较有意思的文章,如何在必应地图上实现多边形搜索,其实就是判断坐标系上一个点是否在多边形内。多边形搜索的用处还是很广泛的,比如搜索某个区域的酒店、饭馆。这又是一个数学问题,可以简单的用图论来表示:判断一个点A是否在多边形p中,先取一条经过A且与x轴平行的直线,然后计算直线与p的所有交点。
1)当A左边的交点数量为奇数,右边的交点数量也是奇数,A在多边形p中。
2)当A左边的交点数量为偶数,右边的交点数量也是偶数,A在多边形p外。

不过我发现这个判断方法没有考虑直线正好经过多边形某个顶点的情况,所以在算法中需要判断p的所有顶点不在直线上。

算法实现如下:
function pointInPolygon(points,lat,lon)
{
  var i;
  var j=points.length-1;
  var inPoly=false;

  for (i=0; i<points.length; i++)
  {
    if (points.Longitude<lon && points[j].Longitude>=lon
      || points[j].Longitude<lon && points.Longitude>=lon)
    {
      if (points.Latitude+(lon-points.Longitude)/
        (points[j].Longitude-points.Longitude)*(points[j].Latitude
          -points.Latitude)<lat)
      {
        inPoly=!inPoly;
      }
    }
    j=i;
  }
  return inPoly;
}

完整文章参考:http://msdn.microsoft.com/en-us/library/cc451895.aspx
必应地图API入门讲座之十一:如何在必应地图上拖拽图标                                       

                                       
                               
                                                                        上次和联想的朋友交流了一下,提起是否可以在地图上自由移动某个兴趣点的图标。以前还真没考虑过这个问题,只记得必应地图(Bing Maps)提供鼠标事件的响应功能。于是专门找了总部的专家Chris Pendleton咨询了一下,感谢CP很快就做了答复。他以前写过这样的博客,介绍如何在必应地图上drag & drop pushpin。原文地址:http://www.bing.com/community/blogs/maps/archive/2008/10/28/draggable-pushpins-with-microsoft-virtual-earth.aspx

如果以前看过我博客的朋友,应该不难读懂源代码。此处我稍微做一下解释。这个例子中增加了三个鼠标事件:
         map.AttachEvent("onmousedown",MouseHandler);   //鼠标按下事件
         map.AttachEvent("onmouseup",MouseHandler);   //鼠标按下后放开事件
         map.AttachEvent("onmousemove",MouseHandler);   //鼠标移动事件
然后,重载这三个鼠标事件的具体实现方法:
      function MouseHandler(e)
      {
         if (e.eventName == "onmousedown" && e.elementID != null)   //鼠标按下事件
         {
            dragShape = map.GetShapeByID(e.elementID); //获得所点击的对象
            return true;
         }else if (e.eventName == "onmouseup")
         {
            dragShape = null;
         }else if (e.eventName == "onmousemove" && dragShape != null)   //鼠标移动事件
         {
            var x = e.mapX;
            var y = e.mapY;
            pixel = new VEPixel(x, y);
            var LL = map.PixelToLatLong(pixel); //获得鼠标移动的位置
            dragShape.SetPoints(LL);   //将目标移动到鼠标当前位置
            return true; // prevent the default action
         }
      }

为了方便中国的用户,我把源代码中的地图控件URL改成必应地图中国平台,这样可以显示直接中文地图。完整源代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title>Drag and Drop</title>
      <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
      <!-- saved from url=(0014)about:internet -->
      <script type="text/javascript" src="
http://dev.ditu.live.com/mapcontrol/mapcontrol.ashx?v=6.2"></script>
      <script type="text/javascript">
      var map = null;
      var dragShape = null;
      function MouseHandler(e)
      {
         if (e.eventName == "onmousedown" && e.elementID != null)
         {
            dragShape = map.GetShapeByID(e.elementID);
            return true;
         }else if (e.eventName == "onmouseup")
         {
            dragShape = null;
         }else if (e.eventName == "onmousemove" && dragShape != null)
         {
            var x = e.mapX;
            var y = e.mapY;
            pixel = new VEPixel(x, y);
            var LL = map.PixelToLatLong(pixel);
            dragShape.SetPoints(LL);
            return true; // prevent the default action
         }
      }
      function GetMap()
      {
         map = new VEMap('myMap');
         map.LoadMap();
         map.AttachEvent("onmousedown",MouseHandler);
         map.AttachEvent("onmouseup",MouseHandler);
         map.AttachEvent("onmousemove",MouseHandler);
         var shape = new VEShape(VEShapeType.Pushpin, map.GetCenter());  
         shape.SetDescription("点击鼠标拖拽");         
         map.AddShape(shape);
         var shape2 = new VEShape(VEShapeType.Pushpin, new VELatLong(39.616318, 116.331278));
         shape2.SetDescription("我也可以移动的哦!");
         map.AddShape(shape2);
      }
      </script>
   </head>

   <body>
      <div id='myMap' style="position:relative; width:800px; height:600px;"></div>
      <div id='resultDiv' style="position:relative; width:400px;">Drag the pushpins around on the map.</div>
   </body>
</html>
必应地图API入门讲座之十二:如何在地图上画折线                                       

                                       
                               
                                                                        推荐一个不错的网站:http://garzilla.net/vemaps/。介绍了一些必应地图(Bing Maps)的开发例子。
在以前的讲座中曾经介绍过如何在地图上显示一段固定的折线,但是很多时候用户希望通过鼠标在地图上画折线。这个需求有很多应用场景,比如自定义一条驾车路线,或者记录旅游线路等。
在上一篇讲座中介绍了如何在必应地图上加载鼠标事件,即通过鼠标拖拽一个图标。这个讲座我们将继续使用到鼠标事件,并且增加一个键盘响应事件。这个讲座所采用的例子可以实现:用户点击“画线”按钮,开始用鼠标在地图上画折线,按ESC键终止画线。
首先定义几个变量:
         var polyline = null;  //所要画的折线
         var polylineMask = null; //画折线过程中临时产生的虚线
         var points = new Array(); //
         var maskPoints = new Array(new VELatLong(0, 0), new VELatLong(0, 0)); //
         var drawing = false; //状态指示(布尔类型)
在这个例子中,我们用到三个事件:
    // Attach the event handlers to the mouse
    myMap.AttachEvent("onmousedown", mouseDownHandler);
    myMap.AttachEvent("onmousemove", mouseMoveHandler);
    myMap.AttachEvent("onkeypress", keyPressHandler);
如果想了解必应地图事件的详细资料,请访问http://msdn.microsoft.com/en-us/library/bb412543.aspx

然后定义一个画折线的函数,当用户点击“画线”按钮的时候调用这个函数:
             function startDrawing() {
             if (polyline && !drawing) //判断polyline已经存在并且是否处于画线状态,确保将以前画的折线清除
             {
                 map.DeleteShape(polyline);
                 polyline = null;
                 points.length = 0;
             }
             map.vemapcontrol.EnableGeoCommunity(true); //关闭原有的地图鼠标响应功能
             drawing = true; //设置进入画线状态
             document.getElementById("myMap").style.cursor = 'crosshair'; //改变鼠标形状,画折线时鼠标变为十字形
             document.getElementById("draw").value = 'Press ESC to exit drawing mode'; //改变按钮所显示的文字
             document.getElementById("draw").disabled = true; //设置“画线”按钮不可按
         }
此时进入画线状态。如果点击的是折线的第一个端点,则只需要记录改点位置;否则,画出当前点与最近一次点击的点之间的线段。定义鼠标左键按下功能的具体实现:
         function mouseDownHandler(e) {
             if (drawing) {
                 currentLatLon = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY)); //记录当前鼠标所点击的位置
                 points.push(currentLatLon); //将鼠标所点击的位置保存在堆栈中
                 maskPoints[0] = currentLatLon; //将当前点作为虚线的起点
                 if (points.length > 1) {  //如果堆栈中已经记录了至少一个点,则可以画线
                     if (!polyline) { //如果还没有初始化polyline对象,则需要初始化
                         polyline = new VEShape(VEShapeType.Polyline, points);
                         polyline.HideIcon();
                         map.AddShape(polyline);
                         maskPoints[1] = currentLatLon
                     } else { polyline.SetPoints(points); } //如果已经初始化过polyline对象,则只需要根据堆栈中所记录的点的位置更新折线形状
                 }
             }
         }
在画折线的过程中,用户移动鼠标来确定下一个折线段的位置,移动过程中线段用虚线表示。鼠标移动事件的功能函数:
    //onmousemove handler
    function mouseMoveHandler(e) {
        if (drawing) {
            var loc = map.PixelToLatLong(new VEPixel(e.mapX, e.mapY)); //鼠标移动时,获取当前位置的经纬度
            if (points.length > 0){polylineMask.Show()}; //如果堆栈中已经记录了点,则显示虚线
            maskPoints[1] = loc
            polylineMask.SetPoints(maskPoints);
        }
    }
接下来要完成的工作是如何结束画线状态。此处我们通过按ESC键来结束,当然很多应用中也可以采用双击鼠标来终止。但是考虑到必应地图的双击功能时放大地图,所以推荐用ESC键来结束画线。键盘响应功能的具体实现:
    function keyPressHandler(e){
    if (drawing && e.keyCode == 27 ){  //如果当前处于画线状态,且捕捉到的键盘响应代码为27(ESC键),则终止画线状态
         drawing = false;       //结束画线状态         
         map.vemapcontrol.EnableGeoCommunity(false);
         document.getElementById("myMap").style.cursor = '';
        document.getElementById("draw").value = 'Click to begin drawing';
        document.getElementById("draw").disabled = false;
        polylineMask.Hide();
        }
本例子的完整代码比较长,就不在这儿贴出来了。有需要代码的和我联系:
posted on 2011-06-26 22:31  刘季  阅读(3744)  评论(0)    收藏  举报