Chinaunix首页 | 论坛 | 博客
  • 博客访问: 71919
  • 博文数量: 34
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 287
  • 用 户 组: 普通用户
  • 注册时间: 2013-11-26 15:01
文章分类
文章存档

2013年(34)

我的朋友

分类: jQuery

2013-12-11 16:03:52

推推99地图找房 的jquery实现,开发中主要参考了推推99的地图找房,推推99使用了prototype.js 库,下面使用的是jquery库,其版本为jquery-1.3.2.js  ,还有保存哈希对象的hash.js  类,主要根据自己开发过程中遇到的问题及解决方法去描述
一、Google地图编程基础

简单描述下Google Map编程中用到的术语,如覆盖对象,地图分层等,以便后面现实中用到术语的统一及理解,已了解可跳过,查看下节的实现步骤,更加详细请参考Google地图API文挡 。

1、google地图编程 

使用方法 GEvent.addListener或 GEvent.bind” 监听”事件。

2)信息窗口

信息窗口包含内容区域和锥形箭头,锥形箭头指向地图上的指定点。

3)覆盖对象

覆盖在地图上有固定经纬度坐标位置的对象,当拖动地图或改变地图类型时,会跟着移动。
Maps API支持两种类型的覆盖对象:标记(GMarker),图标(GIcon)。折线(GPolyline)是用一系列点形成的折线 。

4)控件

缩放工具条、选择地图类型等空间,使用addControl方法向地图增加控件。

2、google地图分层

二、地图找房实现及步骤

实现思路: 

根据物件刊登地址(县市,乡镇,巷、弄、号)抓取Google Map经纬度,在地图G_MAP_MAP_PANE层上添加自定义叠加层,根据条件面板条件显示物件集合及数目,叠加层使用javascript监听鼠标移上、移开、点击等事件,并作出对应的外观改变、弹窗显示物件等响应。
实现步骤: 
2.1、根据经纬度定位并显示物件集合
函数GMap2.fromLatLngToDivPixel(latlng:GLatLng),计算指定地理位置在含有可拖动地图的DOM元素中的像素坐标。如,“深圳图书馆”的经纬度P(22.547083441500213,114.05717031860352),初始地图DOM的ID为“map_canvas”,如下可得“深圳图书馆”在“map_canvas”的像素坐标: 
   map = new GMap2(document.getElementById("map_canvas"));//初始地图

  var point = new GLatLng(22.547083441500213,114.05717031860352);//经纬度

        var L = map.fromLatLngToDivPixel(point);//集合定位

        var div = document.createElement("div");

        div.innerHTML = "深圳图书馆
";

        div.style.left = Math.min(L.x, L.x) + "px";

        div.style.top  = Math.min(L.y, L.y) + "px";

        map.getPane(G_MAP_MAP_PANE).appendChild(div);//添加到地图

2.2、移动缩放地图重新定位物件集合

查看例子会发现,地图缩放后再移动时,自定义叠加层、地图marker、实际地址就不再三点合一,出现位置偏移。解决这个问题,使用一个小技巧,缩放移动地图后,结束地图视图的更改时会触发moveend()事件。因此,监控事件,当moveend()时,删除前次所有自定义的叠加层,然后重新计算DOM元素中的像素坐标,显示控件,即moveend()后: 

1)移除地图前次所有自定义的叠加层。

2)根据经纬度重新计算DOM元素中的像素坐标,显示控件 。


2.3、移动缩放地图保留区域集合,删除视野外集合,加载增加视野区域集合


1)、如何确定地图的显示区域范围?


2)、移动地图后,如何获取前次显示范围对应的物件集合,从而保留原来的保持不变,只增加新区域物件集合?

问题1:确定地图显示区域 

函数GMap2.fromDivPixelToLatLng(pixel:GPoint),根据含有可拖动地图的div中的像素坐标计算地理坐标。如下图,地图显示区域定义两点,假设左下角点像素坐标P1(x,y),根据地图容器宽度及高度,可计算到右上角点为P2(x+$("#map_canvas").width(), y+$("#map_canvas").height()),最后,可通过GMap2.fromDivPixelToLatLng(pixel:GPoint)计算出显示区域的地理坐标,即经纬度范围,如,经度从slngFrom到slngTo,维度从slatFrom到slatTo(实际中我们会减去地图类型、地图缩放等控件的区域)。

实际使用代码: 

        function getBounds()
        {
            var E = 80;

            var G = map.fromContainerPixelToLatLng(new GPoint(E, E / 2));

            var D = map.fromContainerPixelToLatLng(new GPoint($("#map_canvas").width() - E / 2, 

$("#map_canvas").height() - E / 2));

            var B = D.lat().toFixed(3);

            var A = G.lat().toFixed(3);

            var F = G.lng().toFixed(3);

            var C = D.lng().toFixed(3);

            this.bounds = {

                slatFrom: B,

                slatTo: A,

                slngFrom: F,
                slngTo: C
            }

        }

