65.9K
CodeProject 正在变化。 阅读更多。
Home

使用纯 JavaScript 的 Microsoft VEMap

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.95/5 (41投票s)

2009年9月29日

CPOL

14分钟阅读

viewsIcon

4755132

downloadIcon

1646

本文将通过示例指导您在几分钟内创建并嵌入 Microsoft Map 到您的网站中。旨在提供有关如何使用 JavaScript 库嵌入自定义地图的基本知识。

目录

引言

在我写了关于 Google Maps 的热门文章两年后,我每天都会收到很多回复/建议。我尽力提供了支持。在此过程中,我发现很多人希望我以同样的方式撰写关于 Microsoft Map 的文章,就像我为 Google 做的那样。当我搜索 Bing Maps API 时,我很难找到提供关于如何开始使用它的良好且精确知识的链接。因此,我想为您创建这篇文章,以便所有想使用 Microsoft Maps 的人都能受益。我试图让它最简单易懂,但我很期待看到您的回复和建议。我承认这篇文章很大程度上受到了 MSDN 的启发,因为我对 Bing 本身没有足够的经验。我的目的是将所有必要的内容整合到一个主题中。

如果您想使用 Google Maps 而不是 Microsoft Maps,您可以参考

Microsoft 推出了 Bing Map 服务,提供在线地图服务,使用户能够创建自定义地图并在他们自己的应用程序中分享位置信息。地图服务还提供卓越的 API 来搜索位置、对特定位置进行地址编码、在地图上绘制自定义形状、与用户互动等。

地图控件类型

Use_of_VEMap/img.jpg

Microsoft Map 服务为我们提供了两种创建地图控件的选项:

  1. Microsoft Bing Map 控件 SDK
  2. Microsoft Bing Web 服务 SDK

在这两种过程中,当客户端请求服务器时,服务器从 live.com 获取数据并将其发送回客户端。因此,即使在 LAN 中工作,客户端也需要始终连接到互联网才能从 Live 服务器获取在线数据。

Bing 地图控件 SDK

该 SDK 提供 JavaScript API 服务,可以免费添加到网站并开始使用。该 API 提供了许多 JavaScript 类,可以使用它们来创建地图。由于它仅在客户端使用 JavaScript 工作,因此您可以在任何您喜欢的编程语言中使用此服务(例如 JSP、PHP、ASP 等)。

Bing 地图 Web 服务 SDK

Web 服务 API 是使用 Windows Communication Foundation 实现的可编程 SOAP 服务。您可以使用添加 Web 服务引用时自动生成的类库。您可以将 Web 服务集成到您的网站或 WPF 客户端,并在连接到 Internet 时获取图像数据。

在本文中,我将讨论 Bing Map 控件 SDK,这是一个 JavaScript 库。我将提供示例,说明如何更好地利用 Virtual Earth Map 控件在您的网站中。

创建您的第一个地图

这可能对您来说是最令人兴奋的。让我们在网页中创建最简单的地图。我只使用了普通的 HTML 代码来让您更好地理解并使其对所有人都有用。

要创建地图,请按照以下步骤操作:

  1. 在页面顶部添加 Doctype 声明。
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    这非常有用,因为 VEMap 需要 Transitional Dtd。
  2. <head> 部分,添加
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    Microsoft 建议为显示 VEMap 的 Web 应用程序使用 UTF-8 字符集。
  3. 在标题部分,添加下载 JavaScript 文件的 JavaScript 声明,以获取图像数据。
    <script charset="UTF-8" type="text/javascript"
    src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us">
    </script> 
    http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2&mkt=en-us 是主要 JavaScript 文件,应将其添加到您的网页以使用 VEMap 类。

     

    注意:您必须始终使用此链接调用 JavaScript。您不能将 JavaScript 文件保存到您的服务器,然后尝试从中创建地图。

  4. 添加一个包含图像数据并绘制地图的容器。最好使用 Div
    <div id="myMap" style="position:relative; width:400px; height:400px;"></div>
    地图将显示在 div 内部。

