高德地图JS API空间数据采集开发入门实验

高德地图JS API开发基础详解

  • 准备
    • 准备页面:
    • 加载 JS API
      • 顺序同步加载
      • 异步加载
  • 快速上手
    • HELLO,AMAP!
    • 图层
    • 点标记与矢量图形
    • 事件功能与信息窗体
  • 插件的使用
    • 插件的使用流程
    • 插件的引入
      • 异步加载插件
      • 异步加载多个插件
      • 同步加载插件
      • 同步加载多个插件
  • 地图组成与名词解释
    • JS API 地图组成结构
      • 地图容器 Container
      • 图层 Layers
      • 矢量图形 Vector Overlays
      • 点标记 Markers
      • 地图控件 Map Controls
    • 常用名词
      • 插件 Plugins
      • 地图级别 ZoomLevel
      • 经纬度 LngLat
      • 底图 BaseLayer
      • 地图要素 Map Features
      • 标注 Labels
      • 地图平面像素坐标 Plane Coordinates
      • 投影 Projection
      • 三维空间坐标 3D Coordinates
  • 着手开发一个html页面
    • 地图显示
    • 给地图增加控件
    • 输入提示后查询
    • 周边搜索
    • 多边形搜索
    • 功能整合
  • 将poi数据写入数据库
    • 新建数据库
    • 连接并修改数据库函数
    • 将poi部分属性写入数据库
    • 周边搜索、关键字搜索的数据存储
  • 搜索功能改进与完善
    • 移动块
    • 自定义画圆及绘制其他覆盖物的搜索形式
      • 圆形搜索
      • 多边形搜索
      • 沿线搜索
  • 总结与反思

准备

准备页面:

  1. 在页面添加 JS API 的入口脚本标签,并将其中「您申请的key值」替换为您刚刚申请的 key;

  2. 添加div标签作为地图容器,同时为该div指定id属性;

  3. 为地图容器指定高度、宽度;#container {width:300px; height: 180px; }

  4. 进行移动端开发时,请在head内添加viewport设置,以达到最佳的绘制性能;

  5. 在完成如上准备工作之后便可以开始进行开发工作了,查看快速入门。

加载 JS API

上一节说明的是最基本的同步加载 JS API 的方式,如果您需要异步加载,比如通过appendChild,或者通过require等异步方式来加载,这时需要您需要先准备一个全局的回调函数作为 JS API 异步加载的回调函数,并将其函数名作为callback参数添加在 JS API 的引用地址后面,此时要注意,回调函数应该在脚本请求发出之前进行声明。异步加载方式只有在回调之后,才能开始调用JSAPI的相关接口。比如

 window.onLoad  = function(){
        var map = new AMap.Map('container');
  }
  var url = 'https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&callback=onLoad';
  var jsapi = doc.createElement('script');
  jsapi.charset = 'utf-8';
  jsapi.src = url;
  document.head.appendChild(jsapi);

JS API 支持多种加载方式,可以顺序加载也可以异步加载,同时也可以作为一般脚本资源被 RequireJS 等前端框架加载。

顺序同步加载

之前我们使用的是基本的顺序同步加载方式,这种方式下,地图初始化的代码要放在 JS API 的脚本标签之后:

<script src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值"></script>
<script type="text/javascript">
    var map = new AMap.Map('container', {
       center:[117.000923,36.675807],
       zoom:11
    });
</script>

异步加载

异步加载指的是为 JS API 指定加载的回调函数,在 JS API 的主体资源加载完毕之后,将自动调用该回调函数。回调函数应该声明在 JS API 入口文件引用之前,异步加载可以减少对其他脚本执行的阻塞,HTTPS 下我们也建议使用异步方式:

<script type="text/javascript">
    window.init = function(){
        var map = new AMap.Map('container', {
           center:[117.000923,36.675807],
           zoom:11
        });
    }
</script>
<script src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&callback=init"></script>

或者

window.onLoad  = function(){
    var map = new AMap.Map('container');
}
var url = 'https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&callback=onLoad';
var jsapi = document.createElement('script');
jsapi.charset = 'utf-8';
jsapi.src = url;
document.head.appendChild(jsapi);

也可以使用RequireJS 等加载,点这里了解更多,在此不一一赘述。

快速上手

按照「准备」篇完成页面准备工作之后就可以真正开始地图的开发工作了。本篇带您快速了解:地图、图层、点标记、矢量图形、信息窗体、事件的最基本使用方法。

HELLO,AMAP!


简单创建一个地图只需要一行代码,构造参数中的`container`为准备阶段添加的地图容器的`id`:
    var map = new AMap.Map('container');

创建的同时可以给地图设置中心点、级别、显示模式、自定义样式等属性:

   var map = new AMap.Map('container', {
        zoom:11,//级别
        center: [116.397428, 39.90923],//中心点坐标
        viewMode:'3D'//使用3D视图
    });

图层


默认情况下,地图只显示标准底图,如需要叠加别的图层,可以通过`map.add`方法添加图层:

    var map = new AMap.Map('container', {
        resizeEnable: true,
        center: [116.397428, 39.90923],
        zoom: 13
    });
    //实时路况图层
    var trafficLayer = new AMap.TileLayer.Traffic({
        zIndex: 10
    });
    map.add(trafficLayer);//添加图层到地图

也可以在地图初始化的时候通过layers属性为地图设置多个图层:

    var map = new AMap.Map('container', {
        center: [116.397428, 39.90923],
        layers: [//使用多个图层
            new AMap.TileLayer.Satellite(),
            new AMap.TileLayer.RoadNet()
        ],
        zooms: [4,18],//设置地图级别范围
        zoom: 13
    });

