经常的我们在使用地图功能时,会发现在选择一个小区或者一个热门景点的时候,地图上面会给出其边界轮廓,能够方便我们知道其范围大小,有时候在我们使用地图组件的时候,也会面临着类似的需求。比如在地图上面标识出一个商场范围内的热力图,一个热门景点的游览情况等。那么,我们该如何利用地图功能来实现这类效果呢,今天我们一起来探讨一下。

最近我们就有一个需求,需要标识出一些热门场所的人流的热力图情况,同时需要给出该热门场所的边界轮廓。经过查看百度地图和高德地图的开发者API文档,发现并没有这类公共接口提供我们使用。目前地图能够提供我们使用的,基本只能是一些行政区划的边界范围,这个在我之前的文章中也有写过,大家可以参照《仿链家地图找房的简单实现》

那么现在面临的需求该如何实现呢?

通过查看地图功能的接口调用情况和在网上查询相关资料,最终我们找到了下面这个“不算是方法的方法”。

  • 使用了地图的相关API接口获取相关数据
  • API接口不是官方给出的,所以也就面临着稳定性的问题,可能随时被关(高德的只能简单参考,本身就存在较大缺陷,后面会说)

实现思路

  • 通过地图的POI查询服务获取到兴趣点id

    那么什么是POI呢?

    检索服务提供某一特定地区的兴趣点位置查询服务(POI:Point of Interest,感兴趣点)

    相关的官方文档请参照以下地址:

  • 通过兴趣点id获取该兴趣点的详细信息

    这里面需要用到的相关API就需要我们查看地图的执行过程,找到对应的API了。(也希望各个地图官方能够给出官方的方法吧)

PS:地图功能的使用情况在本篇不做说明,具体申请相关Key的过程请分别参照官网说明即可。

下面我们来分别给出百度地图和高德地图的实现方法:

百度地图实现