现在,将所有这些放在一起,我们得到了这个页面:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>My First Map</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

    <script type="text/javascript" 
           src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2">
    </script>
    <script type="text/javascript">
         var map = null;
         var LA = new VELatLong(34.0540, -118.2370, altitude, VELatLong.RelativeToGround);
         function getMap()
         {
            var myMap = document.getElementById("myMap");
            myMap.style.display='';
            map = new VEMap('myMap');
            map.LoadMap(LA, 14, VEMapStyle.Road, false, VEMapMode.Mode2D, true, 1);
         }
    </script>

</head>
<body>
    <div id="myMap" style="position: relative; width: 400px; height: 400px; display:none;">
    </div>
    <input type="button" onclick="getMap();" value="Show Map" />
</body>
</html>

Use_of_VEMap/1.jpg

在这里,我们创建了一个 Button,它将直接加载地图。现在,让我们讨论代码中使用的几个函数:

  • VEMap(divelement):这将把 Map 加载到 div 元素中。div 元素的 Id 被传递给构造函数。
  • VELatLong(latitude, longitude, altitude, altitudemode):这将返回一个 GeoPoint 对象,该对象应传递给 LoadMap。您可以使用 VELatLong 定义任意数量的 GeoPoint。参数如下:
  1. Latitude:地球上单个点的 Latitude
  2. Longitude:地球上单个点的 Longitude
  3. Altitude:它定义了地球上一个点的高度。这是可选的,默认值为 0。
  4. AltitudeModeAltitudemode 定义了高度的表示方式。Altitudemode 可以是 VEAltitudeMode.DefaultVEAltitudeMode.AbsoluteVEAltitudeMode.RelativeToGround
  5. 这是可选的,默认值是 VEAltitudeMode.DefaultAltitudeMode 在处理 Mode3D(将在后续章节讨论)时非常有用。

最后,我们调用了 map.LoadMap(point, zoom, style, fixed, mode, showSwitch, tileBuffer)。这将加载地图,并以指定的 VELatLong 点为中心。

  1. VELatLong:表示地图将居中的全局点。
  2. Zoom:表示缩放级别。范围可以是从 1 到 19。默认值为 4。
  3. Style:指定要显示的地图样式。该值可以是:
    • Road (路况)
    • Shaded (阴影)
    • Aerial (航空)
    • 混合
    • Oblique (倾斜)
    • Birdseye (鸟瞰)
    • BirdseyeHybrid (鸟瞰混合)
    您可以逐一尝试。其中每个都可以从 UI 中更改。

     

  4. Fixed:指定地图是否可以在运行时由用户更改。默认值为 false
  5. Mode:指定地图是应该以 Mode2D 还是 Mode3D 模式加载。默认为 2D。

    注意:Mode3D 需要浏览器安装适当的插件,否则地图将无法正确显示。

  6. ShowSwitch:定义是否在地图上显示地图模式切换按钮。
  7. TileBuffer:指定将使用多少瓦片缓冲区来平滑地图导航。

添加图钉

图钉用于在地图上指示地理位置。我们可以根据需要在地图上添加任意数量的图钉。当区域动态查看时,地图将显示图钉。让我们看下面的代码:

 function AddPin()
 {
     // Add a new pushpin to the center of the map.
     pinPoint = map.GetCenter();
     pinPixel = map.LatLongToPixel(pinPoint);
     var pin = map.AddPushpin(pinPoint);
     pin.SetTitle("First Pin <span style=color:red>Demo Title<>/span>");
     pin.SetDescription("This comes to the <b>description</b> of pushpin.");
     pin.SetCustomIcon("<img src='logo.jpg' />");
     pin.SetMoreInfoURL("http://dotnetricks.blogspot.com");
}

Use_of_VEMap/2.jpg

当调用 map.GetCenter() 时,图钉将添加到地图的中心。map.GetCenter() 返回一个 VELatLong 对象,指向地图的中心。将其传递给 LatLongToPixel(VeLatLong) 以获取实际的 VEPixel 对象。我们需要将此对象传递给 AddPushpin 以将图钉添加到该点。

返回的 Pushpin 对象可以使用 SetTitle 设置 Title,并使用 SetDescription 函数设置 Description。您可以看到我在 SetDescriptionSetTitle 中使用了 HTML。

SetCustomIcon 用于更改默认图钉图标。SetMoreInfoUrl 创建一个 ...,它会打开一个新窗口。