地图 JS API 提供了标准、卫星、路网、路况、建筑等多个官方图层,同时也提供了加载第三方WMS、WMTS、XYZ等标准图层的接口,也提供了把一般的图片、Canvas、视频、热力等作为图层的能力,查看图层相关教程。

点标记与矢量图形

JS API 提供了在地图之上绘制覆盖物的能力,比如点标记 Marker、文本标记 Text、圆点标记 CircleMarker。

添加点标记的方法非常简单,比如添加一个默认样式的Marker:

    var marker = new AMap.Marker({
        position:[116.39, 39.9]//位置
    })
    map.add(marker);//添加到地图

移除的方法如下:

    map.remove(marker)

查看点标记相关教程

也提供了绘制圆Circle、折线 Polyline、多边形 Polygon、椭圆 Ellipse、矩形 Rectangle、贝瑟尔曲线 BesizerCurve等矢量图形的能力,比如添加折线:

  var lineArr = [
        [116.368904, 39.913423],
        [116.382122, 39.901176],
        [116.387271, 39.912501],
        [116.398258, 39.904600]
    ];
    var polyline = new AMap.Polyline({
        path: lineArr,          //设置线覆盖物路径
        strokeColor: "#3366FF", //线颜色
        strokeWeight: 5,        //线宽
        strokeStyle: "solid",   //线样式
    });
    map.add(polyline);

查看矢量图形关教程

事件功能与信息窗体

