个人博客

A web front-end programmer's personal blog.

Google地图和百度地图自定义覆盖层

Google地图(英语:Google Maps;前称:Google Local)是Google公司向全球提供的电子地图服务,地图包含地标、线条、形状等信息,提供矢量地图、卫星照片、地形图等三种视图。其姊妹产品包括Google地球、Google月球、Google火星、Google星空、Google海洋。总所周知,都是些非常牛叉的产品,本人分享个Google地球的软件给喜欢的朋友,下载请点击这里

百度地图是百度于2005年9月发布的服务项目,它是百度公司与北京图为先科技有限公司联合开发的电子地图服务。

目前,国内还有高德地图,搜搜地图(腾讯地图)等,个人还是比较喜欢搜搜地图。

下面整理下项目中关于应用这两个地图的相关内容,主要是两个地图的自定义覆盖物的部分,如果会绘制自定义覆盖物基本上可以在地图上绘制自己想要的div了。


####百度地图部分

百度地图自定义覆盖物的方法为BMap.Overlay(),基本的用法如下:

// 复杂的自定义覆盖物 构造方法
function ComplexCustomOverlay(pro1,pro2){
  this._div = null;
  this.pro1 = pro1;
  this.pro2 = pro2;
  //.... 此处为你的自定义覆盖层添加一些公共的属性
}

//算是继承自定义覆盖层的一些属性和方法
ComplexCustomOverlay.prototype = new BMap.Overlay();  
//初始化
ComplexCustomOverlay.prototype.initialize = function(map){
    this._map = map;
    //此处添加自定义覆盖层 div 的结构和一些属性参数,即模板
    //通过给定class和data-属性方便对其添加事件和操作
    var $div = this._div = $('<div class="mapTemp" data-....></div>');

    //可以同时对div中的DOM绑定事件
    $div.mouseover(function(){});
    $div.click(function() {});

    //将div插入到地图中,注意如果是jquery的dom要转成js的dom
    map.getPanes().floatShadow.appendChild($div[0]);
    return $div[0];
};

//绘制
ComplexCustomOverlay.prototype.draw = function(){
  var map = this._map;
  var pixel = map.pointToOverlayPixel(this._point);
  //下面是通过自定义属性完成一些跟位置有关的交互,不用可取消
  //this._div.attr('data-top',pixel.y - 5);
  this._div.css({
    left: pixel.x - 5,
    top: pixel.y - 10
  });
};
//使用
var map = new BMap.Map(id);
var point = new BMap.Point(longitude,latitude);
var marker = new ComplexCustomOverlay(point,pro2,pro3);
map.addOverlay(marker);

以上是一个自定义覆盖层的简单用法,项目中的需求一般都较为复杂,在微游记项目中,首先要解决一个页面加载多个地图和选项卡切换导致隐藏地图不能很好的展示,已经自定义数据的录入和交互效果的完成等。

对于一个简单百度地图的示例,代码如下:

//id 为地图的容器
var map = new BMap.Map(id);
var point = new BMap.Point(longitude, latitude);//传入经纬度
map.centerAndZoom(point, zoomlev); //初始化地图的放大层级
//==地图事件开始
map.enableScrollWheelZoom();//启用地图滚轮放大缩小
map.enableKeyboard();//启用键盘上下左右键移动地图
//==地图事件结束
map.setViewport(pointArray); //让所有点在可视区内
//====添加控件开始
//向地图中添加缩放控件
var ctrl_nav = new BMap.NavigationControl({anchor:BMAP_ANCHOR_TOP_LEFT,type:BMAP_NAVIGATION_CONTROL_LARGE});
map.addControl(ctrl_nav);

更多的关于地图中控件的使用,参考API,此处就不整理了。

由于隐藏切换导致的地图加载问题 可以通过在将其封装为函数,每次切换时调用该函数即可。下面是项目中封装的函数:

function tabMap(id,longitude,latitude,zoomlev,arr){
    var map = new BMap.Map(id);
    var point = new BMap.Point(longitude, latitude);
    map.centerAndZoom(point, zoomlev);
    var hotelJson = arr;
    //initInfo函数是用来遍历数据,生成对应的覆盖层,即上面的覆盖层类
    initInfo(hotelJson,map);
    //==地图事件开始
    map.enableScrollWheelZoom();//启用地图滚轮放大缩小
    map.enableKeyboard();//启用键盘上下左右键移动地图
    //==地图事件结束
    map.setViewport(pointArray); //让所有点在可视区内
    //====添加控件开始
    //向地图中添加缩放控件
    var ctrl_nav = new BMap.NavigationControl({anchor:BMAP_ANCHOR_TOP_LEFT,type:BMAP_NAVIGATION_CONTROL_LARGE});
    map.addControl(ctrl_nav);

}

PS: 经纬度的参数必须是Number类型,不能是字符型的数字。

生成自定义覆盖层的initInfo函数