结合前面,监听地图的事件,当触发moveend()时,只要执行上面的函数,即可以得到地图当前显示区域的经纬度范围。ajax请求服务器,获取对应范围的物件集合,其中SQL类似“WHERE lat>=slatFrom AND lat<=slatTo AND lng>=slngFrom AND lng<=slngTo”。

问题2:保留前次物件集合数据 

每个物件集合对应一组唯一的经纬度,数据库设计可为每组经纬度对应一个唯一的自动增加的编号ID,每次ajax获取到的数据都保存在以ID为键,经纬度、名称等组成的数组为值的哈希序列中,使用网上哈希对象类 保存前次数据,具体用法可以参考里面的说明,下面简单的看下使用到的部分:
 
        /*

         * json格式:

         * {collectId:["name",'count',"lat","lng","fullname","postId'","casesId"]}

         * 实际数据:

         * {1001:["梅林一村",'20',"22.5653936421316","114.038043022156","梅林一村","",""], 

1002:["彩天名苑",'8',"22.5379670676697","114.068727493286","彩天名苑","","98550"]}

         */

        var m = this.mapMarkers; //前次保存的哈希对象

        var H = new hash();

        $.each(json,function( collectId, data ) {

            H.put( collectId, data ); //保存哈希对象

        });

        ...

        if ( L==0 ) {    

        } else {

            //前次物件集合

            m.forEach( function( data, collectId ) {

                //不在当前区域或集合数目不同

                if ( !H.contains(collectId) || H.get(collectId)[1]!=data[1] ) {

                    ...

                    m.remove(collectId); //移除哈希对象

                    $("#"+collectId).remove(); //移除地图叠加层

                } else {

                    ...

                    $("#"+collectId).remove(); //移除地图叠加层

                    drawMarker( marker, L.y, L.x, point ); //重显示地图叠加层

                }

            });


        }

        //当前JSON处理

        var timer = 0;

        $.each( json,function( collectId, data ) {

            //当前区域新增

            if ( !m.contains(collectId) ) {

                window.setTimeout( function() {

                    ...

                    m.put(collectId, data); //移除地图叠加层

                    drawMarker(marker, L.y, L.x, point); //显示地图叠加层

                },timer++*30);

            }

        });

注意示例中,地图初始显示5个物件集合点,拖动后假设请求的数据为:移除 最左边66间的“东方时代广场”,保留 另外4个物件,其中改变 最右下64间的“美园MAY HOUSE”为164间,新增 最右上两个新的集合(173间和135间的两个物件集合)。 

2.4、jquey自定义事件绑定及触发 

因工作需要,页面显示和地图显示、API交互等分开两人开发,页面点击调用地图显示部分代码。如用户点击县市,显示乡镇,定位地图中心点,使用jquery自定义事件,监听“map:center”事件,点击县市时触发事件,并传递县市经纬度、缩放级别等参数,如下代码所示: 

事件监听: 
 
        $(document).bind(“map:center”,function(event, E) {

            map.setCenter(new GLatLng(E.lat, E.lng), E.zoom);

        });  

事件触发: 
 
        $("#region").bind(“click”,function(event) {

            initSection(rid);//初始乡镇

            //触发

            $(document).trigger(“map:center”,

            {

                lat:G,lng:B,zoom:this.zoom

            });

        });
2.5、sphinx使用setGroupBy函数根据条件筛选物件,统计并排序集合物件数目

地图放大级别很小时,如地图包括整个深圳市,此时若把地图对应区域(整个深圳市)物件集合显示出来,数据是非常大的,因此,我们可能要求,地图放大到某级别时候,覆盖范围大,而只要显示对应物件集合最多的前100个集合。一般做法: 

1)、根据选择条件、区域筛选物件集合,然后GROUP BY集合ID。

2)、根据步骤1)统计集合物件数目。

3)、根据步骤2)排序,输出前100个记录。

在sphinx中只要进行以下操作: 
 
        //显示的数目

        $conf['limit'] = 100;

        $sp->SetLimits(0, $conf['limit'], $this->_maxmatches);

        //SetGroupBy

        $sp->SetGroupBy('collect_id', SPH_GROUPBY_ATTR, '@count desc');

        $result = $sp->Query($this->Spx_q, $sp_index);

        $_collect_count = $result['matches'][view_id]['attrs']['@count'];//物件数目
以上就返回根据字段collect_id作GROUP BY后,以物件集合总数倒序的100条记录,其中物件数目保存在@count属性。
阅读(1336) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~