JS API 提供的Map、点标记、矢量图形的实例均支持事件,鼠标或者触摸操作均会触发相应的事件。我们通过给点标记绑定click事件来简单了解事件系统和信息窗体的基本使用:

     var infoWindow = new AMap.InfoWindow({ //创建信息窗体
        isCustom: true,  //使用自定义窗体
        content:'
信息窗体
'
, //信息窗体的内容可以是任意html片段 offset: new AMap.Pixel(16, -45) }); var onMarkerClick = function(e) { infoWindow.open(map, e.target.getPosition());//打开信息窗体 //e.target就是被点击的Marker } var marker = new AMap.Marker({ position: [116.481181, 39.989792] }) map.add(marker); marker.on('click',onMarkerClick);//绑定click事件

插件的使用

JS API 提供了众多的插件功能,这些功能不会主动随着 JSAPI 主体资源下发,需要引入之后才能使用这些插件的功能。这些功能包括:

  • 服务类,如:POI搜索 PlaceSearch、输入提示 AutoComplete、路线规划 Driving/Walker/Transfer/Riding/Truck、地理编码 Geocoder、公交线路 LineSearch、公交站点 StationSearch、天气查询 Weather等;
  • 地图控件,如:缩放工具条 ToolBar、比例尺 Scale、定位按钮 Geolocation等;
  • 矢量图形编辑工具,如折线/多边形编辑器 PolyEditor、圆形编辑器 CircleEditor等;
  • 工具类,如鼠标绘制工具 MouseTool、测距工具 RangingTool等。

插件的使用流程


使用插件的功能通常需要三个步骤:
  1. 引入插件,支持按需异步加载和同步加载,可同时引入多个插件,见「插件的引入」;
  2. 创建插件实例,非特殊情况需避免重复创建多个实例,复用同一个实例即可;
  3. 调用实例的方法,使用相关功能。

插件的引入


异步加载插件

异步加载指的是在 JS API 加载完成之后,在需要使用到某个插件的时候,通过AMap.plugin方法按需引入插件,在plugin回调之后使用插件功能。

<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值"></script> 
<script type="text/javascript" >
    var map = new AMap.Map('container',{
        zoom:12,
        center:[116.39,39.9]
    });
    AMap.plugin('AMap.ToolBar',function(){//异步加载插件
        var toolbar = new AMap.ToolBar();
        map.addControl(toolbar);
    });
</script>

异步加载多个插件

AMap.plugin的第一个参数使用数组即可同时加载引入多个插件。

  AMap.plugin(['AMap.ToolBar','AMap.Driving'],function(){//异步同时加载多个插件
      var toolbar = new AMap.ToolBar();
      map.addControl(toolbar);
      var driving = new AMap.Driving();//驾车路线规划
      driving.search(/*参数*/)
  });

同步加载插件

如果希望和 JS API 的主体同步加载某些插件,而不是异步加载,可以在 JS API 的入口地址中添加plugin参数,将需要使用的一个或者多个插件的名称作为参数即可,这种用法在 JS API 加载完毕之后便可直接使用插件功能了。

<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&plugin=AMap.ToolBar"></script> 
<script type="text/javascript" >
    var map = new AMap.Map('mapContainer',{
        zoom:12,
        center:[116.39,39.9]
    });
    var toolbar = new AMap.ToolBar();
    map.plugin(toolbar);
</script>

同步加载多个插件

需要加载多个插件时,plugin参数中的插件名称之间以逗号分割。

<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值&plugin=AMap.ToolBar,AMap.Driving"></script> 
<script type="text/javascript" >
    var map = new AMap.Map('mapContainer',{
        zoom:12,
        center:[116.39,39.9]
    });
    var toolbar = new AMap.ToolBar();
    map.plugin(toolbar);
    var driving = new AMap.Driving();
    driving.search(/*参数*/)
</script>

地图组成与名词解释

JS API 地图组成结构

高德地图JS API空间数据采集开发入门实验_第1张图片
使用高德地图 JS API 创建的地图通常由这几部分组成:

地图容器 Container

即在准备阶段所创建的指定了id的div对象,这个div将作为承载所有图层、点标记、矢量图形、控件的容器。

图层 Layers

图层是指能够在视觉上覆盖一定地图范围,用来描述全部或者部分现实世界区域内的地图要素的抽象概念,一幅地图通常由一个或者多个图层组成。如上图中处于整个地图容器最下方的二维矢量图层和实施交通图层。

高德地图 JS API 即提供了标准图层、卫星图层、路网图层、路况图层等官方标准图层接口,又提供了加载其他厂商发布的标准地图服务的图层接口,还提供了加载开发者自己的图片、Canvas、视频、热力数据的图层接口。同时也深度开放了可以自定义绘制方法的自定义图层接口。

矢量图形 Vector Overlays

矢量图形,一般覆盖于底图图层之上,通过矢量的方式(路径或者实际大小)来描述其形状,用几何的方式来展示真实的地图要素,会随着地图缩放而发生视觉大小的变化,但其代表的实际路径或范围不变,如上图中红框内的折线、圆、多边形等。

除了图中的折线、圆、多边形之外,JS API 还提供了矩形、椭圆、贝瑟尔曲线等常用的矢量图形。3D 视图下的 Mesh、Prism 棱柱、MeshLine 也可以看做是一些特殊的矢量图形。

点标记 Markers

点标记是用来标示某个位置点信息的一种地图要素,覆盖于图层之上。如图中蓝色方框中的两个点状要素。其在屏幕上的位置会随着地图的缩放和中心变化而发生改变,但是会与图层内的要素保持相对静止。

普通的点标记 (即 Marker ) ,支持将自定义图标和DOM元素作为展示内容。除了 Marker 之外为了满足不同的场景,JS API 另外提供了丰富的点标记类型,比如圆点标记 (CircleMarker) 、文本标记 (Text)、灵活点标记 (ElasticMarker) 。同时我们提供了海量点(MassMarks)、点聚合(MarkerCluster)来满足大量点标记的展示需求。

地图控件 Map Controls

控件浮在所有图层和地图要素之上,用于满足一定的交互或提示功能。一般相对于地图容器静止,不随着地图缩放和中心变化而发生位置的变化。如上图中绿色方框中的比例尺和级别控件。

常用名词

插件 Plugins

插件是独立于JS API 地图核心模块之外的一些功能,比如服务类、绘制工具、矢量图形编辑工具、点聚合、热力图等。这些插件不会主动随 JS API的主体资源的加载而下发,使用之前需要提前引入,详见插件的使用

地图级别 ZoomLevel

级别与地图的比例尺成正比,每增大一级,地图的比例尺也增大一倍,地图显示的越详细。Web地图的最小级别通常为3级,最大级别各家略有不同,高德地图 JS API 目前最大级别为 20 级。

经纬度 LngLat

坐标通常指经纬度坐标,高德地图的坐标范围大致为:东西经180度(-180——180,西半球为负,东半球为正),南北纬85度(-85——85,北半球为正,南半球为负)。

底图 BaseLayer

严格意义上,底图指处于所有图层和图形最下方的一个图层,通常不透明。可以是单一图层,比如官方标准图层,也可以是图层组合,比图卫星图层和路网图层组合。

地图要素 Map Features

严格意义的地图要素指的是展示在地图上的地理要素,包括道路、区域面、建筑、POI 标注、路名等。开发者自定义的点标记、矢量图形也可以看做是一种地图要素。

标注 Labels

我们习惯将底图上自带的标示一定信息的文字或图标称为标注,比如 POI 标注,道路名称标注等。

地图平面像素坐标 Plane Coordinates

地图平面像素坐标指投影为平面之后的地图上的平面像素坐标,高德地图使用的Web墨卡托投影,在3级时,平面坐标范围为横纵0-256* 2的3次方 像素,每级别扩大一倍,即第n级的平面坐标范围为 0-256*2 的 n 次方 像素。

投影 Projection

地图投影指的是将地球球面的经纬度坐标映射到地图平面坐标的变换和映射关系。高德地图使用 Web 墨卡托投影,即采用 EPSG:3857 坐标系统。

三维空间坐标 3D Coordinates

三维空间坐标是在 3D 地图模式下的世界坐标,由 x、y、z 三个纬度组成。三维空间坐标通常用于描述 Object3D 类型的几何形体。

着手开发一个html页面

地图显示

var map = new AMap.Map('container', {
        resizeEnable: true, //是否监控地图容器尺寸变化
        zoom:11, //初始化地图层级
        center: [116.397428, 39.90923] //初始化地图中心点
    });

参见代码

给地图增加控件

实际编写过程中并没有使用这么多控件,鼠标的滚轮功能已经满足大部分需求。
参见代码

输入提示后查询

//输入提示
    var autoOptions = {
        input: "tipinput"
    };
    var auto = new AMap.Autocomplete(autoOptions);
    var placeSearch = new AMap.PlaceSearch({
        map: map
    });  //构造地点查询类
    AMap.event.addListener(auto, "select", select);//注册监听,当选中某条记录时会触发
    function select(e) {
        placeSearch.setCity(e.poi.adcode);
        placeSearch.search(e.poi.name);  //关键字查询查询
    }

参见代码

周边搜索

AMap.service(["AMap.PlaceSearch"], function() {
        // 构造地点查询类
        var placeSearch = new AMap.PlaceSearch({
            type: '餐饮服务', // 兴趣点类别
            pageSize: 5, // 单页显示结果条数
            pageIndex: 1, // 页码
            city: "010", // 兴趣点城市
            citylimit: true,  //是否强制限制在设置的城市内搜索
            map: map, // 展现结果的地图实例
            panel: "panel", // 结果列表将在此容器中进行展示。
            autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
        });

        var cpoint = [116.405467, 39.907761]; //中心点坐标
        placeSearch.searchNearBy('', cpoint, 200, function(status, result) {

        });
    });

参见代码

多边形搜索

AMap.service(["AMap.PlaceSearch"], function() {
        var placeSearch = new AMap.PlaceSearch({ //构造地点查询类
            pageSize: 5, // 单页显示结果条数
            pageIndex: 1, // 页码
            city: "010", // 兴趣点城市
            citylimit: true,  //是否强制限制在设置的城市内搜索
            map: map, // 展现结果的地图实例
            panel: "result", // 结果列表将在此容器中进行展示。
            autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
        });
        //多边形查
        var polygonArr = [//多边形覆盖物节点坐标数组
            [116.403322, 39.920255],
            [116.410703, 39.897555],
            [116.402292, 39.892353],
            [116.389846, 39.891365]
        ];
        var polygon = new AMap.Polygon({
            path: polygonArr,//设置多边形边界路径
            strokeColor: "#FF33FF", //线颜色
            strokeOpacity: 0.2, //线透明度
            strokeWeight: 3,    //线宽
            fillColor: "#1791fc", //填充色
            fillOpacity: 0.35//填充透明度
        });
        placeSearch.searchInBounds('酒店', polygon);
    });

从这里不难看出来,多边形检索与周边检索非常类似,当开发出来周边搜索,可类似开发多边形搜索功能。
参见代码

功能整合

了解了上述几个简单功能之后,开始尝试将三个功能整合到一个html页面上。

  1. 输入文本后搜索的html页面作为开发基础

  2. 增加周边搜索小窗口按钮

  3. 对上述按钮进行事件绑定,实现点击自动缩放到特定周边。详见:周边搜索

  4. 编辑周边搜索的默认图形,使得周边搜索更加灵活。 圆的编辑代码或圆的绘制和编辑

  5. 在此基础上,也可以增加清除覆盖物的实现。这使得当多次使用周边查询时页面仍能保持较为整洁的良好观感。有关覆盖物的清除方法可以参见:覆盖物

整合后所有的代码如下:


<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
    <title>输入提示后查询title>
    <link rel="stylesheet" href="https://cache.amap.com/lbs/static/main1119.css"/>
    <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css" />
    <script src="https://webapi.amap.com/maps?v=1.4.15&key=YourKeyValue&plugin=AMap.CircleEditor">script>
    <script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js">script>
    <script src="https://cache.amap.com/lbs/static/es5.min.js">script>
    <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=e1e9cc8dd1c2ea38bb2d5c885eccc357&plugin=AMap.Autocomplete,AMap.PlaceSearch">script>
    
    <style>
        html,
        body,
        #container {
            width: 100%;
            height: 100%;
        }
        label {
            width: 55px;
            height: 26px;
            line-height: 26px;
            margin-bottom: 0;
        }
        button.btn {
            width: 80px;
            margin-left: 3px;
            margin-right: 3px;
            margin-top: 3px;
            margin-bottom: 3px;
        }
        #panel {
            position: fixed;
            background-color: white;
            max-height: 90%;
            overflow-y: auto;
            top: 10px;
            right: 10px;
            width: 280px;
            border-bottom: solid 1px silver;
        }
        #myPageTop{
        }
    style>

