开发一个基于位置的动态 mashup

Mashup、地图和快照

Mashup 是一种全新的、高度交互的 Web 开发方法。mashup 是来自不同资源的相关内容的综合,为超级用户体验提供了丰富的动态内容。在开发工具箱中加入 Asynchronous JavaScript + XML (Ajax)mashup 将会让您在不断变化发展的 Web 2.0 工作空间所带来的高要求方面游刃有余。

Ken Bluttman, 自由 Web 开发人员, Freelance Consultant

Ken BluttmanKen Bluttman 在计算机领域工作了将近二十年。在这二十年间,他掌握了多种编程语言并且撰写了六部计算机书籍,而且总是有做不完的事情。



2008 年 11 月 11 日

开始之前

本教程带您亲历了使用 Ajax 动态更新 Web 页面的全过程。这个 Web 页面由多个其它数据源填充的不同部分拼装而成,而使用 Ajax 调用更新其中一部分所需要的数据取自于填充页面另外一部分的数据源。这是 mashup 的基础 — 聚合数据。Ajax 是此过程的关键,因为它让页面的其他部分在无需刷新整个页面的情况下也能更新。具备 Ajax 的基础知识将对您跟随本教程的学习很有帮助;本教程也给出了 Ajax 的概览/回顾以便让您能快速掌握 Ajax。

有关本教程

本教程展示了一种常见的 mashup 技巧并以此为基础进行 mashup 应用的构建。地图在 Web 中十分流行,也是创建优秀 mashup 的原因所在。在本教程中,Google Maps API 提供了地图和地图绘制函数。从地图返回的数据 — 纬度和经度坐标 — 被应用于另一个 API,此 API 由流行的图片 Web 站点 Flickr 提供。Flickr 具备一个终端用户特性,它让您能地理标记 所上传的图片:图片拍摄位置的纬度和经度坐标与此图片相关。

mashup 包括单击 Google 地图并让 Map API 返回您单击之处的坐标。这些值再使用 Ajax 发送给 Flickr API。最终结果是返回由此坐标进行了地理标记后的一系列图片。

在此过程中,还会使用 Flickr API 的一个额外功能:标签。标签(而非地理标记)是描述图片的关键词。比如,您可以将金门大桥的图片标签为 San FranciscobridgeGolden Gatefog(该桥大部分处于大雾之中)等。这些标签由向 Flickr 上传图片的人添加。在本例中,我们不是创建新标签,而是搜索这些标签。

由于此 mashup 包含很多不同的 API,而 Ajax 也在其中,所以本教程按顺序介绍了这些组件:

  1. 展示有关 Google 地图的基础知识。让您了解如何创建并更改它。
  2. 随后,介绍 Ajax,这是因为 Ajax 使用来自 Google 地图的数据。关于 Ajax 的介绍中包括对基本 Ajax 调用的回顾。
  3. 介绍 mashup:来自 Google 地图的纬度和经度坐标通过 Ajax 机制发送给 Flickr API,图片从 Flickr 返回。
  4. 展示使用 Flickr API 的基础知识。让您了解如何获得 Flickr 帐号和使用 Flickr API。

目标

本教程的目标是将您的 Ajax 知识付诸应用,即利用 Ajax 调用将来自一个 API 的数据发送给另一个 API 。几个参数也随此 Ajax 调用发送。由此 Ajax 调用返回的信息随后被格式化以便适合在 Web 页面显示。

先决条件

本教程大部分使用的是 JavaScript 代码。Ajax 并不是一种语言,而是一种在很大程度上依赖于 JavaScript 代码的编程范型。因此,具备 Ajax 的知识将会很有帮助,但如果不具备,那么至少也要具备使用 JavaScript 代码的知识和经验。本教程还假设您了解地图的一些关键特性:距离、坐标和比例尺。

系统要求

具备对 Web 服务器的访问和一个有效的域名是本教程最基本的技术要求。此外,还需要具备向此域添加文件的权限。服务器端语言使用的是 PHP,但服务器端代码很简单。在服务器端,主要是使用代码来查询数据库或从服务检索数据。这些概念在任何一种服务器语言中都很常见,所以用您自己选择的服务器端语言对 PHP 代码进行重写应该不难。


