zoukankan      html  css  js  c++  java
  • 腾讯地图点聚合应用之地图找房

    链家实现的效果

    分析

    地图找房功能使用点聚合来实现的。官网示例如下:https://lbs.qq.com/javascript_v2/sample/overlay-markercluster.html

    链家的地图找房主要分为三层。第一层为市区层,比如南山、罗湖等;第二层为片区,比如南头、科技园等;第三层则为小区。

    因为第一层,第二层的数据没有那么多,这两个接口都是把所有的数据一次返回给前端。但是第三层的数据量就非常的巨大了,链家采取的是返回部分数据,将前端页面上显示的最大经纬度以及最小经纬度传给后台,后台再将筛选后的数据返回给前端。(接口地址大家可以使用 Chrome 的开发工具进行抓包,这里需要注意的是链家的接口采用 jsonp 的形式,所以需要抓取 JS)

    实现

    首先需要添加腾讯地图的API,这里推荐使用异步加载的方式。因为项目使用 Vue 进行开发的单页应用,有可能用户并没有进入地图找房的页面,所以这里建议在打开地图找房的页面时添加腾讯地图的API。

    异步加载需要避免一个重复加载的问题,即不管用户是第几次打开地图找房,地图的 API 都是同一个。 这里为了降低代码复杂度,没有使用单例模式,具体的代码如下:

    const TXMap = {
      map: undefined, // 地图实例
      // 异步加载获取api
      getApi (funName) {
        let script = document.createElement('script')
        script.type = 'text/javascript'
        script.src = `http://map.qq.com/api/js?v=2.exp&callback=${funName}`
        document.body.appendChild(script)
      }
    }
    

    可以看到异步加载就是动态加入 script 标签,src 为腾讯地图 api 的地址,src 包含一个 callback 参数,表示 js 加载完毕后会调用 funName 这个函数。添加了地图 api 之后,window 对象会有一个 qq.maps 对象,我们可以用来判断是否已经添加了 api,来避免重复添加 api。

    接下来就是实现自定义覆盖物这个方法了。还是参照官方文档:https://lbs.qq.com/javascript_v2/doc/overlay.html

    const TXMap = {
      map: undefined,
      overlays: [], // 存放所有覆盖物
      sourceData: [], // 原始数据
      listener: undefined, // 地图缩放或平移的事件监听器
    
      getApi () {}, /* 前面已经声明,此处省略 */
    
      // 实现自定义覆盖物
      drawOverlay (options) {
        let _this = this // 下面有多个 window 对象的方法,避免 this 的指向问题
        this.sourceData = options.data // 存放原始数据
        // 绘制覆盖物之前,清理之前绘制的覆盖物
        this.clearOverlays()
    
        // 如果 initMap 方法已经实现,那么我们可以直接调用,否则需要进行定义
        if (window.initMap === undefined) {
          window.initMap = function () {} // 绘制覆盖物的具体实现 
    
          // 地图 api 如果没有引入则调用 getApi 方法,否则直接调用 initMap ()
          window.qq === undefined ? this.getApi('initMap') : window.initMap()
        } else {
          window.initMap()
        }
      },
      // 清除自定义覆盖物
      clearOverlays () {
        let overlay
        while (overlay = this.overlays.pop()) {
          overlay.onclick = null // 移除点击事件
          overlay.parentNode.removeChild(overlay) // 移除 dom 元素
        }
      },
      // 在 Vue 组件的 beforeDestroy 调用,重置地图,移除时间为监听,避免内存泄漏
      clearMap () {
        this.map = undefined
        if (this.listener) {
          window.qq.maps.event.removeListener(this.listener)
        }
      }
    }
    

    这个地图找房的架子到此就搭得差不多了,接下来就看看绘制覆盖物的具体实现了,也就是 initMap 这个方法。

    window.initMap = function () {
      if (_this.map === undefined) {
        // 地图对象为undefined时, 需要进行地图的绘制
        _this.map = new window.qq.maps.Map(document.getElementById(options.containerId), {
          // 初始化地图中心
          center: new window.qq.maps.LatLng(options.lat || 22.702, options.lng || 114.09),
          // 初始化缩放级别
          zoom: options.zoom || 10,
          // 地图最小缩放级别
          minZoom: 10,
          // 停用缩放控件
          zoomControl: false,
          // 停用地图类型控件
          mapTypeControl: false
        })
        // idle 事件, 地图缩放或平移之后触发该事件
        _this.listener = window.qq.maps.event.addListener(_this.map, 'idle', () => {
          // 获取当前地图可视范围的最大最小经纬度
          let bounds = _this.map.getBounds()
          // 获取当前地图的缩放级别
          let zoom = _this.map.getZoom()
          // 调用 Vue 组件对 idle 事件的处理函数
          options.callback && options.callback(bounds, zoom)
        })
      }
    
      // 自定义覆盖物
      if (window.CustomOverlay === undefined) {
        window.CustomOverlay = function (lat, lng, name, houseCount) {
          // 调用地图 api 计算出覆盖物的位置
          this.position = new window.qq.maps.LatLng(lat, lng)
          this.name = name // 区域名
          this.houseCount = houseCount // 房源数量
        }
        // 继承 Overlay
        window.CustomOverlay.prototype = new window.qq.maps.Overlay()
        // 自定义覆盖物构造函数,定义覆盖为的 DOM 结构,DOM 结构,样式大家可以根据需求自己绘制
        window.CustomOverlay.prototype.construct = function () {
          let div = this.div = document.createElement('div')
          div.className = 'my-overlay' // 覆盖物类名
          // 覆盖物 html 结构
          this.div.innerHTML = `<p class="count" >${this.houseCount}<span>套</span></p><p class="name">${this.name}</p>`
          //将dom添加到覆盖物层,overlayMouseTarget的顺序容器 5,此容器包含透明的鼠标相应元素,用于接收Marker的鼠标事件
          this.getPanes().overlayMouseTarget.appendChild(div)
          // 将 div 添加到 overlays,可以用以后续处理
          _this.overlays.push(div)
          // 定义覆盖物的点击事件
          let center = this.position
          this.div.onclick = function () {
            // 点击之后对地图进行缩放以及平移
            let zoom = _this.map.getZoom()
            if (zoom < 13) {
              _this.map.setCenter(center)
              _this.map.setZoom(13)
            } else if (zoom >= 13 && zoom < 15) {
              _this.map.setCenter(center)
              _this.map.setZoom(15)
            }
          }
        }
    
        // 实现 draw 接口来绘制 DOM 元素
        window.CustomOverlay.prototype.draw = function () {
          let overlayProjection = this.getProjection()
          // 获取覆盖物容器的相对像素坐标
          let pixel = overlayProjection.fromLatLngToDivPixel(this.position)
          let divStyle = this.div.style
          // 根据 DOM 元素调整定位的位置
          divStyle.top = pixel.y - 53 + 'px'
          divStyle.left = pixel.x - 30 + 'px'
        }
      }
    
      // 根据接口数据绘制覆盖物
      if (_this.sourceData.length > 0) {
        _this.sourceData.map(item => {
          let customOverlay = new window.CustomOverlay(item.latitude, item.longitude, item.name, item.house_count)
          customOverlay.setMap(_this.map)
        })
      }
    }
    

    至此,地图找房对绘制覆盖物方法的封装就完成了,接下来只需要将 TXMap 暴露出去,然后在 Vue 组件中进行引入,之后再向下面的方法使用即可

    TXMap.drawOverlay({
      containerId: 'map-box',
      data: res.data
    })
    

    实现效果

    这个例子用了链家的数据做了两层,大家可以根据自己的需要进行修改。

    项目地址: GitHub

    产品动态

    腾讯位置服务已经上线3D版地图API-JavaScript API GL

    对应上文功能的3D版地图API文档链接:
    点聚合自定义覆盖物

    以上内容转载自前端develop的文章《腾讯地图实现地图找房功能》

    作者:前端develop

    链接:https://juejin.im/post/6844903510614474759#comment

    来源:掘金

    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    Python获取微软Microsoft Exchange邮件信息
    Python pandas库 -> 和SQL查询的一些等价操作
    Python ORM之peewee模块
    Python pandas库 ->groupby分组操作
    Python pandas库和MS SQL的等价操作->并集,交集,差集
    深入理解SQL关联查询->不等值连接
    SQL技巧->多重分组排序的思路
    SQL技巧->分组排序 , 取最新数据的两种方法
    Python脚本->导出SQL查询结果到Excel文件
    Python中的加密
  • 原文地址:https://www.cnblogs.com/Yi-Xiu/p/13474779.html
Copyright © 2011-2022 走看看