Google地图开发总结

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

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

谷歌地图的组成

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

谷歌地图的使用

引入谷歌地图

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

<script src="http://ditu.google.cn/maps/api/js?key=AIzaSyBp&language=zh-CN"></script> <!-- 中国版 -->
<!--正常版,需FQ  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBp"></script> -->

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

<div id="map" style="width:100%;height:500px"></div>

初始化谷歌地图

var mapType = google.maps.MapTypeId.ROADMAP;
var lat = 39.915168, lng = 116.403875, zoom = 10;
var mapOptions = {
    center: new google.maps.LatLng(lat, lng),  //地图的中心点
    zoom: zoom,                         //地图缩放比例
    mapTypeId: mapType,                 //指定地图展示类型:卫星图像、普通道路
    scrollwheel: true                    //是否允许滚轮滑动进行缩放
};
var map = new google.maps.Map(document.getElementById("map"), mapOptions); //创建谷歌地图

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

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

添加一个Marker

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

var marker = new google.maps.Marker({
    map: map,
    position: new google.maps.LatLng(lat, lng)
});

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

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

var infowindow = new google.maps.InfoWindow({content: "北京市天安门" }); //创建一个InfoWindow
infowindow.open(map, marker); //把这个infoWindow绑定在选定的marker上面
//给这个marker添加点击事件
google.maps.event.addListener(marker, "click", function(){
    infowindow.open(map,marker);
});

效果如下:

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

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

var locationMarker = {
    path: ‘M22 10.5c0 .895-.13 1.76-.35 2.588C20.025 20.723 13.137 28.032 11 28 9.05 28 3.2 21.28.926 14.71.334 13.42 0 11.997 0 10.5c0-.104.013-.206.017-.31C.014 10.117 0 10.04 0 9.967c-.005-.67.065-1.112.194-1.398C1.144 3.692 5.617 0 11 0c5.416 0 9.906 3.74 10.82 8.657.112.29.18.696.18 1.31 0 .083-.013.167-.015.25.003.095.015.188.015.283zM11 5.833c-2.705 0-4.898 2.09-4.898 4.667S8.295 15.167 11 15.167s4.898-2.09 4.898-4.667c0-2.578-2.193-4.667-4.898-4.667z‘,
    fillColor: ‘#E84643‘,
    fillOpacity: 1,
    strokeColor: ‘#E84643‘,
};
var marker = new google.maps.Marker({map: map, icon: locationMarker, position: new google.maps.LatLng(lat, lng)});

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

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

到这里已经可以解决在地图显示北京哪里被水淹了的问题。就是在被水淹的位置添加一个个的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的类:

function HouseMarker(latlng, map, args) {
    this.latlng = latlng;    //for google map
    this.setMap(map);        //for google map
    this.args = args;        //自定义参数
}

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

HouseMarker.prototype = new google.maps.OverlayView();

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

HouseMarker.prototype.draw = function() {
    //创建一个div
    $div = $("<div class=‘marker-container‘><div class="marker"></div><div class=‘detail-info‘ style="display:none"></div></div>");
    //将div添加到它的dom元素里面
    var panes = this.getPanes();
    var div = $div[0];
    panes.overlayImage.appendChild(div);
    //计算经纬度计算div的像素位置
    var point = this.getProjection().fromLatLngToDivPixel(this.latlng);
    div.style.left = (point.x - 20) + ‘px‘;    //减掉marker宽度的一半,居中
    div.style.top = (point.y - 20) + ‘px‘;    //减掉marker高度的一半,居中
};

再调new HouseMarker,传进当前的经纬度和map对象,就可以在地图正确的位置上显示这个marker了。接下来就能够使用原生的js事件和css控制这个marker了,这样就很方便灵活了。特别是谷歌的mouse事件,即使是上一个marker盖住了下面的marker,鼠标移到上面那个marker时,仍然会触发下面那个marker的事件,这样就有点恶心了。而使用原生的mouse事件就没有这种情况。

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

详见:Custom HTML Markers with Google Maps

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

边界判断

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

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

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

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

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

var mapBounds = mapHandler.getBounds();      //调用谷歌的api获取容器经纬度边界并做一些处理
var xRatio = (mapBounds[1] - mapBounds[0]) / mapWidth,
      yRatio = (mapBounds[3] - mapBounds[2]) / mapHeight;
//marker的经纬度
var lat = marker.latlng.lat(),
      lng = marker.latlng.lng();
//转换marker的像素位置
var pos = {
    top:   -(+lat - mapBounds[3]) / yRatio,
    left:   (+lng - mapBounds[0]) / xRatio,
    bottom: (+lat - mapBounds[2]) / yRatio,
    right: -(+lng - mapBounds[1]) / xRatio
};
var posFlag = 0,
    maxLen = 150,    maxLeftLen = 118;