head>
<body>
<div id="container" >div>
<div id="panel">div>

<div id="myPageTop" style="width: 24rem; ">
    <h4>请输入查找h4>
    <div class="input-item">
        <input id="tipinput" style="margin-right:1rem;"/>
    div>
div>

<div class="input-card" style="width:45rem;">
    <h4>POI查询/搜索服务h4>
    <div class="input-item">
        <label>功能:label>
        <button class="btn" id="search-nearby"> 周边查询button>
        <button class="btn" id="start-edit"> 开始编辑button>
        <button class="btn" onclick="circleEditor.close()">结束编辑button>
        <button class="btn" id="removeAllOverlay" >清除所有button>
    div>
div>
<script type="text/javascript">

    // 定义全局变量
    var cpoint = [116.405467, 39.907761];
    var lng;
    var lat;
    var radius = 200;

    //地图加载
    var map = new AMap.Map("container", {
        resizeEnable: true
    });
    //输入提示
    var autoOptions = {
        input: "tipinput"
    };
    var auto = new AMap.Autocomplete(autoOptions);
    var placeSearch = new AMap.PlaceSearch({
        map: map
    });  //构造地点查询类
    AMap.event.addListener(auto, "select", select);//注册监听,当选中某条记录时会触发
    function select(e) {
        placeSearch.setCity(e.poi.adcode);
        placeSearch.search(e.poi.name);  //关键字查询查询

    }

    // 事件绑定:周边搜索
    document.querySelector("#search-nearby").onclick = function() {
        AMap.service(["AMap.PlaceSearch"], function() {
            // 构造地点查询类
            var placeSearch = new AMap.PlaceSearch({
                //type: '餐饮服务', // 兴趣点类别
                type: '汽车服务|汽车销售|汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|\n' +
                '\n' +
                '医疗保健服务|住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|\n' +
                '\n' +
                '交通设施服务|金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施',
                pageSize: 5, // 单页显示结果条数
                pageIndex: 1, // 页码
                city: "010", // 兴趣点城市
                citylimit: true,  //是否强制限制在设置的城市内搜索
                map: map, // 展现结果的地图实例
                panel: "panel", // 结果列表将在此容器中进行展示。
                autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
            });

            //cpoint = [lng,lat]; //中心点坐标,要传入参数。

            //var cpoint = [116.433320, 39.900255]; //中心点坐标,抱歉,未搜索到有效的结果
            placeSearch.searchNearBy('', cpoint, radius, function(status, result) {

            });
        });
    };

    document.querySelector("#start-edit").onclick = function () {
        var circle = new AMap.Circle({
            map: map,
            center:new AMap.LngLat("116.40332221984863","39.90025505675715"),// 116.405467, 39.907761
            radius:1000,
            strokeColor: "#F33",
            strokeOpacity: 1,
            strokeWeight: 3,
            fillColor: "ee2200",
            fillOpacity: 0.35
        });

        map.plugin(["AMap.CircleEditor"],function(){
            circleEditor = new AMap.CircleEditor(map,circle);
            circleEditor.open();
        });


        circleEditor.on('move', function(event) {
            log.info('触发事件:move')
        })

        circleEditor.on('adjust', function(event) {
            log.info('触发事件:adjust')
        })

        circleEditor.on('end', function(event) {
            log.info('触发事件: end')
            lng = circle.getCenter().getLng();
            lat = circle.getCenter().getLat();
            radius = circle.getRadius();
            cpoint = [lng,lat];
            // event.target 即为编辑后的圆形对象
        })

    };

    function removeAllOverlay(){

        // 清除地图上所有添加的覆盖物
        map.clearMap();
    }

    // 绑定移除事件
    document.getElementById("removeAllOverlay").onclick = removeAllOverlay;

