摘自:http://www.microsoft.com/china/MSDN/library/Windev/windowslive/bb259692.mspx?mfr=true
基于地图的搜索需要有一张地图,还需具备搜索相关位置的能力。幸运的是,Virtual Earth 地图控件为我们同时提供了这两个必要条件。其中最可喜的是,我们只需使用 HTML、JavaScript 和一点点 CSS 即可构建一个基于地图的搜索系统。
VEMap 控件不仅可以显示我们的地图,它还提供了四种不同的执行搜索的方法:
• | 在 local.live.com 上可用的 What/Where 控件在基本的 VEMap 控件中也可用。我们可以增加一行 JavaScript 代码来开启此控件。 |
• | FindLocation() 方法用于执行位置搜索。如果找到匹配位置,地图会自动重新居中于该位置并放大到适当的级别。 |
• | FindNearby() 方法用于执行“what”搜索以查找位于当前地图中心附近的企业。此搜索与 local.live.com 使用相同的黄页数据库。 |
• | Find() 方法可让您最大程度地对搜索进行控制,您既可以指定搜索内容,也可指定搜索范围。还可以在 JavaScript 回调函数中接收搜索结果。 |
通过选择适当的 Find 方法,您可以构建一个功能完备的基于地图的搜索应用程序。
在探讨用于查找位置的各种选项之前,让我们先来看看基本的 Virtual Earth 地图:
<html> <head> <script src="http://dev.virtualearth.net/mapcontrol/v4/mapcontrol.js"></script> <script> var map; function OnPageLoad() { map = new VEMap('myMap'); map.LoadMap(); } </script> <body onload="OnPageLoad();"> <div id="myMap" style="position:relative;width:600px;height:400px;"></div> </body> </html>
程序清单 1 基本页面 (Find.html)
如果在浏览器中加载此页面,您应看到一张带有基本 Virtual Earth 导航仪表板的美国地图。
只需开启 what/where 控件即可利用查找功能,这是最简单的方法。将下面这行代码添加到 OnPageLoad() 方法的末尾:
map.ShowFindControl();
程序清单 2 开启 Find 控件
如果在浏览器中加载修改后的页面,您应在右上角看到 What/Where 控件:
如果在“where”(搜索范围)框中键入一个地址(如 Denver),然后单击“Find”(查找),地图会自动重新居中于所处位置。如果 Virtual Earth 无法找到完全匹配的项,您将看到一个消除二义性的弹出式对话框:
只需单击所需的位置,地图即会重新居中并缩放到适当的级别:
如果用户在“What”(搜索内容)框中输入了信息,则会看到与在黄页中搜索的输入信息匹配的一组图钉。 例如,我们可以在“Vail, Colorado”(科罗拉多州的维尔)查找“coffee”(咖啡):
当然,What/Where 控件也存在一些缺陷。首先,该控件相当宽。地图的宽度必须至少为 635 个像素才能在地图上显示整个控件。可以通过查找相关的 CSS 条目进行样式调整,但此项功能既不容易公开也不直接支持。另一问题是对搜索的定义相当不精确。也就是说,用户可以采用任何格式输入地址,而 Virtual Earth 会做出最佳推断。我们可以通过创建自己的查找控件来克服上述两种局限性。
FindLocation() 方法非常简单而且易于使用。我们只需传入一个包含地址的字符串即可。在本例中,我们想强制用户输入一个邮政编码。因此,我们将要创建一个面板,其中包含一个文本框和一个查找按钮。另外,我们还要将查找按钮链接到我们的 FindLocation 方法。
首先,我们需要增加一些 HTML。请将以下 div 添加到 html 文件体中:
<div id="SearchPanel" > <table border=0> <tr><td bgcolor='#C0C0CF'><p align='center'>Search</p></td></tr> <tr><td><p align='center'> Zip Code: <INPUT id="txtZip" type="text" value="" name="txtZip"> </td></tr> <tr><td bgcolor='#E0E0E0'><p align='center'> <input type="button" value="Search" onclick="DoFind();" id="Search" name="Search" /> </td></tr> <table> </div>
程序清单 3 添加面板
接下来,我们需要添加一些样式信息,以使我们的搜索控件更好看一些。请将以下脚本块添加到页面的头部:
<style type="text/css" media="screen"> #SearchPanel { width: 150px; border-style: solid; border-width: 1px; border-color: lightgray; background: white; } </style>
程序清单 4 查找框样式设计
接下来,我们需要将查找面板附加到地图上并将其定位在所需位置。请用以下代码替换您的 OnPageLoad() 方法:
function OnPageLoad() { map = new VEMap('myMap'); map.LoadMap(); var search = document.getElementById('SearchPanel'); map.AddControl(search); search.style.left = "475px"; search.style.top = "5px"; }
程序清单 5 附加搜索面板
最后,我们需要构建 DoFind() 方法。请将以下代码添加到脚本块中:
function DoFind() { map.FindLocation(document.getElementById('txtZip').value); }
程序清单 6 实现 FindLocation
如果现在加载我们的应用程序,应在右上角看到我们自己自定义的查找框。请输入自己想要的邮政编码,然后单击查找按钮,看看会发生什么情况:
可以添加验证代码以确保用户输入有效的邮政编码,不过我要将此当作练习留给读者。
我们列表中的下一项任务是实现我们自己的“what”搜索。要实现“what”,需要替换我们搜索面板中的 html:
<div id="SearchPanel" > <table border=0> <tr><td bgcolor='#C0C0CF'><p align='center'>Search</p></td></tr> <tr><td><p align='center'> Business: <INPUT id="txtBiz" type="text" value="" name="txtBiz"> </td></tr> <tr><td bgcolor='#E0E0E0'><p align='center'> <input type="button" value="Search" onclick="DoFind();" id="Search" name="Search" /> </td></tr> <table> </div>
程序清单 7 What 文本框
我们还需要更改 DoFind() 方法:
function DoFind() { map.FindNearby(document.getElementById('txtBiz').value); }
程序清单 8 使用 FindNearby
请注意,FindNearby() 方法看起来几乎与 FindLocation() 方法完全一样。
如果现在在浏览器中加载我们的页面,即可执行“what”搜索来查找某个企业:
在运行搜索之前,可能需要放大所关注的区域。默认的地图视图将显示整个美国版图,并在地图中心点附近执行搜索。
执行搜索的最后一个选择可以让您同时对搜索过程和结果进行最大程度的控制。首先,我们只需将 FindLocation 和 FindNearby 搜索合并到单个搜索方法中。
第一步,将“Business”(企业)和“Zip”(邮编)两个文本框都添加到 html 中:
<div id="SearchPanel" > <table border=0> <tr><td bgcolor='#C0C0CF'><p align='center'>Search</p></td></tr> <tr><td><p align='center'> Zip Code: <INPUT id="txtZip" type="text" value="" name="txtZip"> </td></tr> <tr><td><p align='center'> Business: <INPUT id="txtBiz" type="text" value="" name="txtBiz"> </td></tr> <tr><td bgcolor='#E0E0E0'><p align='center'> <input type="button" value="Search" onclick="DoFind();" id="Search" name="Search" /> </td></tr> <table> </div>
程序清单 9 完整的搜索面板
下一步,我们需要再一次替换我们的 DoFind() 方法:
function DoFind() { var where = document.getElementById('txtZip').value; var what = document.getElementById('txtBiz').value; map.Find(what, where, 1); }
程序清单 10 含有 what 和 where 的 Find 方法
现在,如果加载我们的网页,应该会看到 what 和 where 两个文本框。
此时,我们的应用程序与使用内置 what/where 控件的初始版本完全等同。
我们可能不想自动显示结果而是希望另外执行某种筛选或处理。甚至可能想要将结果显示在一个新的面板中。幸运的是,Find() 方法与我们所选择的其他方法都不一样,它允许我们定义一个 JavaScript 回调函数。查找完成后将会激活该回调方法,从而使我们可以对结果进行访问。
根据调用 Find() 的具体方式,我们可能会收到两种不同类型的结果:
• | 如果 Find 方法返回“where”,我们将收到一个 VESearchResult 对象。每个对象均包含一个 ID 值和一对纬度/经度。 |
• | 如果 Find 方法返回“what”,我们将收到一个 VEFindResult 对象。每个对象均包含若干属性,包括 Name、Description、Phone 和一对纬度/经度。 |
由于我们无法确定将会返回哪种类型的结果,因此我们需要对结果类型进行区分。VESearchResult 始终都会有一个非空的 ID 字段,而 VEFindResult 始终都会有一个非空的名称字段。
我们想要将结果显示在地图极右侧的表中。需要添加一些 html 和 css 来定义该表。首先将以下 <div> 标记添加到页面体中:
<div id="SearchResults" ></div>
程序清单 11 SearchResults Div
接下来添加一些 CSS 以定义该 div。请将以下新样式添加到样式部分:
#SearchResults { display: none; width: 325px; border-style: solid; border-width: 1px; border-color: lightgray; background: white; }
程序清单 12 搜索结果的 CSS
最后,我们想要将该 div 作为一个控件附加到我们的地图对象上。让我们回到 OnPageLoad() 函数,并在该函数的末尾添加一些新代码:
var results = document.getElementById('SearchResults'); map.AddControl(results); results.style.left = "640px"; results.style.top = "5px"; map.ShowDisambiguationDialog(false);
程序清单 13 建立搜索结果视图
请注意,与使用 What/Where 面板一样,在将该控件添加到地图后,我们必须设置其位置。同样,我们也会关闭自动排除二义性功能。如果省略最后这一行,我们将无法使用我们的结果,因为在执行回调之后将会强制用户确定一个位置。关闭排除二义性即表示我们告知地图自动选择所返回的第一个位置。
接下来,我们必须向 Find() 调用添加一个额外的参数。此额外参数用于标识该 JavaScript 回调方法:
function DoFind() { var where = document.getElementById('txtZip').value; var what = document.getElementById('txtBiz').value; map.Find(what, where, 1, ProcessResults); }
程序清单 14 DoFind
最后,我们需要建立我们的 ProcessResults() 方法。我们要创建一个表并将其放到 SearchResults <div> 中。
function ProcessResults(findResults) { var results ="<table><tr><td colspan=3 align='center'>Find results</td></tr>"; results += "<tr><td>Name</td><td>Description</td><td style='width: 100px;'>Phone</td></tr>"; var numresults = 5; numresults = Math.min(numresults, findResults.length); for (r=0; r<numresults; r++) { results += "<tr><td>"; if (findResults[r].Name!=null) //VEFindResult 对象 { results += findResults[r].Name + "</td><td>"; results += findResults[r].Description + "</td><td style='width: 100px;'>"; results += findResults[r].Phone; } else { results += "Unknown</td><td>N/A"; } results += "</td></tr>"; } results += "</table>"; var resultPane = document.getElementById('SearchResults'); resultPane.style.display = 'block'; resultPane.innerHTML = results; }
程序清单 15 ProcessResults 方法
如果现在加载我们的页面,则应该能够输入邮政编码和企业并看到结果:
尽管我们的基本应用程序可以正常工作,不过我们始终都可以添加更多的功能。例如,可以添加验证以确保用户只能输入邮政编码。还可以使我们的表显示更多或更少的结果,甚至允许用户翻页到下一组结果。
内置于 VEMap 控件中的多种搜索选择为您设计基于地图的搜索提供了很大的灵活性。无论您想要进行简单搜索还是要对用户输入进行复杂的控制,只需使用 JavaScript、CSS、HTML 和 Virtual Earth SDK 就可以办到。