Use_of_VEMap/4.jpg

我们也可以使用以下方法设置图钉的整个 HTML 内容:

var icon = "<div style='font-size:12px;font-weight:bold;
              border:solid 2px Black;background-color:Aqua;width:50px;'>Custom</div>";

var spec = new VECustomIconSpecification();
spec.CustomHTML = icon;
spec.Image = 'Airplane1.png'

pin.SetCustomIcon(spec);

在这里,我使用了 VECustomIconSpecification 类来定义图标的自定义 HTML。

您可以 在此处 阅读有关 VECustomIconSpecification 的更多信息。

为地图添加形状

我们可以为地图添加自定义形状。我们可以使用 VEShape 类在我们的地图上创建自定义形状。

我们可以根据 VEShapeType 枚举为地图添加不同的形状。它支持的形状有:

  1. Pushpin:用于在地图上放置一个 Pushpin
  2. PolylinePolylines 是地图上的自由绘制线条。
  3. Polygon:它们是点之间的边界区域。

Polyline

折线可以使用 VEShape 类创建。让我们看一个例子:

var polyline = new VEShape(VEShapeType.Polyline,
  [
    new VELatLong(39.73676229957947, -104.710693359375),
    new VELatLong(39.71563813479633, -104.25476074218751),
    new VELatLong(39.26628442213065, -103.74389648437501),
    new VELatLong(39.26203141523748, -103.5406494140625),
    new VELatLong(39.32579941789296, -102.04101562500001)
  ]);

polyline.HideIcon();
polyline.SetLineColor(new VEColor(0,255,0,1));
polyline.SetFillColor(new VEColor(0,0,0,0));
polyline.SetLineWidth(5);
map.AddShape(polyline);

上面的代码将在地图上创建一条折线,该折线跨越指定的点。在这种情况下,HideIcon 很重要,否则它会在折线的起始点放置一个不必要的图钉图标。SetLineColor 指定由 VEColor 生成的 RGB 颜色。SetFillColor(对于折线是不必要的)指定用于填充折线的颜色,而 SetLineWidth 指定在地图上绘制的线的宽度。

Polygon

另一方面,多边形提供了一个封闭的边界区域。您可以使用以下代码:

var polygon = new VEShape(VEShapeType.Polygon,
  [
    new VELatLong(41,-102),
    new VELatLong(37,-102),
    new VELatLong(37,-109),
    new VELatLong(41,-109)
  ]);

polygon.HideIcon();
polygon.SetLineColor(new VEColor(255,0,0,1));
polygon.SetFillColor(new VEColor(0,0,0,0));
polygon.SetLineWidth(5);

这将生成一个带有填充颜色的 Polygon 区域。代码与折线完全相同。由于我们没有为 SetFillColor 指定颜色,因此封闭区域将是透明的。

地址编码

我们可以使用地理编码来查找位置。在 6.2 版中,通过引入 Find 函数,地理编码变得更加容易。您可以使用 VEMap 控件的 Find 函数从地址获取地理位置点的信息。让我们看一下它的原型:VEMap.Find(what, where, findType, shapeLayer, startIndex, numberOfResults, showResults, createResults, useDefaultDisambiguation, setBestMapView, callback);

  1. What:搜索的业务实体名称。
  2. Where:指定要查找地址的参数。
  3. FindType:目前,它只支持 VEFindType.Businesses。所以我们将其设置为 null
  4. ShapeLayer:这代表 VEShapeLayer 的对象。我们将在后面的章节讨论如何创建图层。暂时,我们将其设置为 null
  5. StartIndex:结果的起始索引的可选参数。
  6. numberOfResults:搜索返回的结果数量。
  7. showResults:一个布尔值,指定是否在地图上显示结果。
  8. createResults:为指定 What 的位置创建一个图钉。如果 whatnull,则忽略。
  9. useDefaultDisambiguation:指定当 statecountrycity 等存在歧义时是否出现对话框。
  10. setBestMapView:在找到搜索结果时自动设置最佳地图视图。
  11. Callback:在成功完成搜索操作后将被调用的 callback