Hello Map,新的 Hello World

开发人员通常都会通过创建一个再普遍不过的 Hello World 应用程序来初尝编程的滋味。这不免有些过时。在新的 Web 2.0 世界,您建立的是一个地图。

世界变成了地图

Google 是地图领域的佼佼者。不过,有一点要注意,那就是您必须具备一个可供您使用的 URL。如果您具备对某个域的访问,请遵循如下这些步骤:

  1. 如果还没有帐号,就在 Google 上开一个新帐号(有关链接,参看 参考资料)。
  2. 登记一个 Google Maps API 键(参见 参考资料)。确保阅读条款和条件。Google 将提供您自己的 API 键和一个可供您保存和上传的快捷示例页。创建 Hello Map 应用程序将非常简单。

清单 1 所示的是 Google 提供的自动生成代码。请注意,出于保密的原因,API key 由多个 X 代替。真正的 API 键是一个长的随机符号字符串。

清单 1. 基本的地图页
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8"/>
    <title>Google Maps JavaScript API Example</title>
    <script src="http://maps.google.com/maps?file=api&v=2&key=XXXXXXXXXXXXXXXX"
      type="text/javascript"></script>
    <script type="text/javascript">

    //<![CDATA[

    function load() {
      if (GBrowserIsCompatible()) {
        var map = new GMap2(document.getElementById("map"));
        map.setCenter(new GLatLng(37.4419, -122.1419), 13);
      }
    }

    //]]>
    </script>
  </head>
  <body onload="load()" onunload="GUnload()">
    <div id="map" style="width: 500px; height: 300px"></div>
  </body>
</html>

Google Maps API 编程

API 提供了数十种类以供您包括在自己的应用程序之中。其中最为常用的一个是 GMap2,它为新地图创建一个占位符。针对 GMap2 有很多方法可用。例如,setCenter 可让地图在所提供的纬度和经度位置上居中。

图 1 展示了由此代码生成的地图,地图以 Google 公司位于 Mountain View, CA 的总部为中心。您可以使用鼠标滚动地图,但地图的初始位置由如下代码行内的纬度/经度设置确定:

map.setCenter(new GLatLng(37.4419, -122.1419), 13)

图 1. 最初呈现的地图
显示 Palo Alto, CA 的地图

更改地图坐标和缩放系数

纬度和经度的定义

纬度提供的是垂直地理位置。经度提供的是水平地理位置。纬线是围绕地球表面的线;赤道是最长的一个纬线。经线则是连接地球两极的线。两线相遇的地方就是某位置的坐标。纬度和经度可以用度、分和秒来表示。纬度的一度相当于大约 69 英里;而纬度的一分则相当于大约 1.15 英里;纬度的一秒相当于大约 0.02 英里或 100 英尺。经度距离则根据地球测量位置的不同而不同。经度的一度在赤道的位置相当于大约 69 英里;这个数字向两极逐渐递减。

如果想在 Googletown 徜徉一番,图 1 中的地图很有用,但您也可以通过其他方法使用地图。

要找到具体的地理位置,需要纬度和经度设置,那么到何处才能找到这个至关重要的坐标呢?有很多地方可去,比如地图集或专门的软件包。由于这些都是与 Web 相关的,所以可以到 Web 上寻找一些有用的坐标。如果在 Web 上简单搜索免费的纬度和经度坐标,结果会返回几个非常有用的站点,这些站点在 参考资料 小节中列出。

通过更改 清单 1 内的代码,就可以显示费城的地图(参见图 2)。要实现此目的,只需更改 load 函数内的坐标。费城的坐标是 39.9531 和 -75.1651。还可以将 setCenter 方法的缩放系数增加到 14(在清单 1,该系数为 13);数值越高,看得越近。(缩放系数如果很低 — 比如,只有 4 —,那么将只能看到地球的大部分了)。所以对于费城,可以略微放大一些,现在地图的初始设置是 map.setCenter(new GLatLng(39.9531, -75.1651), 14)

图 2. 放大费城的地图
显示费城的地图

Ajax 回顾