闲话休谈,咱们直接上码

  1. </html>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>百度地图DEMO</title>
  7. <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=你申请的AK"></script>
  8. <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  9. <script type="text/javascript">
  10. $(document).ready(function() {
  11. var queryHouseOutline = function(hid, callback) {
  12. var baseURL = 'http://map.baidu.com/?reqflag=pcmap&coord_type=3&from=webmap&qt=ext&ext_ver=new&l=18';
  13. var url = baseURL + "&uid=" + hid;
  14. callback && (window.queryHouseOutlineCallback = callback);
  15. $.ajax({
  16. type: "get",
  17. async: false,
  18. url: url,
  19. dataType: "jsonp",
  20. jsonpCallback: "queryHouseOutlineCallback",
  21. success: function(datas) {}
  22. });
  23. };
  24. /**
  25. * 模糊查询小区信息, 无返回值
  26. * @param {} house 小区名称
  27. * @param {} city 所属城市名称
  28. * @param {} ak 百度地图AK
  29. * @param {} callback 回调函数,该函数可以接收到请求的返回值
  30. */
  31. var queryHouse = function(house, city, ak, callback) {
  32. var baseURL = 'http://api.map.baidu.com/place/v2/search?output=json&scope=2';
  33. var url = baseURL + "&q=" + house + "&region=" + city + "&ak=" + ak;
  34. callback && (window.queryHouseCallback = callback);
  35. $.ajax({
  36. type: "get",
  37. async: false,
  38. url: url,
  39. dataType: "jsonp",
  40. jsonpCallback: "queryHouseCallback",
  41. success: function(datas) {}
  42. });
  43. };
  44. /**
  45. * 墨卡托坐标转百度坐标
  46. * @param {} coordinate
  47. * @return {}
  48. */
  49. var coordinateToPoints = function(map, coordinate) {
  50. var points = [];
  51. if (coordinate) {
  52. var arr = coordinate.split(";");
  53. if (arr) {
  54. for (var i = 0; i < arr.length; i++) {
  55. var coord = arr[i].split(",");
  56. if (coord && coord.length == 2) {
  57. var mctXY = new BMap.Pixel(coord[0], coord[1]);
  58. var project = map.getMapType().getProjection();
  59. var point = project.pointToLngLat(mctXY);
  60. points.push(new BMap.Point(point.lng, point.lat));
  61. }
  62. }
  63. }
  64. }
  65. return points;
  66. };
  67. /**
  68. * 墨卡托坐标解析
  69. * @param {} mocator
  70. * @return {}
  71. */
  72. var parseGeo = function(mocator) {
  73. if (typeof mocator != 'string') {
  74. return {};
  75. }
  76. var t = mocator.split("|");
  77. var n = parseInt(t[0]);
  78. var i = t[1];
  79. var r = t[2];
  80. var o = r.split(";");
  81. if (n === 4) {
  82. for (var a = [], s = 0; s < o.length - 1; s++) {
  83. "1" === o[s].split("-")[0] && a.push(o[s].split("-")[1]);
  84. }
  85. o = a;
  86. o.push("");
  87. }
  88. var u = [];
  89. switch (n) {
  90. case 1:
  91. u.push(o[0]);
  92. break;
  93. case 2:
  94. case 3:
  95. case 4:
  96. for (var s = 0; s < o.length - 1; s++) {
  97. var l = o[s];
  98. if (l.length > 100) {
  99. l = l.replace(/(-?[1-9]\d*\.\d*|-?0\.\d*[1-9]\d*|-?0?\.0+|0|-?[1-9]\d*),(-?[1-9]\d*\.\d*|-?0\.\d*[1-9]\d*|-?0?\.0+|0|-?[1-9]\d*)(,)/g,
  100. "$1,$2;");
  101. u.push(l);
  102. } else {
  103. for (var c = [], d = l.split(","), f = 0; f < d.length; f += 2) {
  104. var p = d[f];
  105. var h = d[f + 1];
  106. c.push(p + "," + h);
  107. }
  108. u.push(c.join(";"))
  109. }
  110. }
  111. break;
  112. default:
  113. break;
  114. }
  115. if (u.length <= 1) {
  116. u = u.toString();
  117. }
  118. var result = {
  119. type: n,
  120. bound: i,
  121. points: u
  122. };
  123. return result;
  124. };
  125. var map = new BMap.Map("allmap"); // 创建Map实例
  126. map.centerAndZoom("北京", 19);
  127. map.addControl(new BMap.MapTypeControl()); //添加地图类型控件
  128. map.enableScrollWheelZoom(false); //开启鼠标滚轮缩放
  129. /**
  130. * 第一个参数是城市名,第二参数是小区名
  131. */
  132. var showArea = function(city, area) {
  133. queryHouse(area, city, "你申请的AK", function(data) {
  134. if (data.message == 'ok') {
  135. var houses = data.results;
  136. if (houses && houses.length > 0) {
  137. var house = houses[0];
  138. queryHouseOutline(house.uid, function(houseOutline) {
  139. var geo = houseOutline.content.geo;
  140. if (!geo) {
  141. var location = house.location;
  142. var point = new BMap.Point(location.lng, location.lat);
  143. map.centerAndZoom(point, 19);
  144. var marker = new BMap.Marker(point);
  145. marker.setAnimation(BMAP_ANIMATION_BOUNCE);
  146. map.addOverlay(marker);
  147. } else {
  148. map.clearOverlays();
  149. var geoObj = parseGeo(geo);
  150. //边界点
  151. var points = coordinateToPoints(map, geoObj.points);
  152. var ply = new BMap.Polygon(points, {
  153. strokeWeight: 2,
  154. strokeColor: "#F01B2D",
  155. strokeOpacity: 0.9,
  156. fillColor: "transparent"
  157. }); //建立多边形覆盖物
  158. map.addOverlay(ply); //添加覆盖物
  159. map.setViewport(ply.getPath()); //调整视野
  160. }
  161. });
  162. }
  163. }
  164. });
  165. };
  166. showArea($('#cityId').val(), $('#areaId').val());
  167. $('#showBtn').click(function() {
  168. debugger;
  169. showArea($('#cityId').val(), $('#areaId').val());
  170. });
  171. $("#areaId").keydown(function(e) {
  172. if (event.keyCode == "13") {
  173. showArea($('#cityId').val(), $('#areaId').val());
  174. }
  175. })
  176. });
  177. </script>
  178. </head>
  179. <body>
  180. <table>
  181. <tr>
  182. <td>城市:</td>
  183. <td>
  184. <input id="cityId" type="text" value="北京" />
  185. </td>
  186. <td>小区:</td>
  187. <td>
  188. <input id="areaId" type="text" value="故宫博物院" />
  189. </td>
  190. <td>
  191. <button id="showBtn">显示</button>
  192. </td>
  193. </tr>
  194. </table>
  195. <div id="allmap" style="width: 90vw; height: 90vh;"></div>
  196. </body>
  197. </html>

相关的代码注释都有所添加,参照即可。其中需要注意的是百度地图获取到的坐标点需要进行转换成百度地图识别的点位形式。

另外,边界的描画使用到的是地图的Polygon功能,相关内容请参照