现在让我们看看代码:

         function StartGeocoding( address )
         {
            myMap.Find(null, address,  null, null, null, null, null, null null, null,
             GeocodeCallback);
         }
        function GeocodeCallback (shapeLayer, findResults, places, moreResults, errorMsg)
        {
           // if there are no results, display any error message and return
           if(places == null)
           {
              alert( (errorMsg == null) ? "Address not found!!!" : errorMsg );
              return;
           }

           var bestPlace = places[0];
           
           // Add pushpin to the *best* place
           var location = bestPlace.LatLong;
           
           var newShape = new VEShape(VEShapeType.Pushpin, location);
           
           var desc = "<b>Latitude:</b> " + 
                          location.Latitude + "<br><b>Longitude:</b>" 
                          + location.Longitude;
           newShape.SetDescription(desc);
           newShape.SetTitle(bestPlace.Name);
           myMap.AddShape(newShape);
        }

Use_of_VEMap/16.JPG

因此,如果我们调用 StartGeocoding("Kolkata"),它会在纽约市上放置一个标记。在 GeocodeCallback 函数中,我创建了一个 VEShape,并在最佳结果位置放置了一个图钉。如果未找到结果,则会出现消息框 "Address not Found!!!"

添加图层

我们可以在地图中创建图层。我们使用 VEShapeLayer 来创建地图上的多个图层。这将使我们能够对相关信息(例如绘图、图钉等)进行分组,以便可以轻松地以编程方式隐藏和显示它们。基本上,它充当所有类型形状的容器。

过程很简单。创建一个 VEShapeLayer 类,创建 VEShape 对象。使用 AddShape 方法将 Shape 对象添加到 Layer 对象中。最后,在所有形状都添加到 Shape Layer 后,我们使用 VEMap 对象的 AddShapeLayer 将 Layer 添加到地图中。

我们可以使用 Layer 对象的 ShowHide 方法以编程方式使图层可见或不可见。您还可以使用 Layer 对象的 GetShapeByIndexGetShapeByIDDeleteShapeDeleteAllShapes 来在将其添加到地图后对其进行操作。

现在让我们看看下面的代码:

//create the layer
var layer = new VEShapeLayer();

//add a pushpin
var pin = new VEShape(VEShapeType.Pushpin, new VELatLong(39.73, -105));
pin.SetTitle("Goes to Title of the Pushpin");
pin.SetDescription("Goes as Description.");
var icon = "<div style='font-size:12px;font-weight:bold;border:solid 2px 
Black;background-color:Aqua;width:50px;'>My Custom Pushpin</div>";
pin.SetCustomIcon(icon);
pin.SetPhotoURL("http://yourserver/images/mypicture.jpg");
layer.AddShape(pin);

//add a polygon
var polygon = new VEShape(VEShapeType.Polygon,
  [
    new VELatLong(41,-102),
    new VELatLong(37,-102),
    new VELatLong(37,-109),
    new VELatLong(41,-109)
  ]);
polygon.HideIcon();
polygon.SetLineColor(new VEColor(255,0,0,1));
polygon.SetFillColor(new VEColor(0,0,255,0));
polygon.SetLineWidth(5);
layer.AddShape(polygon);

//Add a polyline
var polyline = new VEShape(VEShapeType.Polyline,
  [
    new VELatLong(39.73676229957947, -104.710693359375),
    new VELatLong(39.71563813479633, -104.25476074218751),
    new VELatLong(39.26628442213065, -103.74389648437501),
    new VELatLong(39.26203141523748, -103.5406494140625),
    new VELatLong(39.32579941789296, -102.04101562500001)
  ]);
polyline.HideIcon();
polyline.SetLineColor(new VEColor(0,255,0,1));
polyline.SetFillColor(new VEColor(0,0,255,0));
polyline.SetLineWidth(5);
layer.AddShape(polyline);

map.AddShapeLayer(layer);
}

这段代码看起来与其他代码非常相似,唯一的区别是,我们使用 VEShapeLayer 添加了一个新图层,并将所有形状都添加到了该图层而不是直接添加到地图。此外,我还展示了如何仅使用 HTML 创建 CustomPin。您可以使用 SetCustomIcon 为您的地图生成自定义图钉。SetPhotoURL 函数将在描述窗格中添加一个图像。您还可以使用 ClearInfoBoxStyle / SetInfoBoxStyle 方法来自行绘制自定义信息框。