至此,您已经创建了地图并且根据需要更改了坐标。这就基本上实现了地图的管理。Ajax 是接下来要用到的。可以使用 Ajax 将地图中心所在的坐标发送给服务器以便处理。如果您对 Ajax 的概念很模糊,那么很有必要先来回顾一下有关 Ajax 调用的基础知识。

Ajax 101

Ajax 是通过实例化一个 XMLHttpRequest 对象开始工作的。由于经常存在浏览器不兼容的问题,因此需要编码实现对象创建以便可以遍历一系列的对象创建尝试并最终找到正确的那个,如清单 2 所示。

清单 2. 将变量分配给 XMLHttpRequest 对象的实例化
var XMLHttpRequestObject = false; 
  try { 
    XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP"); 
    } catch (exception1) { 
      try { 
        XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); 
        } catch (exception2) { 
           XMLHttpRequestObject = false; 
        } 
     } 
  if (!XMLHttpRequestObject && window.XMLHttpRequest) { 
      XMLHttpRequestObject = new XMLHttpRequest(); 
  }

清单 2 内代码的结构对于 Internet Explorer 早先的版本而言非常必要。Internet Explorer 7 使用的是标准的 XMLHttpRequest 对象。较早版本的 Internet Explorer 使用的是特定于 Microsoft 的某种 XMLHTTP 对象。总之,上述代码将能够创建适合于特定浏览器的所需对象。为了便于讨论,下文中所述对象指的是 XMLHttpRequest 对象。

清单 2 中的代码在页面加载时运行,以便在需要的时候,对象已经就绪可用。对象是页面和服务器间的纽带,可充当小型页面刷新。更具体地说,Ajax 调用使用 XMLHttpRequest 对象来访问服务器上的数据或运行服务器上的进程。在此过程中,如果需要,还可以发送此次服务器端交互所需的参数。服务器会经对象返回此次调用的状态以及任何需要发回的数据,之后数据就可被页面所用了。

当数据返回时,一种典型的显示它的方式是将数据分配给 div 或其他 HTML 标记的 innerHTML 属性。清单 3 给出了这段代码,该代码取自本教程后面部分展示的示例代码。

清单 3. Ajax 调用
function getPhotos(lat, lon) {

  if (XMLHttpRequestObject) { 
    var obj = document.getElementById("photosgohere");
    var tags = document.getElementById("tags").value;
    var query = 'photos.php?lat=' + lat + '&lon=' + lon + '&tags=' + tags;
    XMLHttpRequestObject.open ("GET", query);
    XMLHttpRequestObject.onreadystatechange = function() {
    if (XMLHttpRequestObject.readyState == 4 &&
        XMLHttpRequestObject.status == 200) {   
     obj.innerHTML = XMLHttpRequestObject.responseText;
    }
  }
XMLHttpRequestObject.send(null);
}
}

这是一个 JavaScript 函数,所以只能在被某些动作(比如 clickonchange 事件)调用后才会运行。对于初学者而言,该代码的功能如下:

  1. 检查对象是否存在(对象在页面加载时创建)。
  2. obj 变量分配给 photosgohere 页面元素(恰巧为 div)。
  3. tags 变量分配给 tags 页面元素(文本框)内的值。
  4. 组装对服务器上的 photos.php 文件的调用。查询字符串在这里也完整给出以便此调用携带服务器文件查询数据所需的参数。
  5. 打开 XMLHttpRequest 对象以备使用。
  6. 使用一个匿名函数来测试此对象的状态。当调用完成后(通过检查状态改变和状态数据),返回给页面的结果置于 photosgohere 元素内。这个表示变量 obj 接收和转换结果。请注意在状态为完成的状态下,在此匿名函数内访问对象的 responseText 属性。
  7. send(null) 方法初始化此调用。

客户端代码还只是问题的一个方面。清单 4 所示的是 photos.php 文件(位于服务器上,用来查询数据并将数据发送回浏览器)的代码。

