注册
web

高德API花式玩法:租房辅助工具

前言


做gis的同学肯定知道等时圈这个东西,即:在一定时间内通过某种出行方式能到达的范围


image.png


通过一些计算,我们可以做一些好玩的事情,比如上图通过调用mapbox等时圈接口,计算在蓝色点位附近骑车17分钟可以到达哪些公司或学校。


可能由于国内交通情况更为复杂,做实时性较差的等时圈意义不大,所以高德地图提供了比较稳当的API:公交地铁到达圈,其概念和等时圈类似,你可以选择地铁或公交出行,或者两者兼可,高德接口将计算出可达范围。


高德公交到达圈的好玩应用


用了很久的高德,发现这个功能好像没有被很好的应用,其实高德早在1.4的API中就提供了此功能,最近正好要换个房子,突然想到这个东西正好可以拿来做一个很棒的辅助。


由于我跟我对象上班的地方离得比较远,所以找个折中的地方租房是是很重要的,我准备查询到两个到达圈后,再计算一下重合部分,在重合部分找房,就准确多了。


使用AMap.ArrivalRange画出到达圈


首先我做了一个简单的页面


image.png


左上角的面板用来设置参数,可选地铁+公交地铁公交三种方式,出行耗时最大支持60分钟(超过了接口会报错),位置需要传入经纬度。


初始化地图的步骤就不用说了,我讲一下这个小应用的使用逻辑。


首先,点击地图时,拾取该位置的经纬度,并通过逆地理接口获取到位置文本


function handleMapClick(e: any) {
 if (!e.lnglat) return
 if (currPositionList.value.length >= 2) {
   autolog.log("最多添加 2 个位置", 'error') // 你不会想三个人一起住吧?
   return
}
 var lnglat = e.lnglat;
 geocoder.getAddress(lnglat, (status: string, result: {
   regeocode: any; info: string;
}) => {
   if (status === "complete" && result.info === "OK") {
     currPositionList.value.push({ name: result.regeocode.formattedAddress, lnglat: [lnglat.lng, lnglat.lat] })
  }
});
}

可以看到,我把点选的位置信息,暂时存放到了currPositionList里面,比如你在西二旗上班,而你女朋友在国贸,则点选后效果是这样的


image.png


左侧面板新增了两个位置,点击查询时,我将依次查询这两个到达圈,并渲染到地图上


function getArriveRange() {
 let loopCount = 0
 for (let item of currPositionList.value) {
   arrivalRange.search(item.lnglat, currTime.value, (_status: any, result: { bounds: any; }) => {
     map.remove(polygons);
     if (!result.bounds) return
     let currPolygons = []
     loopCount++
     for (let item of result.bounds) {
       let polygon = new AMap.Polygon(polygonStyle[`normal${loopCount}` as "normal1" | "normal2"]);
       polygon.setPath(item);
       currPolygons.push(polygon)
    }
     map.add(currPolygons);
     polygons.push({
       lnglat: item.lnglat,
       polygon: currPolygons,
       bounds: result.bounds
    })
     if (loopCount === currPositionList.value.length) {
       map.setFitView();
    }
  }, { policy: currStrategy.value });
}
}

由于接口调用方式是以回调函数的形式返回的,所以我这里记录了一下回调次数,当次数满足后,再去调整视角。这段逻辑运行之后,将是如下结果:


image.png


很遗憾,你和你的女朋友,下班后的一个小时内见不成面了,这意味着,如果找一个折中的地方租房,你们上班单程通勤,无论如何都超过一个小时了,如果想尽量接近一个小时,那么看下两者的交汇处


image.png


大钟寺地铁站将会是个很好的选择。


这样仍需要我们手动去观察,那么能不能算一下两者的交集呢?


在高德地图中使用 turf.js 计算多多边形交集


