可以在前端实现的几个地理位置小功能

2010年3月11日 00:09

在Smashing Magazine上看到这篇Entering The Wonderful World of Geo Location,介绍了获取并处理用户地理位置的应用和方法,很有意思。结合原文的内容,加上之前的一些应用,整理了几个可以完全在前端实现的地理位置相关小功能。

1.通过IP获取用户位置

很多时候需要通过IP判断用户的位置,通常的办法是通过自己的后台程序查询数据库得到。如果用户位置只是应用在前端,或者有其他的特殊原因(比如,懒:),也有一些其他办法来快速的获取用户位置。

maxmind.com提供了一个服务,通过引入一个js文件(http://j.maxmind.com/app/geoip.js),可以把他判断到的用户的国家、城市、经纬度等信息加入到页面中来。下面是从青岛访问这个js文件返回的内容:

function geoip_country_code() { return 'CN'; } function geoip_country_name() { return 'China'; } function geoip_city() { return 'Qingdao'; } function geoip_region() { return '25'; } function geoip_region_name() { return 'Shandong'; } function geoip_latitude() { return '36.0986'; } function geoip_longitude() { return '120.3719'; } function geoip_postal_code() { return ''; }

我们就可以利用这些信息做很多东西了:DEMO

2.W3C共享位置接口

HTML5加入了的贡献地理位置的浏览器API接口,目前firefox3.5等浏览器已经支持这一功能。

用法:

// if the browser supports the w3c geo api
if(navigator.geolocation){
  // get the current position
  navigator.geolocation.getCurrentPosition(

  // if this was successful, get the latitude and longitude
  function(position){
    var lat = position.coords.latitude;
    var lon = position.coords.longitude;
  },
  // if there was an error
  function(error){
    alert('ouch');
  });
}

DEMO

3.逆经纬度解析

通过浏览器API等方式得到经纬度后,有时需要得到对应的城市名,这就是逆经纬度解析。

google maps api提供了一些经纬度解析方法,如果我们不想引入庞大的api,可以直接使用他的请求地址,通过jsonp方式得到google的经纬度解析数据。jsonp请求地址形式为:

http://ditu.google.cn/maps/geo?
output=json&oe=utf-8&q=纬度%2C经度
&key=你申请到的key
&mapclient=jsapi&hl=zh-CN&callback=myfunction

参数q为经纬度,参数callback为回调函数名。

可以看下这个地址的返回结果,数据非常丰富,并且还是中文的:

myfunction && myfunction( {
  "name": "36.06023, 120.3024",
  "Status": {
    "code": 200,
    "request": "geocode"
  },
  "Placemark": [ {
    "id": "p1",
    "address": "中国山东省青岛市市南区台西三路6号-10号",
    "AddressDetails": {
   "Accuracy" : 8,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省",
         "Locality" : {
            "DependentLocality" : {
               "DependentLocalityName" : "市南区",
               "Thoroughfare" : {
                  "ThoroughfareName" : "台西三路6号-10号"
               }
            },
            "LocalityName" : "青岛市"
         }
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0633254,
        "south": 36.0570301,
        "east": 120.3054361,
        "west": 120.2991409
      }
    },
    "Point": {
      "coordinates": [ 120.3024027, 36.0602271, 0 ]
    }
  }, {
    "id": "p2",
    "address": "中国山东省青岛市市南区台西三路8号阿双美容美发厅",
    "AddressDetails": {
   "Accuracy" : 9,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省",
         "Locality" : {
            "DependentLocality" : {
               "AddressLine" : [ "阿双美容美发厅" ],
               "DependentLocalityName" : "市南区",
               "Thoroughfare" : {
                  "ThoroughfareName" : "台西三路8号"
               }
            },
            "LocalityName" : "青岛市"
         }
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0632366,
        "south": 36.0569414,
        "east": 120.3055696,
        "west": 120.2992744
      }
    },
    "Point": {
      "coordinates": [ 120.3024220, 36.0600890, 0 ]
    }
  }, {
    "id": "p3",
    "address": "中国青岛市市南区台西四路站",
    "AddressDetails": {
   "Accuracy" : 9,
   "AddressLine" : [ "台西四路站" ]
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0630636,
        "south": 36.0567684,
        "east": 120.3063986,
        "west": 120.3001034
      }
    },
    "Point": {
      "coordinates": [ 120.3032510, 36.0599160, 0 ]
    }
  }, {
    "id": "p4",
    "address": "中国青岛市市南区云南路(台西四路口)站",
    "AddressDetails": {
   "Accuracy" : 9,
   "AddressLine" : [ "云南路(台西四路口)站" ]
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0643586,
        "south": 36.0580634,
        "east": 120.3073456,
        "west": 120.3010504
      }
    },
    "Point": {
      "coordinates": [ 120.3041980, 36.0612110, 0 ]
    }
  }, {
    "id": "p5",
    "address": "中国青岛市市南区贵州路站",
    "AddressDetails": {
   "Accuracy" : 9,
   "AddressLine" : [ "贵州路站" ]
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0614856,
        "south": 36.0551904,
        "east": 120.3036956,
        "west": 120.2974004
      }
    },
    "Point": {
      "coordinates": [ 120.3005480, 36.0583380, 0 ]
    }
  }, {
    "id": "p6",
    "address": "中国青岛市市南区团岛站",
    "AddressDetails": {
   "Accuracy" : 9,
   "AddressLine" : [ "团岛站" ]
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0629146,
        "south": 36.0566194,
        "east": 120.3022496,
        "west": 120.2959544
      }
    },
    "Point": {
      "coordinates": [ 120.2991020, 36.0597670, 0 ]
    }
  }, {
    "id": "p7",
    "address": "中国山东省青岛市市南区团岛四路海湾花园",
    "AddressDetails": {
   "Accuracy" : 9,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省",
         "Locality" : {
            "DependentLocality" : {
               "AddressLine" : [ "海湾花园" ],
               "DependentLocalityName" : "市南区",
               "Thoroughfare" : {
                  "ThoroughfareName" : "团岛四路"
               }
            },
            "LocalityName" : "青岛市"
         }
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0642706,
        "south": 36.0579754,
        "east": 120.3006386,
        "west": 120.2943434
      }
    },
    "Point": {
      "coordinates": [ 120.2974910, 36.0611230, 0 ]
    }
  }, {
    "id": "p8",
    "address": "中国山东省青岛市市南区",
    "AddressDetails": {
   "Accuracy" : 4,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省",
         "Locality" : {
            "DependentLocality" : {
               "DependentLocalityName" : "市南区"
            },
            "LocalityName" : "青岛市"
         }
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.0954205,
        "south": 36.0413849,
        "east": 120.4266629,
        "west": 120.2858189
      }
    },
    "Point": {
      "coordinates": [ 120.3877350, 36.0667110, 0 ]
    }
  }, {
    "id": "p9",
    "address": "中国山东省青岛市",
    "AddressDetails": {
   "Accuracy" : 4,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省",
         "Locality" : {
            "LocalityName" : "青岛市"
         }
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.3313685,
        "south": 35.9407727,
        "east": 120.6326294,
        "west": 120.0970459
      }
    },
    "Point": {
      "coordinates": [ 120.3827710, 36.0663480, 0 ]
    }
  }, {
    "id": "p10",
    "address": "中国山东省",
    "AddressDetails": {
   "Accuracy" : 2,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省"
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 38.4055838,
        "south": 34.3851760,
        "east": 122.7159599,
        "west": 114.8033683
      }
    },
    "Point": {
      "coordinates": [ 117.0198960, 36.6692270, 0 ]
    }
  } ]
}
 )