从外部源导入数据到地图

Virtual Earth Maps 内置了从 3 种链接导入数据的功能:

  1. 使用 Windows Live 的形状集合:您可以在与您的 Live 网站关联的画板上创建形状。这些数据可以很容易地用于您的网站,以绘制带有标题和描述的形状。操作步骤如下:
    • 打开 Bing 网站
    • 绘制自定义地图控件。请记住勾选“共享地图”复选框。
    • 从共享链接获取 CID。我的例子是 BAFA39A62A57009C!227
    • 使用 VeShapeSourceSpecification 绘制地图。
  2. 使用 GeoRSS 的形状:您可以使用 GEORss feed 来生成自定义地图图层。
  3. 使用 KML feed 的形状:KML feed 也可以轻松用于生成您的自定义形状图层。

Use_of_VEMap/6.jpg

让我们看代码:

var layer = new VEShapeLayer();
   var veLayerSpec = new 
       VEShapeSourceSpecification(VEDataType.VECollection,"BAFA39A62A57009C!227", layer);
   map.ImportShapeLayerData(veLayerSpec);

在这里,我们使用了 VEShapeSourceSpecification 来生成自定义形状图层。VEDataType 可以有 3 种类型:

  1. VEDataType.VECollection:指定如果 datasource 是 Live Scratchpad feed。我使用了此资源来显示地图。
  2. VEDataType.GeoRSS:指定如果 datasource 是一个链接,该链接对应于 GEORSS Feed。
    var veLayerSpec = new VEShapeSourceSpecification(VEDataType.GeoRSS, 
                                  "https:///GEOFeeds/myfeed.xml", layer);
    GeoRSS feed 的模式定义是:
     <?xml version="1.0" encoding="utf-8"?>
    <rss xmlns:georss="http://www.georss.org/georss" version="2.0">
      <channel>
        <title>My Map</title>
        <link>http://www.bing.com</link>
        <description>This is custom map created by Abhishek Sur</description>
        <language>en-in</language>
        <item>
    
          <title>Kolkata</title>
          <link>http://www.bing.com/?cid=BAFA39A62A57009C!227</link>
          <description>This is called City of Joy<br>Click 
              <a href='www.indiarocks.com'>here</a> for more information.</description>
          <guid isPermaLink="false">65c45d4e4c933e6c</guid>
    
          <pubDate>Tue, 29 Sep 2009 22:24:39 GMT</pubDate>
          <georss:point>22.2280904167845 86.044921875</georss:point>
        </item>
        <item>
    
          <title>Kolkata</title>
          <link>http://www.bing.com/?cid=BAFA39A62A57009C!227</link>
          <description>This is called City of Joy<br>Click 
            <a href='www.indiabuilds.com'>here</a> for more information.</description>
          <guid isPermaLink="false">65c45d4e4c933e6c</guid>
    
          <pubDate>Tue, 29 Sep 2009 22:24:39 GMT</pubDate>
          <georss:polygon>22.816694126899844 86.044921875 25.423431426334236 
          88.24218750000001 26.056782885778812 81.73828125 22.044913300245675 
          83.759765625 21.105000275382054 85.16601562500001 21.596150576461447 
          87.05566406250001 22.532853707527103 87.97851562500001 22.167057857886142 
          88.81347656250001 23.22115498184656 88.59375 23.704894502324887 
          87.93457031250001 24.587090339209624 87.451171875 
          24.186847428521233 89.9560546875 23.584126032644097 89.12109375 
          22.816694126899844 86.044921875</georss:polygon>
        </item>
        
    这里,georss 可以是 3 种类型:georss:pointgeorss:polylinegeorss:polygon

    您可以使用服务器中的数据动态生成 GeoRSS。为此,创建一个 httphandler 并直接创建响应。记住使用 ContentType=application/xml;

  3. VEDataType.ImportXML:指定如果 datasource 中指定了 KML 数据。
    var veLayerSpec = new VEShapeSourceSpecification(VEDataType.ImportXML, 
                       "https:///kml/myXML.xml", layer);

Use_of_VEMap/7.jpg

因此,我们可以看到地图已成功导入到上面的图片中。