在上面提到的getArriveRange函数中,我新增了这样的逻辑


      if (loopCount === currPositionList.value.length) {
       let poly1 = turf.multiPolygon(toNumber(polygons[0].bounds));
       let poly2 = turf.multiPolygon(toNumber(polygons[1].bounds));
       var intersection = turf.intersect(turf.featureCollection([poly1, poly2]));
       if (intersection) {
         let geojson = new AMap.GeoJSON({
           geoJSON: {
             type: "FeatureCollection",
             features: [intersection]
          },
           getPolygon: (_: any, lnglats: any) => {
             return new AMap.Polygon({
               path: lnglats,
               ...polygonStyle.overlap
            });
          }
        });
         polygons.push({
           lnglat: [0, 0],
           polygon: geojson,
           bounds: intersection.geometry.coordinates
        })
         map.add(geojson);
      } else {
         autolog.log("暂无交集,请自行查找", 'error')
      }
       map.setFitView();
    }

由于高德地图到达圈获取到的经纬度是字符串,放到 turf 里面会报错,所以这里写了一个简单的递归,将多维数组所有的数据都转化为数字。


// 递归的将多维数组内的字符串转为数字
function toNumber(arr: any) {
 return arr.map((item: any) => {
   if (Array.isArray(item)) {
     return toNumber(item)
  } else {
     return Number(item)
  }
})
}

使用turf.multiPolygon将获取到的多维数组转化为标准的 geojson 格式,以便于 turf 处理,在turf7.x中,turf.intersect的用法稍有改变,需要turf.featureCollection([poly1, poly2])作为参数传入。


这一步操作 turf 将计算并返回两个多多边形的交集intersection(geojson),但是在高德地图API2.0中,直接传入这个geojson会报错(1.4不会),看了下源码,发现高德有一个操作是直接取第 0 个features,导致它识别不了这种格式的数据,所以我们手动处理下,即:


          let geojson = new AMap.GeoJSON({
           geoJSON: {
             type: "FeatureCollection",
             features: [intersection]
          },
           getPolygon: (_: any, lnglats: any) => {
             return new AMap.Polygon({
               path: lnglats,
               ...polygonStyle.overlap
            });
          }
        });

这样,高德就可以正确渲染这个数据了,这里需要注意的是,geojson 虽然也是 AMap.Polygon 构造的,但是需要一个特殊参数:path,没有的话,也不会报错,但是渲染不出来。


渲染完成后是这样的:


image.png


使用绿色代表重合部分,说明在这之中找房都是可以的。


通过 AMap.PlaceSearch 搜索交集区域的小区


高德提供了通过多边形区域搜索POI的接口


         placeSearch = new AMap.PlaceSearch({ //构造地点查询类
           pageSize: 5, // 单页显示结果条数
           pageIndex: 1, // 页码
           map: map, // 展现结果的地图实例
           autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
        });
         placeSearch.searchInBounds('小区', intersection.geometry.coordinates);

image.png


效果如上图所示,这样就可以轻松租房啦!


但是由于此接口是 get 请求,如果交集区域过大,会超出 get 请求长度限制:


image.png


结语


这个就叫产品思维,一个简单的API可以延伸出很多有趣的应用。


此仓库已在 github 开源,地址:


github.com/LarryZhu-de…


番外


高德云镜(高德云镜三维重建平台)目前已向企业和政府开放使用(暂未对个人开发者开放)


首屏.gif


在web端,高德开发了 Cesium 插件用作展示,但目前来看要求配置过高



  • CesiumJS引擎:CesiumJS v1.117+(建议)
  • 浏览器:Chrome v126+(建议)
  • 显卡:16GB显存以上独立显卡,推荐 NVDIA RTX 4090
  • CPU:2.5 GHz 以上(建议)
  • 内存:32GB 以上(建议)

看起来类似谷歌地球的全量城市建模。


官网:yunjing.amap.com/#/


开发文档:yunjing.amap.com/#/docs


作者:德莱厄斯
来源:juejin.cn/post/7403991780512399387

0 个评论

要回复文章请先登录注册