清单 4. Ajax 调用所涉及的服务器端代码
<?php
  $lonlow=urlencode($_GET['lon']-0.1);
  $lonhigh=urlencode($_GET['lon']+0.1);
  $latlow=urlencode($_GET['lat']-0.1);
  $lathigh=urlencode($_GET['lat']+0.1);
  $tags = urlencode($_GET['tags']);
  
  function getInfo($url){
    $chandle = curl_init();
    curl_setopt($chandle, CURLOPT_URL, $url);
    curl_setopt($chandle, CURLOPT_RETURNTRANSFER, 1);
    $result = curl_exec($chandle);
    curl_close($chandle);
    return $result;
  }

  $url="http://api.flickr.com/services/rest/?method=flickr.photos.search
    &api_key=xxxxxx&tags={$tags}&bbox={$lonlow},{$latlow},{$lonhigh},{$lathigh}
    &per_page=10";
  $result = getInfo($url);
  $content= simplexml_load_string($result);
  echo 'Total Found=' . $content->photos['total'] . '<br /><br />';
  foreach ($content->photos->photo as $photo) {
    $title = $photo['title'];
    $farmid = $photo['farm'];
    $serverid = $photo['server'];
    $id = $photo['id'];
    $secret = $photo['secret'];
    $owner = $photo['owner'];
    $thumb_url = 
      "http://farm{$farmid}.static.flickr.com/{$serverid}/{$id}_{$secret}_tjpg";
    $page_url = "http://www.flickr.com/photos/{$owner}/{$id}";
    $image_html= "<a href='{$page_url}'><img alt='{$title}' 
      src='{$thumb_url}'/></a>"; 
    echo '<p>' . $image_html;
    echo '<br />' . $title . '</p>';
 }
?>

清单 4 中大部分代码都基于 Flickr API 的使用,而这将在本文后续部分进行详细讨论。这里,只给出大致的概括:

  • 所传递的纬度和经度值扩大为 4 个坐标,用于定义一个地理边界框。
  • 用 API 键、所查找的标签以及在之前步骤创建的 4 个坐标对 Flickr API 进行调用。
  • 所返回的 Flickr 数据被处理成可用的格式并由 PHP echo 语句写入。此过程返回一系列预组装的 echo 语句,这些语句将被放入 photosgohere div,作为它的 innerHTML 属性。

注意:对 Flickr 的调用需要 API 键,这与 Google Maps 调用类似。这里,与 Google Maps API 一样,真正的 API 键由若干 X 字母代替。本教程在 “设置好 Flickr” 一节给出了获得 Flickr API 键的全过程。


mashup

之前的 清单 1 给出了基本的 Google Map 结构。首先实例化一个 Google map 对象 GMap2。可以使用侦听程序结构向此对象添加事件,这就告知地图对象要准备好在指定的事件发生时动作。在本例中,向地图对象添加了一个 click 事件。地图已经是可滚动的(单击并握住鼠标以便四处移动此地图),但现在要让地图也能响应单击动作。

添加地图事件侦听程序

修改后的代码如清单 5 所示。这是完整的页面代码、HTML 和 JavaScript 代码。

清单 5. 完整的客户端 HTML 文件
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<title>Google Maps JavaScript API Example</title>
<script type="text/javascript" 
   src="http://maps.google.com/maps?file=api&v=2&key=xxxxx"> 
</script>
<script type="text/javascript">

  var XMLHttpRequestObject = false; 
  try { 
    XMLHttpRequestObject = new ActiveXObject("MSXML2.XMLHTTP"); 
    } catch (exception1) { 
      try { 
        XMLHttpRequestObject = new ActiveXObject("Microsoft.XMLHTTP"); 
        } catch (exception2) { 
           XMLHttpRequestObject = false; 
        } 
     } 
  if (!XMLHttpRequestObject && window.XMLHttpRequest) { 
      XMLHttpRequestObject = new XMLHttpRequest(); 
  } 