处理事件

Map 进行事件处理是构建地图最重要的一节。VEMap 对各种事件做出响应,从普通的键盘事件开始,它响应拖放、鼠标单击、滚轮移动等,也响应自定义 Map 事件(如果已附加)。

处理事件非常容易。您只需要编写一个回调函数,当事件触发时会自动调用该函数。然后使用 AttachEvent 注册事件。

map.AttachEvent(eventname, functionname) 

让我们看看代码:

         var map = null;
         var loc = new VELatLong(41.0540, -102.2370);
         function getMap()
         {
            var myMap = document.getElementById("myMap");
            myMap.style.display='';
            map = new VEMap('myMap');
            map.LoadMap(loc, 9, VEMapStyle.Road, false, VEMapMode.Mode2D, true, 1);
            //create a polygon
            var polygon = new VEShape(VEShapeType.Polygon,
              [
                new VELatLong(41, -102),
                new VELatLong(37, -102),
                new VELatLong(37, -109),
                new VELatLong(41, -109)
              ]);
            polygon.SetLineColor(new VEColor(255, 0, 0, 1));
            polygon.SetFillColor(new VEColor(0, 255, 0, 0));
            polygon.SetTitle("This goes to title");
            polygon.SetDescription("This goes to Description");
            polygon.SetLineWidth(5);

            map.AddShape(polygon);
            map.AttachEvent("onclick", MouseHandler);
            map.AttachEvent("ondoubleclick", MouseHandler);
            map.AttachEvent("onmousedown", MouseHandler);
            map.AttachEvent("onmouseup", MouseHandler);
            map.AttachEvent("onmousewheel", MouseHandler);
            
        }
        function MouseHandler(e) {
                var msg = "Mouse: ";
                msg += e.eventName;
                if (e.eventName == "onclick") {
                    if (e.leftMouseButton)
                        msg += "left";
                    else if (e.rightMouseButton)
                        msg += "right";
                    else
                        msg += "middle"; ;
                }

                msg += " Clicked at ";
                msg += "X:" + e.mapX + "  Y:" + e.mapY + " with ";
                msg += " Shift: " + e.shiftKey;
                msg += " Ctrl: " + e.ctrlKey;
                msg += " Alt: " + e.altKey;
                if (e.elementID != null) { //Gets in when an element generates an event
                    msg += e.elementID + "<br>";
                    var shape = map.GetShapeByID(e.elementID);
                    msg += "Title: " + shape.GetTitle() + " and ";
                    msg += "Description: " + shape.GetDescription() + "<br>";
                }
                else 
                    msg += "map";
                document.getElementById("resultDiv").innerHTML = msg;
            }

Use_of_VEMap/5.jpg

在上面的代码中,我添加了几个事件处理程序,称为 onclickondoubleclickonmousedown... 每个都调用 MouseHandler。在任何 mouseeventhandler 中,我们都有一个隐式对象 e。我们可以使用 e.eventName 来获取触发事件的事件。e.mapX, e.mapY 代表事件生成的地图的坐标点。e.elementID 获取区域内(如果有)的绑定元素,e.zoomLevel 定义地图的当前缩放级别等。在这里,我们获取了绑定的 Polygon 并获取其 Titledescription 向您展示。

处理 3D 地图

要处理 3D 模式,您需要安装 Virtual Earth 3D 插件。每当您单击主导航菜单上的 3D 按钮时,3D 插件都会自动启动。

Use_of_VEMap/8.jpg

安装 3D 插件后,您还可以安装名为 3dVIA 的 3D 模型创建软件。它允许您直接在地图上创建自定义对象,您以后可以使用 ImportShapeLayerData 非常轻松地将其导出或导入到您的网站。

Use_of_VEMap/9.jpg

安装成功后,尝试创建您的第一个 3D 地图。

为了处理 3D 地图,我们需要将地图模式更改为 3D。使用代码 VEMap.SetMapMode(VEMapMode.Mode3D) 将以 3D 模式加载地图。创建 3D 地图的过程与我们在 2D 中处理的方式几乎相同。假设我们以 Pushpin 为例。

  var pin = new VEShape(VEShapeType.Pushpin,new VELatLong(47.62048276634572,-122.34932886660015));
  map.AddShape(pin);  