Yahoo提供的接口

雅虎提供了一些经纬度查询接口,可以使用YQL查询。

查询语句为:

select * from flickr.places where lat=36.06023 and lon=120.3024

用法:

<script type="text/javascript" charset="utf-8">
 function getPlaceFromFlickr(lat,lon,callback){
   // the YQL statement
   var yql = 'select * from flickr.places where lat='+lat+' and lon='+lon;

   // assembling the YQL webservice API
   var url = 'http://query.yahooapis.com/v1/public/yql?q='+
              encodeURIComponent(yql)+'&format=json&diagnostics='+
              'false&callback='+callback;

   // create a new script node and add it to the document
   var s = document.createElement('script');
   s.setAttribute('src',url);
   document.getElementsByTagName('head')[0].appendChild(s);
 };

 // callback in case there is a place found
 function output(o){
   if(typeof(o.query.results.places.place) != 'undefined'){
     alert(o.query.results.places.place.name);
   }
 }

 // call the function with my current lat/lon
 getPlaceFromFlickr(36.6692270,117.0198960,'output');
</script>

4.经纬度解析

经纬度解析就是通过地名取得经纬度数据,同样利用google那个请求地址,可以实现这一功能,请求地址格式为:

http://ditu.google.cn/maps/geo?output=json&oe=utf-8
&q=地名的url encode编码
&key=你申请到的key
&mapclient=jsapi&hl=zh-CN&callback=myfunction

