|
最近在用google map做这样一件事情:0 G+ z) y8 f: P9 z- X* y
数据库中有一个USER表,记录了人名及其所在地和最远的出行距离,需要将表中这样的用户查询出来:
+ {# X* w6 ~- I0 o5 p8 Z# ~4 L, ]他距离广东佛山不超过他的最远出行距离。(注:这里的距离是两地间最短行车路线的距离,并非直线距离)
- ~/ G- H6 W6 h( g" N计算两地间最短行车路线的距离可以通过google map的GDirections类做到,方法如下:复制代码
- <body onunload="GUnload()">
- </body>
复制代码这里很容易犯一个错误,很多人会这样写:
- var directions;
- function initialize() {
- directions = new GDirections();
- directions.load("from: 江西省南昌市 to: 江西省新建县");
- alert(directions.getDistance().meters);}
复制代码然后会提示directions.getDistance().meters没有定义。这是因为GDirections的load方法是异步的,alert(directions.getDistance().meters)的时候距离还没有计算出来。正确的方法是给load方法增加一个监听器,等它完成之后,就可以取得你想要的值了。
/ s) N$ M+ x7 F% b m知道如何计算距离了,现在该如何实现本文开始的那个需求呢?
# r$ G! K# X3 I一边是从数据库中读取数据,一边是google map计算结果。我先说下一开始时我的一个傻帽想法:用php先读取出用户,得到一个数组,再遍历数组,取得他们的地址一一向google map发送请求,取得结果后再输出到模板。然后我就想如果用php向google map发送请求,google map只提供了javascript的api,并没有php的api,而javascript是在浏览器执行。想到这我自己都傻了,我居然试图在服务器端执行客户端浏览器的代码。
0 B+ @& `, J; W, h2 |$ s( f纠正思路:
% M$ Y6 m1 c1 d8 |+ n+ ^用php先读取出用户,得到一个数组,输出到模板。(剩下的事情交给浏览器)
- <?php
- $people = array(
- 0 => array(
- 'name' => '刘德华',
- 'address' => '南昌',
- 'maxdistance' => '900',
- ),
- 1 => array(
- 'name' => '金城武',
- 'address' => '日本',
- 'maxdistance' => '1500',
- ),
- 2 => array(
- 'name' => '刘若英',
- 'address' => '浙江',
- 'maxdistance' => '1300',
- ),
- 3 => array(
- 'name' => '成龙',
- 'address' => '宜春',
- 'maxdistance' => '800',
- ),
- 4 => array(
- 'name' => '李连杰',
- 'address' => '北京',
- 'maxdistance' => '700',
- ),
- 5 => array(
- 'name' => '黄晓明',
- 'address' => '上海',
- 'maxdistance' => '1400',
- ),
- 6 => array(
- 'name' => '陆毅',
- 'address' => '北京',
- 'maxdistance' => '1300',
- ),
- 7 => array(
- 'name' => '古天乐',
- 'address' => '南京',
- 'maxdistance' => '1200',
- ),
- 8 => array(
- 'name' => '孙红雷',
- 'address' => '青岛',
- 'maxdistance' => '1800',
- ),
- 9 => array(
- 'name' => '聂远',
- 'address' => '杭州',
- 'maxdistance' => '1500',
- )
- );
- $people = json_encode($people);
- $jobaddress = '广东佛山';?>
复制代码浏览器中对得到的数组遍历,再一一向google map发送请求,得到距离。复制代码这段代码似乎没什么问题,但是运行之后却让人大失所望,它将数组的最后一个元素输出了10遍。
2 F1 o6 c0 k2 d$ W1 k但是一想,这问题也出得理所当然,原因还在于”异步”,load方法向google map请求数据是不少时间的,但是循环却是瞬间完成的,所以在load的监听函数中输出currentPerson.name时循环早已结束,所以输出的总是数组的最后一个元素。7 ^- I% N' y1 l8 G
于是将代码改成这样:
- function initialize() {
- var people = eval('('+'<?php echo $people;?>'+')');
- var directions = new GDirections();
- for(i = 0, max = people.length; i < max; i++){
- var currentPerson = people;
- var onDirectionLoad = function(currentPerson){
- return function(){
- if(directions.getStatus().code == G_GEO_SUCCESS)
- {
- var distance = directions.getDistance().meters;
- var listDiv = document.getElementById('userlist');
- var maxdistance = currentPerson.maxdistance * 1000;
- alert(distance+','+maxdistance);
- if(distance * 1 <= maxdistance){
- document.write(currentPerson.name+'
');
- }
- }
- }
- }
- GEvent.addListener(directions, "load", onDirectionLoad(currentPerson));
- directions.load("from: "+"<?php echo $jobaddress;?>"+" to: "+currentPerson.address);
- }}
复制代码这里将load的监听函数封装成了一个闭包,关于闭包我是这两天才了解了下概念,在这里就不累赘了,怕讲不好,自己google吧。总之,闭包在这里的作用就是让currentPerson这个变量在每一次请求中不会因为循环影响。% Q& v) ]2 ?. g: ^7 u
原以为这样可以搞定了,没想到currentPerson随我意了,directions却没有,就是说在监听函数中得到的directions.getDistance().meters总是数组最后一个元素的距离。
8 ^- u. w) F. X0 s: g, + @因此将directions也封装到闭包中:
- function initialize() {
- var people = <?php echo $people;?>;
- for(i = 0, max = people.length; i < max; i++){
- var currentPerson = people;
- function createDirection(currentPerson){
- var directions = new GDirections();
- var onDirectionLoad = function(currentPerson){
- return function(){
- if(directions.getStatus().code == G_GEO_SUCCESS)
- {
- var distance = directions.getDistance().meters;
- var listDiv = document.getElementById('userlist');
- var max_distance = currentPerson.maxdistance * 1000;
- if(distance * 1 <= max_distance){
- listDiv.innerHTML += currentPerson.name+','+currentPerson.address+','+distance+','+max_distance+',YES
';
- }else{
- listDiv.innerHTML += currentPerson.name+','+currentPerson.address+','+distance+','+max_distance+',NO
';
- }
- }
- }
- }
- GEvent.addListener(directions, "load", onDirectionLoad(currentPerson));
- directions.load("from: 广东佛山 to: "+currentPerson.address);
- return directions;
- }
- createDirection(currentPerson);
- }}
复制代码OK,搞定了!: p( m- y# # 6 G$ F
演示:演示1
/ W/ L3 u6 I4 w: O; F, J" o" E后来看见有人用串联的方法做,于是我也试了试:
- var people = <?php echo $people;?>;
- var i = 0;
- var max = people.length;
- function go() {
- var directions = new GDirections();
- var currentPerson = people;
- var onDirectionLoad = function(currentPerson){
- return function(){
- if(directions.getStatus().code == G_GEO_SUCCESS)
- {
- var distance = directions.getDistance().meters;
- var listDiv = document.getElementById('userlist');
- var max_distance = currentPerson.maxdistance * 1000;
- if(distance * 1 <= max_distance){
- listDiv.innerHTML +=currentPerson.name+','+currentPerson.address+','+distance+','+max_distance+',YES
';
- }else{
- listDiv.innerHTML +=currentPerson.name+','+currentPerson.address+','+distance+','+max_distance+',NO
';
- }
- i++;
- if(i < max){
- go();
- }
- }
- }
- }
- GEvent.addListener(directions, "load", onDirectionLoad(currentPerson));
- directions.load("from: <?php echo $jobaddress;?> to: "+currentPerson.address);}
复制代码一样可以达到要求。
7 F) }% R2 z u+ m5 @不过呢,串联的形式是在完成了一个请求之后再发送下一个请求的,速度自然会慢一些。! u# P$ z( o o# o1 ~6 w/ V* [: t
演示:演示2 |
|