function getPhotos(lat, lon) {

  if (XMLHttpRequestObject) { 
    var obj = document.getElementById("photosgohere");
    var tags=document.getElementById("tags").value;
    var query='photos.php?lat=' + lat + '&lon=' + lon + '&tags=' + tags;
    XMLHttpRequestObject.open ("GET", query);
    XMLHttpRequestObject.onreadystatechange = function() {
    if (XMLHttpRequestObject.readyState == 4 &&  
        XMLHttpRequestObject.status == 200) {     
     obj.innerHTML = XMLHttpRequestObject.responseText;
    }
 }
XMLHttpRequestObject.send(null);
}
}
function load() {
 if (GBrowserIsCompatible()) {
   var map = new GMap2(document.getElementById("map"));
   map.setCenter(new GLatLng(39.9531, -75.1651), 14);
 }
 GEvent.addListener(map, "click", function() {
 var coords = map.getCenter();
 coords=coords.toString();
 document.getElementById("message").innerHTML = coords;
 var coords2=coords.substr(1,coords.length-2);
 pos=coords2.search(/,/);
 var lat=coords2.substring(0,pos);
 var lon=coords2.substring(pos+1, coords2.length);
 getPhotos(lat, lon); 

});
}
</script>
</head>
<body onload="load()">
<table>
<tr><td valign="top"><div id="map" 
    style="width: 500px; height: 450px"></div><br />   
<b><div id="message"></div></b><br />
<form>
<b>Enter tag(s) here, then click on the map</b><br />
<input type="text" id="tags" />
</form>
<td>&nbsp;&nbsp;</td><td valign="top">
    <div id="photosgohere"></div></td>    
</tr>
</table>
</body>
</html>

图 3 显示了由清单 2 的代码所呈现的页面。出现的是费城的地图,下面是输入标签的地方。当输入标签信息时,单击地图将会:

  • 返回地图中心的坐标(因为地图是可滚动的,所以每次中心的位置也许会不同)
  • 调用 Ajax 代码,查询字符串由两个坐标和标签组合而成
  • 发送来自 Flickr 的所有匹配图片并在页面上加以显现
图 3. 有待您进一步处理的 Web 页
显示费城的地图

完成 mashup

有关纬度和经度的更多内容

赤道的纬度是 0 度。从赤道到北极,纬度从 0 向 90 度值递增,而从南极到赤道,数字逐减到 -90 度。本初子午线是跨越英国格林威治的虚构的一条连接北极和南极的线。此线的经度是 0 度。以此为起点,向东增加,向西减少。地球正对格林威治的垂直线是 -180 度和 180 度交汇的地方。

好了,有趣的部分就要开始了! 图 4 所示的是输入标签 Liberty 并单击地图后的结果。这里是费城的地图,因此返回的是 Liberty Bell 的照片以及其他一些带 Liberty 标签的图片。

图 4. 在费城搜索 “Liberty”
显示费城的地图

单击地图还会使地图中心的坐标出现在地图之下。费城大致位于纬度 39 度和经度 -75 度。图 4 显示了一个 mashup:两个数据源合并到一个页面内。在本例中,来自 Google API 的信息通过 Ajax 被传递给 Flickr;最终结果显示了此 Google 地图以及所返回的 Flickr 图片。


设置好 Flickr

Flickr 是一个非常流行的图片网站。通过此网站,您可以上传图片、创建图片相册、指定图片是公开给大众还是只公开给朋友和家人等等。Flickr 也是一个先进的 API 开发者的天地。Flickr API 具有很多函数,而只要有其中的一个函数 —— search —— 您就能创建这个 mashup 了。

获得帐号和 API 键后就可以开始行动了!

要创建这个 mashup,需要打开一个 Flickr 帐号。建立好帐号后,再获得一个 Flickr API 键(相关链接,请参见 参考资料)。

开发人员和 API 迷们感兴趣的是 Flickr 的 code.flickr 部分(参见 参考资料)。这包括论坛、开发人员的 blog 以及 API 文档。在 Flickr API 页(参见 参考资料)内有 开始使用 Flickr API 所需的所有资料:一个概览、服务条款、所有 API 调用的列表及相关文档、尝试 API 调用的试验台(testbed)。最后的这个特性尤其有用,因为它返回的是一个准备好的 URL 字符串,可用于您的页面代码。

所有 Flickr API 调用的使用均应包括一个给定的 URL:http://api.flickr.com/services/rest/?method=,然后是特定的 API 方法,后跟 API 键以及其他必需或可选的参数。本教程主要围绕 search API 方法展开,所以此 URL 最后应该类似如下所示:

$url="http://api.flickr.com/services/rest/?method=flickr.photos.search

URL 字符串的其余部分包含参数:此 API 键和特定于此方法的一些参数。