参数q为encodeURI(“中国山东省青岛市市北区”),callback是jsonp回调函数名。

举个例子,返回结果:

myfunction && myfunction( {
  "name": "中国山东省青岛市市北区",
  "Status": {
    "code": 200,
    "request": "geocode"
  },
  "Placemark": [ {
    "id": "p1",
    "address": "中国山东省青岛市市北区",
    "AddressDetails": {
   "Accuracy" : 4,
   "Country" : {
      "AdministrativeArea" : {
         "AdministrativeAreaName" : "山东省",
         "Locality" : {
            "DependentLocality" : {
               "DependentLocalityName" : "市北区"
            },
            "LocalityName" : "青岛市"
         }
      },
      "CountryName" : "中国",
      "CountryNameCode" : "CN"
   }
},
    "ExtendedData": {
      "LatLonBox": {
        "north": 36.1237216,
        "south": 36.0515859,
        "east": 120.4388307,
        "west": 120.3107713
      }
    },
    "Point": {
      "coordinates": [ 120.3748010, 36.0876620, 0 ]
    }
  } ]
}
 )

5.google maps 图片接口

有时候我们只想展示简单的地图,不需要交互和拖动,可以通过google maps提供的静态地图API引入动态生成的地图图片,不过需要为你的域名申请一个key。

引入图片的url格式为:


http://maps.google.com/maps/api/staticmap?

sensor=false
&size=200x200
&maptype=roadmap
&key=<em>你申请到的KEY</em>
&markers=color:blue|label:1|37.4447,-122.161
&markers=color:red|label:2|37.3385,-121.886
&markers=color:green|label:3|37.3716,-122.038
&markers=color:yellow|label:4|37.7792,-122.42

得到图片:

null

后记

关于地图的更多操作,可以参见以前的这篇文章:Google Maps Api介绍与基础操作

随着互联网的发展,越来越多的功能可以在前端实现,出现了越来越多的强大的第三方服务,我们可以很方便的在我们的网站上加入一些实用的功能。这也许就是web2.0的魅力吧。

TED2010:下一代的地图技术在微软而非Google

2010年2月28日 22:16


阅读全文 »

JavaScript单元测试工具 — QUnit

2010年2月4日 12:32

QUnit是jQuery团队开发的JavaScript单元测试工具,使用方便,界面美观。近期试用了一下并进一步了解了JavaScript单元测试,记录一下所思所得。

什么是单元测试