高德地图实现

  1. </html>
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <title>高德地图DEMO</title>
  7. <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.10&key=你申请的AK"></script>
  8. <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
  9. <script type="text/javascript">
  10. $(document).ready(function() {
  11. var map = new AMap.Map('allmap', {
  12. zoom: 19,
  13. center: [116.397428, 39.90923]
  14. }); // 创建Map实例
  15. /**
  16. * 第一个参数是城市名,第二参数是小区名
  17. */
  18. var showArea = function(city, area) {
  19. queryHouse(area, city, "你申请的AK", function(data) {
  20. console.error(data)
  21. if (data.status == 1) {
  22. var houses = data.pois;
  23. if (houses && houses.length > 0) {
  24. var house = houses[0];
  25. queryHouseOutline(house.id, function(houseOutline) {
  26. console.error("get outline success");
  27. var pathPoints = houseOutline.data.spec.mining_shape.shape;
  28. var tmpPath = pathPoints.split(";");
  29. var points = [];
  30. tmpPath.forEach(function(value, index, array) {
  31. points.push(value.split(","))
  32. });
  33. map.clearMap();
  34. var ply = new AMap.Polygon({
  35. map: map,
  36. path: points,
  37. strokeColor: "#F01B2D",
  38. fillColor: "transparent"
  39. }); //建立多边形覆盖物
  40. map.setFitView(); //调整最佳显示
  41. });
  42. }
  43. }
  44. });
  45. };
  46. var queryHouseOutline = function(hid, callback) {
  47. var baseURL = 'https://www.amap.com/detail/get/detail';
  48. $.ajax({
  49. type: "get",
  50. data: {
  51. id: hid
  52. },
  53. url: baseURL,
  54. dataType: "json",
  55. success: function(datas) {
  56. callback(datas)
  57. }
  58. });
  59. };
  60. /**
  61. * 模糊查询小区信息, 无返回值
  62. * @param {} house 小区名称
  63. * @param {} city 所属城市名称
  64. * @param {} ak 高德地图AK
  65. * @param {} callback 回调函数,该函数可以接收到请求的返回值
  66. */
  67. var queryHouse = function(house, city, ak, callback) {
  68. var baseURL = 'http://restapi.amap.com/v3/place/text?&keywords=' + house + '&city=' + city + '&output=json&offset=20&page=1&key=' + ak;
  69. callback && (window.queryHouseCallback = callback);
  70. $.ajax({
  71. type: "get",
  72. async: false,
  73. url: baseURL,
  74. dataType: "jsonp",
  75. jsonpCallback: "queryHouseCallback",
  76. success: function(datas) {}
  77. });
  78. };
  79. showArea($('#cityId').val(), $('#areaId').val());
  80. $('#showBtn').click(function() {
  81. showArea($('#cityId').val(), $('#areaId').val());
  82. });
  83. $("#areaId").keydown(function(e) {
  84. if (event.keyCode == "13") {
  85. showArea($('#cityId').val(), $('#areaId').val());
  86. }
  87. })
  88. });
  89. </script>
  90. </head>
  91. <body>
  92. <table>
  93. <tr>
  94. <td>城市:</td>
  95. <td>
  96. <input id="cityId" type="text" value="北京" />
  97. </td>
  98. <td>小区:</td>
  99. <td>
  100. <input id="areaId" type="text" value="故宫博物院" />
  101. </td>
  102. <td>
  103. <button id="showBtn">显示</button>
  104. </td>
  105. </tr>
  106. </table>
  107. <div id="allmap" style="width: 90vw; height: 90vh;"></div>
  108. </body>
  109. </html>

高德地图的实现方式根据实际的效果来看,本身应该是做了API接口限制的处理,经常会出现获取不到详细信息或者给出的详细信息中的边界信息数据不准确。

这里只是作为一个对比参照,高德地图不推荐来做这个需求,API接口稳定性太差。

后记

①百度地图会涉及到功能接口配额的问题

主要会涉及到上面的地点检索配额,如果只是个人简单使用的,可以注册个人开发者,基本配额就够使用了

②高德地图没有找到配额相关的数据,毕竟走的非正规手段吧

③百度地图和高德地图对于一些位置的边界数据不同

有些地点只会在其中一个能够获取到(高德地图能够返回数据的情况下)

④高德地图在检索位置时,能够支持全拼音输入,也能检索出来(感觉这个厉害,但是中文多音字处理不知道会怎么样)


参考资料:

百度地图小区边界(轮廓)处理

高德地图之python爬取POI数据及其边界经纬度(根据关键字在城市范围内搜索)