//右边超出
if(pos.right < maxLen) posFlag |= 1;
//上面超出
if(pos.top < maxLen) posFlag |= 2;
//左边超出
if(pos.left < maxLeftLen) posFlag |= 4;
//对超出的情况进行处理,代码略
switch(posFlag){
      case 1: //右
      case 2: //上
      case 3: //右上
      case 4: //左
      case 6: //左上
}

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

绘制形状

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

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

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

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

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

时间: 2024-10-01 07:51:58

Google地图开发总结的相关文章

Google地图开发初级篇

上回我们学习了如何搭建一个google map应用,了解了基础知识,下面我们来深入学习google map中待发掘的宝藏 在这篇文章,我将告诉你 1.   如何创建google地图 2.   Google地图 的模式,和地图类型 3.   Google地图上的控件使用 4.   Google地图的点击事件和其他事件 5.   摄像头移动知识 一. 地图对象 1.  获得地图对象 A.   地图控件所在的fragment 在上一篇中,我们自动生成项目后,可以看到MapActivity和它的布局文件

Google地图

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

Android 百度地图开发(一)--- 申请API Key和在项目中显示百度地图

标签: Android百度地图API Key  分类: Android 百度地图开发(2)  最近自己想研究下地图,本来想研究google Map,但是申请API key比较坑爹,于是从百度地图入手,其实他们的用法都差不多,本篇文章就带领大家在自己的Android项目中加入百度地图的功能,接下来我会写一系列关于百度地图的文章,欢迎大家到时候关注!   一 申请API key 在使用百度地图之前,我们必须去申请一个百度地图的API key,申请地址http://lbsyun.baidu.com/a

Android地图开发之地图的选择

做lbs开发差不多快2年了,地图相关的产品也差不多做了3个了,用到过的地图包括google地图.高德地图.百度地图.图吧.Osmdroid,今天总结下,方便大家开发时选择合适的地图. 首先说定位模块选择,高德地图.百度地图现在都有了单独的地位sdk,且都支持全球定位,都是非常不错的选择.我现在做的项目对定位要求很高,现在的选择是gps定位使用系统定位方式,基站定位使用百度定位,gps连接成功使用系统定位接口,gps断开切换到百度基站定位. gps定位,百度和高德都用过,但是测试发现没有同类产品统

android 百度地图开发实例(转载)

因为在我的寝室google基站定位返回的数据总是为空,所以换成百度地图,发现百度地图开发起来非常方便,提供了许多有用的工具,地图的加载速度也比google地图快许多. 为了加强记忆,写一点android 百度地图开发常用的方法. 1初始化 MapManager mBMapMan = new BMapManager(this);boolean isSuccess = mBMapMan.init(this.mStrKey, new MyGeneralListener()); isSuccess 的值

Google 地图 API for Android

原文:Introduction to Google Maps API for Android 作者:Eunice Obugyei 译者:kmyhy 从健康类 app Runkeeper 到游戏 app 精灵宝可梦,位置服务对现代 app 来说越来越重要. 在本文中,我们将创建一个 app,名字就叫做 City Guide.这个 app 允许用户搜索一个地点,使用 Google 地图显示这个地点的位置并监听用户的位置改变. 我们将学习如何使用 Google 地图 API for Android,G

Google地图接口API之地图基础

拥有一个免费的API Key之后就可以正式调用Google的API了进行开发了. 创建一个简单的 Google 地图: <html> <head> <script src="http://maps.googleapis.com/maps/api/js?key=AIzaSyDY0kkJiTPVd2U7aTOAwhc9ySH6oHxOIYM&sensor=false"> </script> <script> functio

[转]Net Framework引路蜂地图开发示例

From:http://www.2cto.com/kf/201207/140421.html 引路蜂地图也提供对.Net Framework平台的支持,可以开发桌面地图应用,由于Mono C#的跨平台特性,使用Visual Studio 和Mono引路蜂地图开发包开发的地图应用可以运行于Windows ,Lunix,Unix,Mac OS等平台.开发桌面应用比开发移动应用要容易的多,屏幕,内存等方面都比移动平台要宽裕的多.下面使用一个简单的应用来介绍一下.Net Framework引路蜂地图开发

jplogic之GIS搜狗地图开发案例

在项目开发过程中我们可能遇到各种各样的需求,而GIS在应用便是其中一个.特别是在web类型的项目中会经常用到.我们都知道 网络地图服务,以其实时性.大信息量.丰富的功能,成为传统地图的延伸,同时扩展出无法替代的实用性和功能性,随着互联网的发展,网络地图已成为人们经常使用的互联网服务之一.因此我们可以在很多类型的应用中看到这些应用关于GIS技术的运用.我们可以在很多地方可以看到它的身影,比如google地图.百度地图.高德地图.搜狗地图等,这些电子地图服务商都提供大量的API允许开发者很方便在自己