script>
body>
html>

将poi数据写入数据库

使用access创建数据库,并使用IE浏览器预览(因为要用到基于IE内核浏览器支持的ActiveX插件)。其他浏览器暂不支持ActiveX插件。

新建数据库

  1. 空数据库,命名为poiData;
  2. 新建表:poi
  3. 添加字段:NamepoiIDLngLat,数据类型都是短文本
  4. 保存为2002-2003数据库版本,路径filePath

连接并修改数据库函数

function addPOIData(strName, strId, strLongitude, strLatitude) {
    //创建数据库连接对象
    var conn = new ActiveXObject("ADODB.Connection");
    //创建数据集对象
    var rs = new ActiveXObject("ADODB.Recordset");

    var connectionString = "DBQ=filePath.mdb;DRIVER={Microsoft Access Driver (*.mdb)};";
    
    console.log(connectionString);
    conn.open(connectionString);
    var sql = "insert into poi(Name,poiID,Lng,Lat) values('" + strName + "','" + strId + "','" + strLongitude + "','" + strLatitude + "')";
    try {
        conn.execute(sql);
        //关闭记录集
        rs.close();
        //关闭数据库连接
        conn.close();
    }
    catch (e) {
        document.write(e.description);
    }
}

将poi部分属性写入数据库

以根据搜索结果添加marker为例,把其中的数据写入到数据库:

  1. 找到获取poi对象的地方:
placeSearch.search('东方明珠', function (status, result) {
       // 查询成功时,result即对应匹配的POI信息
       console.log(result)
       var pois = result.poiList.pois;
        for(var i = 0; i < pois.length; i++){
            var poi = pois[i];
            var marker = [];
            marker[i] = new AMap.Marker({
                position: poi.location,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
                title: poi.name
            });
            // 将创建的点标记添加到已有的地图实例:
            map.add(marker[i]);
        }
        map.setFitView();

    })
  1. 在获取到poi对象之后,使用addPOIData函数:
map.add(marker[i]);
addPOIData(poi.name,poi.id,poi.location.lng,poi.location.lat);
  1. 打开测试html页面是否可行。当查询到数据库的数据如下:
ID Name poiID Lng Lat
1 东方明珠广播电视塔 B00150F6D6 121.499717 31.239702
2 东方明珠广播电视塔(公交站) BV10385979 121.50161 31.239862
3 陆家嘴(地铁站) BV10029743 121.502262 31.238195
4 东方明珠 B0FFL7YY8J 121.699108 31.187925
5 东方明珠 B0FFL7L39N 121.657356 31.584515
6 东方明珠 B0FFLDUR2A 121.412119 31.173262
7 东方明珠公园 B0FFFS16ZK 121.500127 31.241103
8 东方明珠广播电视塔(1门) B00155DLW1 121.500617 31.23885
9 东方明珠-城市广场 B0FFG4JZTG 121.499649 31.239729
10 东方明珠广播电视塔(8号门) B00155R4RT 121.500861 31.239404

则说明数据添加成功了。

在打开ie的时候如果遇到ADO警告(通常是很多个弹窗警告),可以参见该链接解决。

周边搜索、关键字搜索的数据存储

  1. 找到关键字搜索函数入口:
placeSearch.search(e.poi.name,function (status, result){})

修改函数:

placeSearch.setCity(e.poi.adcode);
	//关键字查询
	placeSearch.search(e.poi.name,function (status, result) {
	    console.log(result);
	    var pois = result.poiList.pois;
	    for(var i = 0; i < pois.length; i++){
	        var poi = pois[i];
	        var marker = [];
	        marker[i]=new AMap.Marker({
	            position: poi.location,
	            title: poi.name
	        });
	        map.add(marker[i]);
	        addPOIData(poi.name,poi.id,poi.location.lng,poi.location.lat);
	    }
	    map.setFitView();
	});

并在获取到poi对象之后添加addPOIData函数,测试是否可用:ie打开该html页面,输入搜索:重庆。选择重庆市,等待地图页面加载出来。此时刷新poi表见到如下数据:

ID Name poiID Lng Lat
176 重庆市 B00178WI1P 106.550464 29.563761
177 重庆市中心 B00178TUGP 106.551294 29.562943
178 重庆市人民政府 B001702338 106.550483 29.563707
179 重庆市渝中区瑞天路61-8 B0FFKTRMRS 106.50242 29.553818
180 重庆市渝中区健康路卤店王烧腊 B0FFKQZZVC 106.543084 29.552855
181 重庆市包协 B001709UXJ 106.561941 29.555964
182 重庆市妇联 B001783SH3 106.54805 29.564651
183 中国共产党重庆市委员会 B00170CT3Z 106.548386 29.563538
184 重庆市科学技术协会 B00170L88M 106.565265 29.561184
185 重庆市疾病预防控制中心(上肖家塆) B0017098ZK 106.527192 29.542505
说明函数可用。 同样地,为“周边搜索”功能添加该函数。入口函数:
placeSearch.searchNearBy('', cpoint, 200, function(status, result) {

	});

为其添加对应函数

placeSearch.searchNearBy('', cpoint, radius, function(status, result) {
    // 查询成功时,result即对应匹配的POI信息
    console.log(result)
    var pois = result.poiList.pois;
    for(var i = 0; i < pois.length; i++){
        var poi = pois[i];
        var marker = [];
        marker[i] = new AMap.Marker({
            position: poi.location,   
            // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
            title: poi.name
        });
        // 将创建的点标记添加到已有的地图实例:
        map.add(marker[i]);
        addPOIData(poi.name, poi.id, poi.location.lng, poi.location.lat);
    }
    map.setFitView();

});

同样对其功能进行测试。周边搜索定位到北京。传入的坐标为:[116.405467, 39.907761]

ID Name poiID Lng Lat
186 菖蒲河沿 B0FFGZCBUD 116.404956 39.908786
187 公共厕所 B000A83BHO 116.405332 39.908872
188 北库司胡同1号 B0FFI7883D 116.404825 39.909184
189 欧美同学会(菖蒲河沿) B000AA21AN 116.406377 39.9091
190 南河沿大街与菖蒲河沿交叉口 B0FFI8LC5Z 116.406674 39.908958

同样地,编辑圆形之后也可以进行搜索。

搜索功能改进与完善

移动块

以上html布局中,不同功能之间相互遮挡。给出下面函数使得div可移动。

function dragDiv(id) {
    var Drag = document.getElementById(id);
    Drag.onmousedown = function (ev) {
        var ev = event || window.event;
        event.stopPropagation();
        var disX = ev.clientX - Drag.offsetLeft;
        var disY = ev.clientY - Drag.offsetTop;
        document.onmousemove = function (ev2) {
            var ev = event || window.event;
            Drag.style.left = ev.clientX - disX + "px";
            Drag.style.top = ev.clientY - disY + "px";
            Drag.style.cursor = "move";
        };
    };
    Drag.onmouseup = function (ev) {
        document.onmousemove = null;
        this.style.cursor = "default";
    };
}

自定义画圆及绘制其他覆盖物的搜索形式

圆形搜索

之前的案例中,覆盖物都是给定之后进行修改,不可自定义覆盖物。参考绘制矢量图形,进行圆的绘制。

var mouseTool = new AMap.MouseTool(map);
function drawCircle () {
	mouseTool.circle({
	   strokeColor: "#FF33FF",
	   strokeOpacity: 1,
	   strokeWeight: 6,
	   strokeOpacity: 0.2,
	   fillColor: '#1791fc',
	   fillOpacity: 0.4,
	   strokeStyle: 'solid'
	   // 线样式还支持 'dashed'
	   // strokeDasharray: [30,10],
	});
	// mouseTool.circle();
    }
mouseTool.on('draw', function(event) {
	// event.obj 为绘制出来的覆盖物对象
	log.info('覆盖物对象绘制完成');
    })

由于绘制的对象是圆,那么event.obj.CLASS_NAME就是AMap.Circle。那么可以获取对应的参数进行相应设置。

cpoint = event.obj.getCenter();
lng = event.obj.getCenter().getLng();
lat = event.obj.getCenter().getLat();
radius = event.obj.getRadius();

多边形搜索

按照前面的思路,开发多边形搜索功能。参照多边形搜索

var polygonArr = [//多边形覆盖物节点坐标数组
     [116.403322, 39.920255],
     [116.410703, 39.897555],
     [116.402292, 39.892353],
     [116.389846, 39.891365]
	 ];
var polygon = new AMap.Polygon({
     path: polygonArr,//设置多边形边界路径
     strokeColor: "#FF33FF", //线颜色
     strokeOpacity: 0.2, //线透明度
     strokeWeight: 3,    //线宽
     fillColor: "#1791fc", //填充色
     fillOpacity: 0.35//填充透明度
	 });
placeSearch.searchInBounds('酒店', polygon);

参考绘制矢量图形,将默认的多边形修改为绘制多边形,并获取动态坐标。如果不知道polygon有哪些属性,可以查看覆盖物-参考手册找到polygon对应的属性列表。在方法一栏中找到getPath()返回Array类型:获取折线路径的节点数组。说明:其中lat和lng是经纬度参数。

function drawPolygon () {
	mouseTool.polygon({
	    strokeColor: "#FF33FF",
	    strokeOpacity: 1,
	    strokeWeight: 6,
	    strokeOpacity: 0.2,
	    fillColor: '#1791fc',
	    fillOpacity: 0.4,
	    // 线样式还支持 'dashed'
	    strokeStyle: "solid",
	    // strokeStyle是dashed时有效
	    // strokeDasharray: [30,10],
		})
    }
mouseTool.on('draw', function(event) {
    // event.obj 为绘制出来的覆盖物对象
    log.info('覆盖物对象绘制完成');
    polygonArr= event.obj.getPath();
})

将上述polygonArr替换为动态路径,然后再定义全局变量polygonArr即可。测试代码搜索成功后,给placeSearch.searchInBounds('酒店', polygon);增加回调函数。参照周边搜索及其修改后的代码。