百度&高德地图小区景点边界轮廓实现的更多相关文章

  1. 在谷歌地图上绘制行政区域轮廓【结合高德地图的API】

    实现思路: 1.利用高德地图行政区域API获得坐标列表 2.将坐标列表绘制在谷歌地图上[因为高德地图和国内的谷歌地图都是采用GCJ02坐标系,所有误差很小,可以不进行坐标误差转换] 注意点: 1.用百 ...

  2. 百度地图API和高德地图API资料集锦

    [高德地图API]从零开始学高德JS API(五)路线规划——驾车|公交|步行   [高德地图API]从零开始学高德JS API(四)搜索服务——POI搜索|自动完成|输入提示|行政区域|交叉路口|自 ...

  3. GPS定位为什么要转换处理?高德地图和百度地图坐标处理有什么不一样?

    GPS定位为什么要转换处理?高德地图和百度地图坐标处理有什么不一样? 先了解一下 高德地图 采用: GCJ-02 (不可逆) 百度百科: http://baike.baidu.com/link?url ...

  4. iOS打开百度地图、高德地图导航

    1.判断手机里是否已经安装了百度地图或者高德地图: BOOL hasBaiduMap = NO; BOOL hasGaodeMap = NO; if ([[UIApplication sharedAp ...

  5. Android笔记:百度地图与高德地图坐标转换问题

    安卓项目使用了百度地图的定位SDK,web端使用的也是百度地图, 后来发现界面显示百度地图不如高德效果好,web改用高德地图,原本的百度地图坐标是可以直接使用的,由于高德和百度地图的坐标系不一致 要如 ...

  6. iOS 地图坐标系之间的转换WGS-84世界标准坐标、GCJ-02中国国测局(火星坐标,高德地图)、BD-09百度坐标系转换

    开发过程中遇到地图定位不准确,存在偏差.首先确认你获取到的坐标所在坐标系跟地图数据是不是相匹配的. 常用的地图SDK:高德地图使用的是GCJ-02(也就是火星坐标系),百度使用的是BD-09百度坐标系 ...

  7. iOS判断并使用百度地图 高德地图 导航 (使用URI,不集成sdk)

    [objc] view plaincopy  1. BOOL hasBaiduMap = NO;   2.         BOOL hasGaodeMap = NO;   3.            ...

  8. Windows Store Javascript项目使用高德地图、谷歌地图、百度地图API

    原文 Windows Store Javascript项目使用高德地图.谷歌地图.百度地图API 在Win8 Store 项目中可以使用的地图主要有微软的Bing Map,目前高德地图sdk也支持Wi ...

  9. ios 一步一步学会自定义地图吹出框(CalloutView)-->(百度地图,高德地图,google地图)

    前言 在 ios上边使用地图库的同学肯定遇到过这样的问题:吹出框只能设置title和subtitle和左右的view,不管是百度地图还是高德地图还是自带的 google地图,只提供了这四个属性,如果想 ...

随机推荐

  1. windows 10 下配置安装node.js

      环境配置 node.js windows10 25.5k 次阅读  ·  读完需要 6 分钟 5 在去年就自己配置安装过node.js,但是使用npm安装模块时安装成功后调用require('mo ...

  2. linux常用命令(二)文件上传下载及软件安装

    1.上传下载工具安装 (1)WINDOWS 到linux的文件上传及下载: windows下打开secureCRT,通过SSH连到⾄至远程linux主机:上传下载工具安装命令:yum -y insta ...

  3. ASP.Net Core 2.2 MVC入门到基本使用系列 (二)

    本教程会对基本的.Net Core 进行一个大概的且不会太深入的讲解, 在您看完本系列之后, 能基本甚至熟练的使用.Net Core进行Web开发, 感受到.Net Core的魅力. 本教程知识点大体 ...

  4. 使用Code First建模自引用关系笔记

    原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasRequired:前者(A)包含后者(B)一个不为 ...

  5. [leetcode.com]算法题目 - Pascal's Triangle

    Given numRows, generate the first numRows of Pascal's triangle. For example, given numRows = 5,Retur ...

  6. 【BZOJ3709】 [PA2014]Bohater(贪心)

    传送门 BZOJ Solution 考虑如果可以回血肯定要打,那么就是按照伤害值从小到大排个序能打就打,不能打就\(NIE\). 接着看不能够回血的,emmm,把这个过程反着看一下就是打一个怪扣\(a ...

  7. Android RecycleView 的优化

    减少条目的 View 的层级.层级越少效率越高,尤其避免使用 weight.用 ConstraintLayout 可以最大程度减少层级. 使用 ViewStub.如果某个 view 可能不需要被加载, ...

  8. linux03

    linux day31.正则表达式 \* ------重复0无数次 \+ ------重复1 无数次 ^ -------开头 $ -------结尾 | ------或 & ----- 与 ( ...

  9. cad2014卸载/安装失败/如何彻底卸载清除干净cad2014注册表和文件的方法

    cad2014提示安装未完成,某些产品无法安装该怎样解决呢?一些朋友在win7或者win10系统下安装cad2014失败提示cad2014安装未完成,某些产品无法安装,也有时候想重新安装cad2014 ...

  10. 二进制入门-打造Linux shellcode基础篇

    0x01 前言   本文的目的不是为了介绍如何进行恶意的破坏性活动,而是为了教会你如何去防御此类破坏性活动,以帮助你扩大知识范围,完善自己的技能,如有读者运用本文所学技术从事破坏性活动,本人概不负责. ...