Use_of_VEMap/10.jpg

我们可以使用 SetAltitude 方法设置图钉的高度。

  var pin = new VEShape(VEShapeType.Pushpin,new VELatLong(47.62048276634572,
                -122.34932886660015));
  pin.SetAltitude(250);
  pin.SetAltitudeMode(VEAltitudeMode.Absolute);
  map.AddShape(pin); 

如果我们指定 VEAltitudeMode.DefaultVEAltitudeMode.RelativeToGround 作为 Altitudemode,那么高度是从 Ground 设置的,就像下面的图片一样:

Use_of_VEMap/11.jpg

上图显示了如何使用高度改变图像。

您可以使用 3DVIA 为地图创建自定义 3D 模型。访问 bing.com/maps [^],切换到 3D 视图,然后转到 collections 菜单,接着单击“Open your collections”,然后单击房子图标或右键单击一个位置,然后单击“Add 3D model”。

Use_of_VEMap/12.jpg

创建 3D 模型后,使用相同的过程来使用它:

var veLayerSpec = new VEShapeSourceSpecification(VEDataType.VECollection, 
           "E7DBA9A4BFD458C5!113", layer);
map.ImportShapeLayerData(veLayerSpec);

整合所有元素

最后,让我们创建一个包含所有最重要元素的网站。为了演示,我为地图创建了一个自定义菜单,允许您执行最重要的操作。让我们看看下面的代码:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>

<style type="text/css">
  ul, li{margin:0;padding:0;}

  ul.pmenu {
    position:absolute;
    margin: 0;
    padding: 1px;
    list-style: none;
    width: 150px; 
    border: 1px solid #ccc;
    background:white;
    display:none;
    z-index:10;
  }

  ul.pmenu li {position: relative;}

  ul.pmenu li ul {
    position: absolute; 
    left: 150px; 
    top: 0;
    display: none;
    z-index:10;
  }

  ul.pmenu li a {
    display: block;
    text-decoration: none;
    color: black;
    padding: 2px 5px 2px 20px;
  }

  ul.pmenu li a:hover {
    background:#335EA8;
    color:white;
  }

  ul.pmenu li a.parent {
    background:url('drop_down_triangle.gif') no-repeat 140px 4px;
  }
  ul.pmenu li a.parent:hover {
    background:#335EA8 url('drop_down_triangle_hover.gif') no-repeat 140px 4px;
  }


  * html ul.pmenu li { float: left; height: 1%; }
  * html ul.pmenu li a { height: 1%; }
  * html ul.pmenu li ul {left:147px;}


  ul.pmenu li:hover ul, ul.pmenu li.over ul { display: block; }
  ul.pmenu li ul{left:150px;}

</style>