function(status, result) {
	// 查询成功时,result即对应匹配的POI信息
	console.log(result)
	var pois = result.poiList.pois;
	for(var i = 0; i < pois.length; i++){
	    var poi = pois[i];
	    var marker = [];
	    marker[i] = new AMap.Marker({
	        position: poi.location,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
	        title: poi.name
	    	});
	    // 将创建的点标记添加到已有的地图实例:
	    map.add(marker[i]);
	    addPOIData(poi.name, poi.id, poi.location.lng, poi.location.lat);
		}
	map.setFitView();
	
	}

测试:用ie浏览器打开,框选广州的一处地方,搜索并刷新数据库。

ID Name poiID Lng Lat
191 微八连锁酒店(广州西村分店) B00140WAL7 113.239592 23.140388
192 东盈快捷酒店 B0FFGOFIHG 113.545177 23.110201
193 原景商务酒店(广州北京路纪念堂地铁站店) B00141JVYF 113.262521 23.131277
194 广州斯维登服务公寓(洛溪渔人码头) B0FFG1AB92 113.296751 23.048226
195 盈丰源酒店(会展中心店) B00140W1Y4 113.280034 23.102697

可见多边形搜索功能也开发完成了。

沿线搜索

需求:通过在地图上画Polyline折线覆盖物,对覆盖物区域进行搜索。并将数据存储到数据库。

关于Polyline属性详见

首先,增加绘制折线的函数:参考绘制矢量图形,进行折线绘制测试,并获取到覆盖物对象为:AMap.Polyline,这与我们的预期一致。

function drawPolyline () {
    mouseTool.polyline({
        strokeColor: "#3366FF",
        strokeOpacity: 1,
        strokeWeight: 6,
        // 线样式还支持 'dashed'
        strokeStyle: "solid",
        // strokeStyle是dashed时有效
        // strokeDasharray: [10, 5],
    })
}
mouseTool.on('draw', function(event) {
    // event.obj 为绘制出来的覆盖物对象
    log.info('覆盖物对象绘制完成')
	
	polylineArr = event.obj.getPath();

})

高德地图没有对Polyline进行搜索的函数。先查找Polyline属性。通过查看覆盖物-参考手册,发现方法getPath( ) 返回Array 获取折线路径的节点数组。其中lat和lng是经纬度参数。以及方法getBounds( )返回 Bounds 获取当前折线的矩形范围对象。

所谓“沿线搜索”,本质上是把折线转化为具有较小宽度的长方形条带,再对这个带状区域进行多边形搜索。以上两个方法都能获取到折线相关信息,这里只需要“沿线搜索”,所以获取getPath()即可(见上述代码)。首先把获取到的折线坐标转化为带状区域多边形坐标,然后将带状坐标通过setPath方法设置到Polyline对象即可。剩余步骤类似于多边形搜索。但这种方法,将折线数组转化为带状图形数组的难度比较大。另一种沿线搜索的策略是:先获取折线路径的路线规划,再从路线规划中获取相关poi信息。如此一来,沿线搜索就变成了取折线折点的点搜索。路线规划参考。

首先找到路线规划相关的函数:

var driving = new AMap.Driving(drivingOption)

    // 根据起终点经纬度规划驾车导航路线
    driving.search(new AMap.LngLat(116.379028, 39.865042), new AMap.LngLat(116.427281, 39.903719), function(status, result) {
        // result 即是对应的驾车导航信息,相关数据结构文档请参考  
        //https://lbs.amap.com/api/javascript-api/reference/route-search#m_DrivingResult
        if (status === 'complete') {
            log.success('绘制驾车路线完成')
        } else {
            log.error('获取驾车数据失败:' + result)
        }
    });

接着查看回传参数result的相关属性:DrivingResult对象,发现有start(起点),end(终点),waypoints(途经点,最多支持不大于16个途经点)三个属性可供使用,它们都属于poi类型。所以仿照上述的代码,添加marker并保存数据:

function drivingSearch() {
    driving.search(path[0],path[path.length-1 ],{waypoints:path},function (status, result) {
        if (status === 'complete') {
            log.success('绘制驾车路线完成')
        } else {
            log.error('获取驾车数据失败:' + result)
        }
        
        // var pois = result.poiList.pois;
        var pois = [];
        pois.push(result.start);
        for(i=0;i<result.waypoints.length;i++)
        pois.push(result.waypoints[i]);
        pois.push(result.end);
        for(var i = 0; i < pois.length; i++){
            var poi = pois[i];
            var marker = [];
            marker[i] = new AMap.Marker({
                position: poi.location,   
                // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
                title: poi.name
            });
            // 将创建的点标记添加到已有的地图实例:
            map.add(marker[i]);
            addPOIData(poi.name, poi.id, poi.location.lng, poi.location.lat);
        }
        map.setFitView();

    });
}

使用ie浏览器测试,在新疆附近绘制折线并查询,刷新数据库。
高德地图JS API空间数据采集开发入门实验_第2张图片