单元测试又称为模块测试,是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。单元测试主要是用来检验程式的内部逻辑,也称为个体测试、结构测试或逻辑驱动测试。通常由撰写程式码的程式设计师负责进行。

通常来说,程式設計師每修改一次程式就會進行最少一次單元測試,在編寫程式的過程中前後很可能要進行多次單元測試,以證實程式達到軟件規格書(en:Specification)要求的工作目標,沒有臭蟲;雖然单元测试不是什么必须的,但也不坏,這牽涉到專案管理的政策決定。

—— 维基百科 (中文英文)

为什么JavaScript需要单元测试

阅读全文 »

中国工会网改版670万?国家队威武!

2010年1月20日 17:25

一则消息

中华人民共和国财政部新发布了一条竞标公告:中国工会网扩建项目一期工程(网站改版、内容管理、站内检索、统计分析)成交结果公告TC099R72

采购人名称:中国工会网络中心
采购项目名称:中国工会网扩建项目一期工程(网站改版、内容管理、站内检索、 统计分析)
招标编号:TC099R72
成交结果确定日期:2009年12月25日
成交金额:670万元
成交供应商名称:北京中软宏大信息技术有限公司
成交供应商地址:北京市海淀区学院南路55号中软大厦A座2层,10081

招标采购代理机构:中招国际招标有限公司
项目联系人:陆欣
电话:010-62108160

中招国际招标有限公司
2009年12月30日

阅读全文 »

jQuery1.4下载、性能及新特性详解

2010年1月20日 10:02

jQuery1.4正式版发布了,官方同步推出了The 14 Days of jQuery 网站,来介绍jQuery1.4的新特性和教程,其中有一篇文章详细介绍了jQuery1.4的新增功能,现转载其中文翻译如下:

原文:jQuery 1.4 Released

翻译:coolnalu

jQuery 1.4 发布啦

为了庆祝jQuery的四周岁生日, jQuery的团队荣幸的发布了jQuery Javascript库的最新主要版本! 这个版本包含了大量的编程,测试,和记录文档的工作,我们为此感到很骄傲。

我要以个人的名义感谢 Brandon Aaron, Ben Alman, Louis-Rémi Babe, Ariel Flesler, Paul Irish, Robert Kati?, Yehuda Katz, Dave Methvin, Justin Meyer, Karl Swedberg, and Aaron Quint。谢谢他们在修复BUG和完成这次发布上所做的工作。

下载(Downloading)

按照惯例,我们提供了两份jQuery的拷贝,一份是最小化的(我们现在采用Google Closure作为默认的压缩工具了),一份是未压缩的(供纠错或阅读)。
阅读全文 »

google的声明,谷歌百度同时解禁,白宫表态,接下来会发生什么?

2010年1月13日 19:45

继1月12日百度被黑长达半天之后,今天互联网爆出了更重磅的新闻:google官方博客宣布有意关闭google.cn及谷歌中国办公室

这一消息立即引起了轩然大波,互联网上弥漫着一股哀伤与低迷的氛围。

而接下来发生的一系列事情,让人不禁开始绷紧神经,不禁要问:百度和谷歌究竟发生了什么?中国政府到底想干什么?事态究竟将怎样发展?

本文只搜集看到的、听到的一些消息,不发布个人意见。

Google 官方博客声明

阅读全文 »

百度被黑深层分析

2010年1月12日 12:14

扯淡分析

1. 百度被黑的真正原因是:伊朗圣战军的新任领袖阿卜杜.阿卜杜拉(abaidu.abaidula)看百度不爽,犯了名讳:) -_-!

2. abaidu.abaidula在GOOGLE上搜“SB”搜到自己的名字一下就怒了于是黑了百度 -_-!

3. 政治抗议只是表面原因,其实——由于米国的军事打击威胁,伊朗人准备大批量购买火箭筒,于是来百度搜索,但是遭遇百度的竞价排名,伊朗人选购了搜索结果排名第一位的火箭筒,到手之后发现上当。伊朗人气不过,遂黑了百度 -_-!