function initInfo(json,obj){
    for(var i=0; i<json.length; i++){
        //解决闭包
        (function(a){
            //判断是否区分主点和覆盖点
            if(!json[a].poi){
                var point = new BMap.Point(json[a].longitude,json[a].latitude);
                var marker = new ComplexCustomOverlay(point,a,json[a]);
                obj.addOverlay(marker);
            }else{
                //对主点应用百度地图的控件
                var pt = new BMap.Point(json[a].longitude,json[a].latitude);
                var myIcon = new BMap.Icon("http://developer.baidu.com/map/jsdemo/img/fox.gif", new BMap.Size(300,157));

                var content = '<div style="margin:0;line-height:20px;padding:2px;">' +
                '地址:'+json[a].adress+'<br/></div>';                    

                var searchInfoWindow = null;

                searchInfoWindow = new BMapLib.SearchInfoWindow(obj,content,{
                    title  : json[a].title,      //标题
                    width  : 290,             //宽度
                    //height : 105,              //高度
                    panel  : "panel",         //检索结果面板
                    enableAutoPan : true,     //自动平移
                    searchTypes  :[
                        //BMAPLIB_TAB_SEARCH,   //周边检索
                        BMAPLIB_TAB_TO_HERE,  //到这里去
                        BMAPLIB_TAB_FROM_HERE //从这里出发
                    ]
                });
                // 创建标注
                var marker = new BMap.Marker(pt,{icon:myIcon},searchInfoWindow);
                marker.addEventListener("mouseover", function(e){
                   searchInfoWindow.open(marker);
                });
                obj.addOverlay(marker);
            }
        })(i)
    }
}

该函数将数据库取回的数据依次遍历生成覆盖层插到指定的地图中,通过一个自执行函数解决构造函数无法遍历问题,另外对主点引用百度的交通线路控件,该控件还要先引入下面两个百度插件:

//css
<link rel="stylesheet" href="http://api.map.baidu.com/library/SearchInfoWindow/1.5/src/SearchInfoWindow_min.css" />
//js
<script type="text/javascript" src="http://api.map.baidu.com/library/SearchInfoWindow/1.5/src/SearchInfoWindow_min.js"></script>

这样只要将数据库中的数据拼接成相应的json变量传入到对应的函数中就可以实现相应的功能了。

####谷歌地图部分

由于某党的英明领导,很多Google的功能都用不了,不过还好地图部分还没有完全被墙,想要开发Google地图部分可以引用下面的JS,不借助VPN,只是速度慢。

<script src="http://ditu.google.cn/maps/api/js" type="text/javascript"></script>

另外还有关于Google地图的 Gmap.js插件,详情点击这里,这个插件已经可以完成常见的相关功能了,但我没有在它上面找到这个项目的接口,无奈只好看Google地图的API,点击这里,需要VPN你懂的。。

同样,Google地图的自定义覆盖层的构造函数代码如下:

//谷歌自定义覆盖层的构造函数
function USGSOverlay(pro1,pro2,map) {
  this._div = null;
  this.pro1 = pro1;
  this.pro2 = pro2;
  //.... 此处为你的自定义覆盖层添加一些公共的属性
  this.setMap(map);  //必须与地图关联
}

USGSOverlay.prototype = new google.maps.OverlayView();
USGSOverlay.prototype.onAdd = function() {
    //此处添加自定义覆盖层 div 的结构和一些属性参数,即模板
    var $div = this._div = $('<div data-....></div>');

     var panes = this.getPanes();

     panes.overlayLayer.appendChild($div[0]);
     //console.log(panes.overlayMouseTarget.appendChild($div[0]))
     panes.overlayMouseTarget.appendChild($div[0]);
     //http://stackoverflow.com/questions/13912754/mouseover-on-custom-overlay-in-google-maps
     //通过addDOMListener来给div绑定事件
     google.maps.event.addDomListener($div[0], 'mouseover', function(ev){
        //事件处理
     });
     //或直接绑定事件
     $div.on('mouseover',function(){
        //事件处理
     })

};

USGSOverlay.prototype.draw = function(){
  var overlayProjection = this.getProjection();
  var pos = overlayProjection.fromLatLngToDivPixel(this._point);
  var $div = this._div;
  //下面是通过自定义属性完成一些跟位置有关的交互,不用可取消
  //$div.attr('data-top',pos.y - 5);
  $div.css({
    left : pos.x,
    top : pos.y,
    width: 50,
    height: 50
  });
};

给自定义覆盖层绑定事件也可以用dom的target

$('map').on('click',target,function(){
    // map 为地图的div 容器
    // target 自定义覆盖层的 class
})

生成一个普通的Google地图地图的代码函数:

function g_tabMap(id,longitude,latitude,zoomlev,json,arr){  
    var mapOptions = {
        zoom: zoomlev,
        center: new google.maps.LatLng(longitude, latitude),
        mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    var map = new google.maps.Map(document.getElementById(id),mapOptions);
    //同上百度,googleIntial函数是用来遍历数据,生成对应的覆盖层,即上面的覆盖层类
    googleIntial(map,json);

}
//普通调用
g_tabMap();

同上,通过googleIntial函数来循环数据渲染

function googleIntial(obj,json){        
    for(var i=0; i<json.length; i++){
        (function(a){
            if(!json[a].poi){
                var point = new google.maps.LatLng(json[a].longitude,json[a].latitude);
                //var bounds = new google.maps.LatLngBounds(point, point);
                var overlay = new USGSOverlay(point,a,obj, json[a]);
            }else{
                var image = 'http://pic.lvmama.com/img/you/view_point.png';                         
                var point = new google.maps.LatLng(json[a].longitude,json[a].latitude);
                var marker = new google.maps.Marker({
                    position : point,
                    map: obj,
                    icon : image
                });
                marker.setMap(obj);
            }
        })(i)
    }
}

PS: 需要注意的是通过addDOMListener来给Google地图中的DOM元素绑定事件。

关于谷歌地图的实例demo 关于百度地图的实例demo


更多的功能还要详细的研究相应的地图API,需要根据项目的需求来进行。此处只是记录了我在项目需求中的一些心得,希望会对自己和需要的人有帮助。