Google地图开发总结

我们经常使用地图查位置、看公交、看街景,同时地图还开放第三方的API给开发者。利用这些API进行地图的个性化的展示和控制,例如北京被水淹了,开发一个网页显示北京被淹的地图,地图上面标志被水淹的位置、严重程度,或者我是交警,想要在地图上标志发生车祸、被交通管制的路段,甚至是利用地图的街景,控制街景的位置变化做一个tour show动画。因为地图本身就是一个比较好玩的东西,再加上一些个性化的控制会更加的有趣。

常有的地图有谷歌、百度、必应等,这些都有提供api,下面以谷歌地图为例做说明。虽然谷歌被墙,但是谷歌有一个中国域名版本的,没有被墙,可以自由访问:http://www.google.cn/maps,估计很多人都不知道。首先来看下谷歌地图是怎么显示在页面的

谷歌地图的组成

只要做一下元素审查,就可以发现谷歌地图的主体部份是用一张张的图片拼成的,只要缩放比例或者位置一改变,就会再去请求新的图片,也就是说地图的渲染是在后端进行的,后端把图片生成好发给前端,之所以没放在前端绘制主要应该是考虑了客户端的性能和兼容性。左上角和右下角的控制也是用div absolute定位上去的。

map

 

谷歌地图的使用

引入谷歌地图

首先加载地图的api,你可以指定所用语言,如果没指定,地图将根据浏览器的语言(可通过请求的http头的Accept-Language字段)自动选用语言。还可以指定谷歌地图的版本,现在最新版是ver=3.25,还可以加上一些指定的地图的lib。必填的参数是key,如果没有key去谷歌地图的开发者页面申请一个即可。大陆版的跟正常版的在使用上目测没什么区别

然后在页面写一个div,作为地图的容器,指定地图的宽高

初始化谷歌地图,最主要的两个参数是传一个中心点和缩放倍数,如果你点地图右下角的+号,就会再放大一倍,这里的放大倍数就指这个

这样在你的页面就有一个以天安门为中心的地图了

bj

接下来,给天安门添加一个地理标志,使用谷歌自带的marker

添加一个Marker

通过上面代码的new我们已经有了个map对象,然后再创建一个marker对象,把这个marker绑定到map上

在地图上就可以看到天安门上标记了一个地理位置图标

5

接下来希望点一下这个marker的时候就显示这个位置的具体地址,如下所示,首先创建一个InfoWindow,并把它绑定到上面的那个marker的上方展示,同时给marker添加一个点击事件,一点的时候就打开提示框:

效果如下:

5

这里所有的样式都是谷歌自带的,假设这个marker的样式跟网站的风格不太一致,我想要自定义一个marker不用谷歌自带的,那怎么办呢?在上面new一个marker的时候可以再传一个icon的参数,自定义icon,同时这个icon需要使用svg的格式。

在PSD里面将UI里面的icon形状导成一个AI文件,然后再用AI导出svg,就有了icon的svg格式。打开svg文件,将里面的path、fill等作为地图icon的参数,如下:

就可以将默认的marker样式换掉,如下所示,你也可以换成其它各种各样的形状,像房子、车等icon

7

 

检查一下刚刚添加的marker,发现最后被谷歌地图转换成了一个canvas元素:

8

 

到这里已经可以解决在地图显示北京哪里被水淹了的问题。就是在被水淹的位置添加一个个的marker,现在我希望点击marker的时候能够显示该处的图文受灾情况。可以使用上面介绍的InfoWindow,只要把参数{content: “北京市天安门” },换成{content: “<div class=’detail-info’>…</div>”},然后写detail-info的样式即可。但是这样会有两个问题:

1. 不方便改变InfoWindow那个框的样式,例如没有一个直接的方法可以去掉右上角的x按钮

2. 假设有几百个地方被水淹了,也就是说得添加几百个marker,同时每个marker都得添加一个click事件,因为谷歌的事件没有marker事件委托,每个marker都得一个个加事件,一下子加几百个事件,这样就有点egg pain了。

所以说如果使用了上面的marker的方式,谷歌把它变成了一个canvas,以后所有的操作都得处处受制于谷歌的API,同时谷歌的API并不是十分的丰富和灵活。因此必须得另辟一条路,如果能够用原生的div放到谷歌地图里面那就简单多了,因为地图本身就是用div实现的,所以用原生的应该是可以的。其实只要用谷歌搜一搜就可以找到解决办法

使用原生HTML Marker

谷歌地图还提供了另外一个往地图里面加东西的OverlayView,使用这个的原理就是创建一个OverlayView对象然后给它append一个div,把这个div的position置为absolute(相对于地图的容器container),然后再设置它在这个容器的left/top位置,关键就在于怎样根据当前marker的经纬度转换为在容器的像素位置。而这个对象已经提供了一个转换方法可以调用。将自定义的Marker封装成一个类,例如现在要做一个房源的地图展示,需要把房源标在地图上,自定义一个HouseMarker的类:

再将这个HouseMarker的原型指向谷歌的OverlayView进行继承

然后实现这个原型的draw函数:

再调new HouseMarker,传进当前的经纬度和map对象,就可以在地图正确的位置上显示这个marker了。接下来就能够使用原生的js事件和css控制这个marker了,这样就很方便灵活了。特别是谷歌的mouse事件,即使是上一个marker盖住了下面的marker,鼠标移到上面那个marker时,仍然会触发下面那个marker的事件,这样就有点恶心了。而使用原生的mouse事件就没有这种情况。其实这个也是可以理解的,因为谷歌地图是用的一个canvas画布展示marker,在这个画布里面只根据鼠标的位置和marker的位置判断鼠标有没有进入marker里面,所以不管上面有没有被盖住,只要算出来的位置是符合的。

如下面所示,鼠标hover的时候就显示详细信息,如果这个详细信息刚好下面有个marker就会出现上面讨论的情况:

4

详见:Custom HTML Markers with Google Maps

第二步是的鼠标hover的时候展示详情框,最简单的就是用CSS控制即可,使用上面定义的DOM结构,初始化时让detail-info隐藏:

然后再设置:

就可以了,不用一行JS

第二种办法是监听mouse事件,使用事件委托:

用JS的进行显示和隐藏的好处是:可以对展示做一些后续的处理,这也是下面要提到的

我们已经初步解决了marker展示的问题,但其实还有一些问题:展示这些详细信息会出现超出可见区域的情况

边界判断

当这个marker比较靠边的时候,详情的框会超出显示范围:

9

 

所以需要做边界判断,不管marker在什么位置,详情框都可以在展示区域内显示,效果如下:

10

 

也就是说需要判断当前marker是否超出了地图容器能够正常显示的范围,如果超出了就要做下处理——如果太靠上就把详情展示在下面,如果太靠右详情框就不应该是和marker水平居中了,而是要往左移一移,同时把三角形的位置挪一挪。所以关键是要做一个边界判断,而做边界判断的前提是拿到marker在容器里面的left/top位置。

已经不可以再上使用上面获取位置的方法了,因为那个位置算好之后不会再变,不会跟着地图的拖动而发化变化,谷歌地图是借助transform等设置改变它的位置,而不是用position了。

但是可以拿到当前地图在这个容器里面的边界经纬度,最东、最西、最北、最南,也可以拿到这个容器的像素宽高,所以就可以知道一个像素对应地图多少经纬度,即像素/经纬度的比例ratio。同时marker的纬度是知道的,可以算一下它距离边界的经纬度dx, dy,dx除以ratio就能够换算像素值了。代码如下:

还有一种情况是如果详情框太长了,超出了容器的一半,不管向上显示还是向下显示,marker刚好在正中间时,详情框都会超出显示范围。这种情况可以借助第二种解决办法,就是将地图移动一下,超出的就可以显示了。需要计算移动后的地图中心点在哪里,再调API提供的panTo就可以了,如下。难点是计算要正确

panTo

 

绘制形状

接下来再简单讨论一个高级话题,就是在谷歌地图上面绘制一个形状,然后获取该形状的地理位置。谷歌已经提供了一个叫DrawingManager的类,只要new一个对象,传些参数,就可以在地图上显示draw tool了,如下:

11

然后再监听这个manager的complete事件,在complete事件里面获取当前画的图形的范围,例如上面的圆可以获取到它的圆心和半径。详见:Drawing Layer (Library)

然而谷歌提供的这个工具非常的简陋,你无法直接改变上面工具栏的icon,就连画的圆边界也是扭扭曲曲的,如上所示。只提供了完成事件,没有画时候的事件,所以你没办法在画的时候加一个不断变化的、显示所画范围多少公里的提示框。

因此另外一个解决办法是自已实现一个类似的工具,通过鼠标的mousedown、mousemove、mouseup事件搭配组合,结合上面推荐的画marker的方法,插入svg元素,动态改变它的path做到实时变化的效果。这样就很灵活了,想怎么搞就怎么搞,但是代码量应该也是挺大的。

 

除此之外还有街景、3D控制的API,这里不再讨论,有兴趣自己查查谷歌的API。

原博客园地址:http://www.cnblogs.com/yincheng/p/google-map.html

Google地图开发总结》有18个想法

  1. 博主,能把源代码分享一份吗。我这儿遇到一个问题,我用的是谷歌地图自带的mark,我现在要一个鼠标悬浮然后弹出一个框。但是鼠标移入事件不生效!

发表评论

电子邮件地址不会被公开。