本教程中使用了 Flickr Search API 调用以便 latitudelongitude 参数可被发送给此 API 方法。而这样做的全部目的就是为了给结果一个中心点。只提供纬度和经度并不能限制在其中查找图片的图片区域。为了达到限制的目的,必须使用其他参数。search 方法接受由四个地理点构成的边界框,这四点定义了一个方形的地理区域。

Google 地图提供了地图中心的两个坐标。这些坐标再通过 Ajax 调用发送给 Flickr API。 在这个 photos.php 文件,由 2 个坐标创建出 4 个坐标:从两个所提供的纬度和经度坐标分别加上和减去 0.1 度,而这 4 个值就定义了一个边界框。如下 PHP 代码实现了此目的:

$lonlow=urlencode($_GET['lon']-0.1);
$lonhigh=urlencode($_GET['lon']+0.1);
$latlow=urlencode($_GET['lat']-0.1);
$lathigh=urlencode($_GET['lat']+0.1);

代码先是初始化 4 个变量,然后再将 4 个变量插入此 API 调用,如下所示:

bbox={$lonlow},{$latlow},{$lonhigh},{$lathigh}

由于纬度的一度相当于约 69 英里,相差 0.1 度的四角所确定的这个边界框的面积大约相当于 49 平方英里。即将 6.9 英里四舍五入到 7 英里,然后 7x7=49 平方英里。

可以将多个标签发送给此 Flickr Search API。图 5 使用了两个标签:Philadelphiazoo。通过在这两个单词间放上一个加号(Philadelphia+zoo ),就意味着搜索是要找到包含这两个标签的图片,结果返回的是一些动物图片。请注意,在本图中,在单击它之前,地图是可滚动的。费城动物园临近地图的中心。

图 5. 搜索费城动物园
显示费城的地图

有关服务器的更多内容

了解了 mashup 的工作原理之后,让我们来关注一下服务器上所发生的事情吧。坐标和标签都被发送给 photos.php 文件。边界框如之前所述的那样创建。此 URL 包含调用并综合了 API 键和参数。另一个参数 — 每页返回的图片数量 — 也被包括到字符串中,但此参数可选。

对此 Search API 的调用所返回的是数据,而非图片。所返回的数据包含指向这些图片在 Flickr 空间中所在位置的具体信息以及其他一些相关信息(标题、所有者、图像位置等)。对 Flickr API URL 的调用所返回的数据经 Curl 库函数传递以便于数据管理。数据然后经 PHP simplexml_load_string function 传递以便于使用 For Each 结构处理每个 XML 元素。

For Each 结构中,解析了的 XML 被按规范重新组装以便创建链回 Flickr 内的图片文件的链接。此链接再从 Ajax 调用发送回来,由于它所链接的是图片缩略图,所以在 Web 页面上看到的将是缩略图。可以单击这些缩略图以查看真正的图片,如本文后续部分所示。


展开搜索

基本的 mashup 就完成了。您已经可以输入标签、单击费城地图并从 Flickr 获得相关的图片。但是,如果您对费城不敢兴趣,那么该如何是好呢?没问题。您可以更改这个 mashup 来满足自己的需求。

由您决定在何处搜索

本教程的下一部分将开始新的过程,与从地图获得坐标不同,这次您需要输入坐标。此地图现在开始缩小以显示美国的整体陆地。当单击此地图时,它会按所提供的坐标放大。然后,搜索以相同的方式运行 — 利用坐标和标签。

页面具有两个针对纬度和经度值的新输入框,参见图 6。

图 6. 需要输入坐标和标签
显示美国的地图

为纽约市使用 40.77 和 -73.94,图 7 显示了针对标签 train 返回的搜索结果。

图 7. 纽约市的火车图片
显示美国的地图

表 1 中列出了全球主要的一些城市所在的纬度和经度坐标。

表 1. 一些主要城市的坐标
城市国家纬度经度
北京中国39.85116.38
柏林德国52.513.35
波士顿美国42.32-71.2
芝加哥美国42.32-71.2
达拉斯美国32.82-96.72
丹佛美国39.8-104.9
拉斯维加斯美国36.2-115.3
伦敦英国51.460.01
莫斯科俄罗斯55.7837.6
纳什维尔美国36.2-86.8
新德里印度28.5577.15
巴黎法国48.82.3
菲尼克斯美国33.36-112.1
里约热内卢巴西-23-43.3
罗马意大利41.912.4
旧金山美国37.75-122.56
西雅图美国47.62-122.3
悉尼澳大利亚-33.84151.2
多伦多加拿大43.7-79.4
温哥华加拿大49.2-123.12
华盛顿美国38.9-77