ID Name poiID Lng Lat
196 起点 undefined 87.454022 43.870275
197 途经点 undefined 87.454022 43.870275
198 途经点 undefined 87.507031 43.882154
199 途经点 undefined 87.543286 43.864334
200 途经点 undefined 87.530377 43.84017
201 途经点 undefined 87.567455 43.801329
202 途经点 undefined 87.661663 43.837001
203 终点 undefined 87.661663 43.837001
但是这样的到的poi数据并不是理想数据。这是因为绘制折线取点的时候不一定会取到高德地图数据库中拥有地名的点。可以对得到的每一个节点进行小范围的周边搜索,再将搜索得到的结果保存到数据库。
document.querySelector("#search-nearby").onclick = function() {
    AMap.service(["AMap.PlaceSearch"], function() {
        // 构造地点查询类
        var placeSearch = new AMap.PlaceSearch({
            //type: '餐饮服务', // 兴趣点类别
            type: '汽车服务|汽车销售|汽车维修|摩托车服务|餐饮服务|购物服务|生活服务|体育休闲服务|\n' +
            '\n' +
            '医疗保健服务|住宿服务|风景名胜|商务住宅|政府机构及社会团体|科教文化服务|\n' +
            '\n' +
            '交通设施服务|金融保险服务|公司企业|道路附属设施|地名地址信息|公共设施',
            pageSize: 5, // 单页显示结果条数
            pageIndex: 1, // 页码
            city: "010", // 兴趣点城市
            citylimit: true,  //是否强制限制在设置的城市内搜索
            map: map, // 展现结果的地图实例
            panel: "panel", // 结果列表将在此容器中进行展示。
            autoFitView: true // 是否自动调整地图视野使绘制的 Marker点都处于视口的可见范围
        });

        //cpoint = [lng,lat]; //中心点坐标,要传入参数。
        //var cpoint = [116.433320, 39.900255]; //中心点坐标,抱歉,未搜索到有效的结果
        for(j=0;j<pois.length;j++) {


            placeSearch.searchNearBy('', pois[j].location, 200, function (status, result) {
                // 查询成功时,result即对应匹配的POI信息
                console.log(result)
                var pois0 = result.poiList.pois;
                for (var i = 0; i < pois0.length; i++) {
                    var poi = pois0[i];
                    var marker = [];
                    marker[i] = new AMap.Marker({
                        position: poi.location,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
                        title: poi.name
                    });
                    // 将创建的点标记添加到已有的地图实例:
                    map.add(marker[i]);
                    addPOIData(poi.name, poi.id, poi.location.lng, poi.location.lat);
                }
                map.setFitView();

            });
        }
    });
};

高德地图JS API空间数据采集开发入门实验_第3张图片
以北京附近为例,查询之后得到的结果:
高德地图JS API空间数据采集开发入门实验_第4张图片

证明沿线搜索也能运行了。

总结与反思

该实验以高德地图JS API开发文档为基础,对基础查询功能进行了开发。

其中沿线搜索的功能开发并不是很理想,因为绘制的折线并没有能很好的转化为包含折线带状区域。如果通过折线的getPath或者getBound方法得到坐标进行多边形查询,本质都是多边形查询,并没有体现“沿线”这一功能。刚开始想到将折线坐标数组转化为多边形坐标数组(从头到尾将折线坐标偏移一遍,再反过来反方向偏移来构成一个大致包裹折线的多边形),如下:

	var polygonArr1=[];
	var polygonArr2=[];
	var polygonB = [];
	for(i=0;i<polygonArr.length;i++){
		j=polygonArr.length-i-1;
	    polygonArr1.push([polygonArr[i][0],polygonArr[i][1]+10.000000]);
	    polygonArr2.push([polygonArr[j][0],polygonArr[j][1]-20.000000]);
	}
	var polygonB = polygonArr1.concat(polygonArr2);

但是这样的转化效果并不理想,适用性非常差。只能针对角度接近于180度的折线拟合。

后来想到通过规划沿线导航进而获取导航路径的信息poi,经过查询发现也不能如意。driving.search函数只能返回到传入参数的poi信息,而不能获取沿途的poi信息。这样一来,沿线搜索就变成折线折点坐标群体的周边搜索了。关于如何更好实现“沿线搜索”的问题值得深入研究。

其次,代码逻辑性不强,有待完善。例如获取marker(其实是获取poi)并且存储到数据库的代码,每一次不同覆盖物查询都用到一样的语法逻辑。将其封装起来成为一个函数供调用会减少代码重复性。每一次覆盖物查询(或者关键字查询)都是固定不变的:

function(status, result) {
	// 查询成功时,result即对应匹配的 POI信息
	console.log(result)
	var pois = result.poiList.pois;
	for(var i = 0; i < pois.length; i++){
	    var poi = pois[i];
	    var marker = [];
	    marker[i] = new AMap.Marker({
	        position: poi.location,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
	        title: poi.name
	    	});
	    // 将创建的点标记添加到已有的地图实例:
	    map.add(marker[i]);
	    addPOIData(poi.name, poi.id, poi.location.lng, poi.location.lat);
		}
	map.setFitView();
	
	}

将这部分代码抽取得到

// 抽取添加 marker和存储数据的函数
function addMarkerAndPoi(status,result){
    console.log(result);
    var pois = result.poiList.pois;
    for(var i = 0; i < pois.length; i++){
        var poi = pois[i];
        var marker = [];
        marker[i]=new AMap.Marker({
            position: poi.location,
            title: poi.name
        });
        map.add(marker[i]);
        addPOIData(poi.name,poi.id,poi.location.lng,poi.location.lat);
    }
    map.setFitView();
}

将减少代码的冗余性,也更方便阅读和更新。

此外,还可以针对覆盖物开发更多的个性化功能。例如开发支持圆形的编辑;多边形的编辑以及折线的编辑;删除单个覆盖物,移动覆盖物等。高德地图JS API示例都给出了编辑覆盖物/矢量图形相关教程。

通过本次开发实验,了解了高德地图JS API有关搜索查询以及覆盖物的简单知识;学会如何读懂html代码并对相应的元素修改;学会了根据报错信息找到代码疏忽错漏的地方。

你可能感兴趣的:(GIS)