4. 国内互联网形势风起云涌,百度忙于公关打理,忘了域名续费 -_-!

5. 因为李彦宏不信春哥,百度未能满状态原地复活。。-_-!

阴谋论分析

阅读全文 »

使用框架的最高境界是忘掉框架,而不是依赖甚至依附框架

2010年1月6日 23:27

张三丰一路剑法使完,竟无一人喝彩,各人竟皆诧异:“这等慢吞吞、软绵绵的剑法,如何能用来对敌过招?”转念又想:“料来张真人有意放慢了招数,好让他瞧得明白。”

只听张三丰问道:“孩儿,你看清楚了没有?”张无忌道:“看清楚了。”张三丰道:“都记得了没有?”张无忌道:“已忘记了一小半。”张三丰道:“好,那也难为了你。你自己去想想罢。”张无忌低头默想。过了一会,张三丰问道:“现下怎样了?”张无忌道:“已忘记了一大半。”

周颠失声叫道:“糟糕!越来越忘记得多了。张真人,你这路剑法是很深奥,看一遍怎能记得?请你再使一遍给我们教主瞧瞧罢。”张三丰微笑道:“好,我再使一遍。”提剑出招,演将起来。众人只看了数招,心下大奇,原来第二次所使,和第一次使的竟然没一招相同。周颠叫道:“糟糕,糟糕!这可更加叫人胡涂啦。”张三丰画剑成圈,问道:“孩儿,怎样啦?”张无忌道:“还有三招没忘记。”张三丰点点头,放剑归座。张无忌在殿上缓缓踱了一个圈子,沉思半晌,又缓缓踱了半个圈子,抬起头来,满脸喜色,叫道:“这我可全忘了,忘得乾乾净净的了。”张三丰道:“不坏,不坏!忘得真快,你这就请八臂神剑指教罢!”

寻根究底:Ajax请求的GET与POST方式比较

2009年12月30日 21:38

YSlow里有一条规则叫Use GET for AJAX requests,即“使用GET方式请求AJAX”,YSlow中的解释如下:

When using the XMLHttpRequest object, the browser implements POST in two steps: (1) send the headers, and (2) send the data. It is better to use GET instead of POST since GET sends the headers and the data together (unless there are many cookies). IE’s maximum URL length is 2 KB, so if you are sending more than this amount of data you may not be able to use GET.

翻译:

当使用XMLHttpRequest对象时,浏览器通过两个步骤实现POST:(1)发送请求头;(2)发送数据。而GET的请求头和数据是一起发送的(除非包含很多cookie),所以使用GET方式更好些。IE支持的最大URL长度是2KB,所以你的数据很长的话就不能用GET了。

这段话蜻蜓点水,只说了GET和POST的这两个差别,而实际使用中会是这么简单吗?

寻根:GET与POST的差别

阅读全文 »

教程:编写放在收藏夹里的网页划词翻译工具

2009年12月26日 17:04

关于收藏夹工具

随着互联网技术的发展,越来越多的传统计算机应用被移植到了web上,目前流行起了一种“放在收藏夹里的工具”,点一下收藏书签,无需安装运行,便可以开始使用强大的功能。

比如搜狗云输入法(搜狗云输入法的简单分析)、人间网转帖工具等,都是应用了这种方式。

这种方式的优点是显而易见的:

· 无需安装,随点随用;

· 跨操作系统、跨平台,只要有浏览器就可以使用;

· 程序放在服务器上,可以随时更新升级;

· …

这种看似很强大的应用,其实它的原理很简单,实现也很容易,今天我们就基于这一理念,利用google翻译API,一起做一个简单的网页划词翻译工具,和大家一起学习和理解这一种创新的互联网应用模式。

demo可以看这里: http://www.oncoding.cn/demos/trans/index.html

阅读全文 »