纬度与经度值并不像想象中那样容易确定。在 Web 上搜索这些主要城市会出现各种各样不同精度的值。记住,小数点位数越多,精度越高。这些值都针对 Google 地图测试过,并且相应进行过调整以便让这些城市位于地图的中心位置。

为了展示坐标的使用,图 8 展示了一个 Google 地图,其中标记出了表 1 中给出 4 个欧洲城市:柏林、伦敦、巴黎和罗马。在 Google 地图 API 文档有关覆盖图的部分可以找到有关标记的(一种覆盖图)的信息(参见 参考资料) 。

图 8. 由所提供的坐标确定的地图上的标记
显示 4 个欧洲城市的地图

清单 6 给出了创建这些标记的部分页面代码。

清单 6. 创建 Google 地图标记
<script type="text/javascript">
function load() {
  if (GBrowserIsCompatible()) {
    var map = new GMap2(document.getElementById("map"));
    map.setCenter(new GLatLng(48.8, 2.3), 4);
      var berlin = new GLatLng(52.5, 13.55);
      map.addOverlay(new GMarker(berlin));
      var london = new GLatLng(51.46, 0.01);
      map.addOverlay(new GMarker(london));
      var paris = new GLatLng(48.8, 2.3);
      map.addOverlay(new GMarker(paris));
      var rome = n        
ew GLatLng(41.9, 12.4);
      map.addOverlay(new GMarker(rome));
  }
}
</script>

进行缩放

地图的缩放系数也能影响到您看到的效果。即使坐标集有些偏差,但地图所显示的地域很大,那么从表面上看,坐标好像也是正确的。如果只是浏览地图,这还说得过去,但获得尽可能精确的坐标将能帮助您从 Flickr 获得最多的图片。以前说过这些返回的图片是被地理标记过的(有经度和纬度设置),并且这个边界框代表大概 49 平方英里的面积。因此,偏差几个英里的地图坐标所返回的图片,如果有的话,会与正确的图有很大差别。

可以用 Google map 对象的 setCenter 方法设定 Google 地图的缩放系数。低缩放系数的地图面积更大,高缩放系数的地图会放大地图。值越高,放大得越大:

  • 图 5 中的缩放系数是 14。
  • 图 6 中的缩放系数是 3。
  • 图 7 中的缩放系数是 10。
  • 图 8 中的缩放系数是 4。

关于 Search API 的更多内容

对 Flickr 进行 Search API 调用最为复杂。有 30 多个参数可附加到此调用。有完整的参数列表可供查看和测试 Flickr 的 API 领域。

参数列举

下面列举了一些搜索参数:

  • user_id:每个 Flickr 会员都有一个 ID。在使用时,此搜索会过滤由该用户上传的图像。
  • tags:在本教程前面介绍过。
  • min_upload_datemax_upload_date:过滤向 Flickr 上传图片的日期。
  • min_taken_datemax_taken_date:过滤图片拍摄的日期。
  • privacy_filter:可应用于图片的各种设置。默认值是 (1) public。 本教程所展示的所有照片都是公共的。其他设置则可让图片只对朋友或家人可见。
  • bbox:本教程使用的边界框。
  • media:照片或视频。
  • per_page:每个页面返回的图片数量。值的范围是 1 - 500;默认是 100。

个性化搜索

本教程介绍的主要搜索方法在这里将会有所调整。接下来展示通过用户 ID 和标签进行的搜索。利用这种搜索,您可以找到您自己的照片或您的某个朋友或家人成员的图片。user_id 属性对于过滤用户至关重要;本例使用最符合逻辑的一个人 — 本文作者。

图 9 所示的 Web 页面内只输入了标签。嵌入到 Flickr API 调用的是作者的用户 ID。所传递的标签被插入到 API 调用内,只有相应进行了标签的作者的图片才会出现。

图 9. 作者的图片
作者的图片