<script src="http://ecn.dev.virtualearth.net/mapcontrol/mapcontrol.ashx?v=6.2"></script>
<script>

   var map;
   var shape;
   var mapx, mapy;
  function hidePopupMenu()
  {
    var menu = document.getElementById('popupmenu').style.display='none';
  }

  function showPopupMenu(e)
  {
    var menu = document.getElementById('popupmenu');
    if (e.rightMouseButton)
    {
        var latlong = map.LatLongToPixel(new VELatLong(e.mapX,e.mapY));
        var x = map.GetLeft();
        var y = map.GetTop();
        mapx = e.mapX;
        mapy = e.mapY;
        
        menu.style.display='block'; //Showing the menu
        menu.style.left = e.mapX + x; //Positioning the menu
        menu.style.top = e.mapY + y;
        if(e.elementID)
          shape = map.GetShapeByID(e.elementID);
    }
    else
    {
        hidePopupMenu();
    }
  }

  function GetMap()
  {
    map = new VEMap('myMap');
    map.LoadMap();

    map.AttachEvent('onclick', showPopupMenu);
    prepMenu();
  }

  function prepMenu()
  {

    navRoot = document.getElementById("popupmenu");
    var items = navRoot.getElementsByTagName('li');
    for (i=0; i<items.length; i++)
    {
      node = items[i];
      if (node.nodeName=="LI")
      {
      node.onmouseover = function()
      {
        this.className+=" over"; //Show the submenu
      }
      node.onmouseout=function()
      {
        if (this.className.indexOf('pmenu') > 0)
        {
        this.className="pmenu";
        }
        else {
        this.className = "";
        }
      }
      }
    }
  }
  function deleteObject()
  {
     if(shape)
        map.DeleteShape(shape);
     shape = null;
  }  
  
  function StartGeocoding( address )
         {
            map.Find(null,    // what
              address, // where
              null,    // VEFindType (always VEFindType.Businesses)
              null,    // VEShapeLayer (base by default)
              null,    // start index for results (0 by default)
              null,    // max number of results (default is 10)
              null,    // show results? (default is true)
              null,    // create pushpin for what results? (ignored since what is null)
              null,    // use default disambiguation? (default is true)
              null,    // set best map view? (default is true)
              GeocodeCallback);  // call back function
        }
        function GeocodeCallback (shapeLayer, findResults, places, moreResults, errorMsg)
        {
           // if there are no results, display any error message and return
           if(places == null)
           {
              alert( (errorMsg == null) ? "There were no results" : errorMsg );
              return;
           }

           var bestPlace = places[0];
           
           // Add pushpin to the *best* place
           var location = bestPlace.LatLong;
           
           var newShape = new VEShape(VEShapeType.Pushpin, location);
           
           var desc = "Latitude: " + location.Latitude + "<br>Longitude:" + 
                      location.Longitude;
           newShape.SetDescription(desc);
           newShape.SetTitle(bestPlace.Name);
           map.AddShape(newShape);
        }
        function onGeocodeClick()
        {
           map.Clear();
           address = document.getElementById("txtWhere").value;
           StartGeocoding(address);
        }
</script>

</head>
<body onload="GetMap();">
    <input id="txtWhere" type="text" style="width: 255px; " /> 
    <input type="button" value="Geocode" onclick="onGeocodeClick()" />

  <div id='myMap' style="position:relative; width:400px; height:400px;"></div>

  <ul id="popupmenu" class="pmenu">
    <li><a href="#" onclick='' class="parent">Switch view</a>
    <ul class="pmenu">
      <li><a href="#" 
        onclick="map.SetMapStyle(VEMapStyle.Hybrid);hidePopupMenu()">Hybrid</a></li>
      <li><a href="#" 
        onclick="map.SetMapStyle(VEMapStyle.Road);hidePopupMenu()">Road</a></li>
      <li><a href="#" 
        onclick="map.SetMapStyle(VEMapStyle.Aerial);hidePopupMenu()">Aerial</a></li>
      <li><a href="#" 
        onclick="map.SetMapStyle(VEMapStyle.Birdseye);hidePopupMenu()">Bird's Eye</a></li>
    </ul>
    </li>
    <li><a href="#" onclick='' class="parent">Zoom</a>
    <ul class="pmenu">
      <li><a href="#" onclick="map.ZoomIn();hidePopupMenu()">In</a></li>
      <li><a href="#" onclick="map.ZoomOut();hidePopupMenu()">Out</a></li>
    </ul>
    </li>
    <li><a href="#" 
      onclick="map.AddPushpin(map.GetCenter());hidePopupMenu();">Add Pushpin</a></li>
    <li><a href="#" 
      onclick="deleteObject();hidePopupMenu();">Delete Object</a></li>
  </ul>
</body>
</html>

Use_of_VEMap/13.jpg

上面的代码将创建一个自定义上下文菜单,其中包含通用地图应具有的所有功能。您还可以使用上方地图中的 Textbox 来使用地理编码功能地址。

结论

VEMap 控件易于开发,并且是一个非常实用的显示地图的工具。如果您需要任何进一步的帮助,请随时评论。我很乐意回答您的问题。

这是文章的第一部分。我还会为 WPF 用户提供更多内容,并很快发布该主题的第二部分,其中将包括 Web 服务解决方案,并且我还将介绍如何在 Windows 应用程序中使用 Virtual Map earth。希望您也会阅读。

参考文献

历史

  • 2009 年 9 月 29 日:首次发布

我也希望看到您的回复。希望您喜欢这个主题。如果不喜欢,请告诉我进行修改,以便通过您的想法丰富文章。

感谢您的支持。

© . All rights reserved.