Ajax 调用内的 Web 页面和 photos.php 文件的代码已经针对图 9 的使用作了修改。Web 页面也进行了设置以便地图打开后显示的是华盛顿特区。地图侦听程序获取 click 事件并调用 getphotos() 函数,但不传递坐标。

function load() {
if (GBrowserIsCompatible()) {
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(38.9, -77), 11);
}
GEvent.addListener(map, "click", function() {
getPhotos();
});
}

在 photos.php 文件内,只使用了所传递的标签,而用户 ID 则嵌入在 URL 字符串内。纬度/经度/边界框设置则被忽略 — 华盛顿特区的位置已知。与之前一样,API 键藏于若干 X 字母,但用户 ID 却在代码内;由于它可通过 Flickr 使用,所以没有必要隐藏它:

$url="http://api.flickr.com/services/rest/?method=flickr.photos.search
&api_key=xxxxxxxx&user_id=28770060%40N02&tags={$tags}";

从 Flickr 返回的图片以缩略图链接的形式链接到相关的较大图片。单击缩略图会显示 Flickr 站点上完整大小的图片。图 10 显示了单击图 9 顶部图片后的显示结果。

在图 10 所示的 Flickr 页面内还显示了其他有趣的信息。这可能不太容易在屏幕显示的图片中看到,但在图片的右侧有关于作者的 Photostream(一个 Flickr 术语)、与图片相关联的标签以及位置(因为图片是经过地理标记过的)信息。当向 Flickr 上传图片时,您可能还会惊奇地看到所使用的相机以及照片的拍摄日期。Flickr 甚至还保留了照片被查看的次数。

图 10. 图片的放大视图
我的图片

在图 10 的右侧有一个 More Properties 链接。单击此链接会返回有关此图片的准确细节,包括曝光时间、光圈设置、ISO 速度、分辨率等。您可能不熟悉这些术语,它们表明了相机快门时间、快门的宽度以及胶卷的饱和速度。最后的这个术语很有趣,因为数码相机不使用胶卷!但 ISO 速度在摄影领域仍是一个重要的系数,所以也有对应于数码相机的同样的系数。图 11 显示了图 10 中所示照片的更多细节信息。

图 11. 有关图片的准确信息
我的图片

结束语

创建 mashup 最重要的因素是从外部资源获得信息的能力。这类信息可通过 Web 服务和 API 调用获得。很多 Web 站点都开始了行动并为开发人员提供了站点自己的 API 以便他们试用。在研究本教程的过程中,很容易被大量 API 测试和专注于 mashup 的 Web 站点所吸引。

大多数 API 的使用都是免费的。提供 API 的 Web 站点都希望通过 API 的使用而提高访问量和知名度。很多站点会限制每天可以进行的 API 调用的数量,还有一些站点会区分个人和商业应用程序。商业应用程序常常会有价格或其他要求。每个 API 服务都有自己的服务条款,所以在使用时,请务必认真阅读以防止出现法律问题。

参考资料

学习

获得产品和技术

条评论

developerWorks: 登录

标有星(*)号的字段是必填字段。


需要一个 IBM ID?
忘记 IBM ID?


忘记密码?
更改您的密码

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件

 


在您首次登录 developerWorks 时,会为您创建一份个人概要。您的个人概要中的信息(您的姓名、国家/地区,以及公司名称)是公开显示的,而且会随着您发布的任何内容一起显示,除非您选择隐藏您的公司名称。您可以随时更新您的 IBM 帐户。

所有提交的信息确保安全。

选择您的昵称



当您初次登录到 developerWorks 时,将会为您创建一份概要信息,您需要指定一个昵称。您的昵称将和您在 developerWorks 发布的内容显示在一起。

昵称长度在 3 至 31 个字符之间。 您的昵称在 developerWorks 社区中必须是唯一的,并且出于隐私保护的原因,不能是您的电子邮件地址。

标有星(*)号的字段是必填字段。

(昵称长度在 3 至 31 个字符之间)

单击提交则表示您同意developerWorks 的条款和条件。 查看条款和条件.

 


所有提交的信息确保安全。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Web development, XML, Open source
ArticleID=350888
ArticleTitle=开发一个基于位置的动态 mashup
publish-date=11112008