GIS

本文最后更新于:5 个月前

基于GIS的开发与学习

GIS

什么是GIS

GIS: Geographic lnformation System 地理信息系统

地理信息系统(GIS,Geographic Information System)是一门综合性学科结合了地理学与地图学以及遥感和计算机科学

GIS开发通常分为

  • 桌面端开发
  • web端开发
  • 移动端开发

C/S & B/S

C/S 架构

客户机-服务器,即Client-Server(C/S)结构
C/S结构通常采取两层结构
服务器负责数据的管理,客户机负责完成与用户的交互任务

B/S 架构

浏览器-服务器,Browser/Server
主要应用于广域网中

三层:

  • Browser客户端
  • webapp服务器端
  • DB(数据库)端

webGIS

webGIS
将前端可视化技术与GIS技术结合,提供更好的信息展示和用户交互

HTML –> vue/react –> openlayers/cesium

GIS框架本质上来讲,使用的依然是JavaScript做为编程语言,结合HTML和CSS在地图场景的具体应用

webGIS - 地图组成结构

图层 - Layer

图层是指能够在视觉上覆盖一定地图范围,用来描述全部或者部分现实世界区域内的地图要素的抽象概念

标准图层、卫星图层、路网图层、路况图层

矢量图形 - Vector Overlays

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

点标记 - Markers

点标记是用来标示某个位置点信息的一种地图要素,覆盖于图层之上

点要素

地图控件 - Map Controls

控件浮在所有图层和地图要素之上,用于满足一定的交互或提示功能

地图名词

地图级别 - ZoomLevel

级别与地图的比例尺成正比,每增大一级,地图的比例尺也增大一倍,地图显示的越详细

Web地图的最小级别通常为3级,最大级别各家略有不同,高德地图JSAPI目前最大级别为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坐标系统

高德开放平台

高德开放平台官网:https://lbs.amap.com/

开发准备

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/abc/prepare

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>

    <!--引入高德脚本-->

    <script type="text/javascript">
        window._AMapSecurityConfig = {
            securityJsCode:'您申请的安全密钥',
        }
    </script>
    <script type="text/javascript" 
        src="https://webapi.amap.com/maps?v=2.0&key=您申请的key值">
    </script> 

    <!--设置地图样式-->

    <style>
        #container{
            width: 700px;
            height: 700px;
            }
    </style>
  <head>
  <body>

    <!--创建地图容器-->

    <div id="container"></div>
    <script>
        //定义一个变量,保存/加载对象
        var map = new AMap.Map('container')
    </script>
  </body>
</html>

效果图

地图参数

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/documentation#map

var map = new AMap.Map('map', {
      viewMode: '3D',
      center: [116.397083, 39.874531],
      layers: [AMap.createDefaultLayer()],  // layers 字段为空或者不赋值将会自动创建默认底图。
      zoom: 12,
})

地图图层

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/layers/official-layers

例–按钮—>实时路况

<body>
    <button onclick="add()">显示实时路况</button>
    <button onclick="remove()">隐藏实时路况</button>

    <!--创建地图容器-->
    <div id="container"></div>
    <script>
        //定义一个变量,保存/加载对象
        var map = new AMap.Map('container',{
            zoom: 10,  //设置地图显示的缩放级别
            center: [116.397428, 39.90923],//设置地图中心点坐标
            viewMode: '2D',  //设置地图模式
        });

        var traffic = new AMap.TileLayer.Traffic({
            'autoRefresh': true,     //是否自动刷新,默认为false
            'interval': 180,         //刷新间隔,默认180s
        });

        //map.add(traffic); //通过add方法添加图层
        //map.remove(traffic) //需要时可以移除

        function add()
        {map.add(traffic)} 
        function remove()
        {map.remove(traffic)}
    </script>
  </body>

地图控件

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/overlays/toolbar

    AMap.plugin(['AMap.ToolBar','AMap.Scale','AMap.HawkEye','AMap.MapType','AMap.ControlBar'],function(){

            //添加控件
            //ToolBar(工具条) 集成了缩放,平移,定位
            map.addControl(new AMap.ToolBar())

            //Scale(比例尺) 展示地图在当前层级和经纬度下的比例
            map.addControl(new AMap.Scale())

            //HawkEye(鹰眼) 右下角显示地图的缩略图
            map.addControl(new AMap.HawkEye())
            
            //MapType(切换图层)
            map.addControl(new AMap.MapType())
            
            //ControlBar(工具条方向盘)
            map.addControl(new AMap.ControlBar())

        })

地图事件

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/events/map_overlay

例 - 获取鼠标点击经纬度

// 监听地图的点击事件
        map.on('click',function(event){
            //控制台输出当前点击具体信息
            console.log(event)

            //输出经纬度
            console.log(`经度:${event.lnglat.lng},纬度:${event.lnglat.lat}`)
        })

点标记 Marker

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/overlays/marker

基于经纬度绘制点—

         //基于经纬度绘制点
        var marker = new AMap.Marker({
            position: new AMap.LngLat(116.39, 39.9),   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
            title: '北京'
        });

        // 将创建的点标记添加到已有的地图实例:
        map.add(marker);

        // 移除已创建的 marker
        //map.remove(marker);

点图标无法正常显示,需附带本地路径+图片

    offset: new AMap.Pixel(-10, -10), //相对点的偏移位置
    icon: '2.png', // 添加 Icon 图标 URL

交互式绘制点

//交互式绘制点
       map.on('click',function(event){
            //控制台输出当前点击具体信息
            console.log(event)

            //输出经纬度
            console.log(`经度:${event.lnglat.lng},纬度:${event.lnglat.lat}`)

            var marker = new AMap.Marker({
            position: event.lnglat,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
            offset: new AMap.Pixel(-10, -10),
            icon: '2.png', // 添加 Icon 图标 URL
            title: '北京'
        });

        // 将创建的点标记添加到已有的地图实例:
        map.add(marker);
        })

点图标无法正常显示,需附带本地路径+图片

自定义Icon图标

 icon: '2.png', // 添加 Icon 图标 URL

var icon = new AMap.Icon({
    size: new AMap.Size(40, 50),    // 图标尺寸
    image: '//webapi.amap.com/theme/v1.3/images/newpc/way_btn2.png',  // Icon的图像
    imageOffset: new AMap.Pixel(0, -60),  // 图像相对展示区域的偏移量,适于雪碧图等
    imageSize: new AMap.Size(40, 50)   // 根据所设置的大小拉伸或压缩图片
});
icon:icon

圆点标记—标注省会

  <script type="text/javascript" src='https://a.amap.com/jsapi_demos/static/resource/capitals.js'></script>

for(var i=0;i<capitals.length;i+=1){
    var center = capitals[i].center;
    var circleMarker = new AMap.CircleMarker({
          center:center,
          radius:10+Math.random()*10,//3D视图下,CircleMarker半径不要超过64px
          strokeColor:'white',
          strokeWeight:2,
          strokeOpacity:0.5,
          fillColor:'rgba(0,0,255,1)',
          fillOpacity:0.5,
          zIndex:10,
          bubble:true,
          cursor:'pointer',
          clickable: true
        })
    circleMarker.setMap(map)
  }

纯文本标记

<!--纯文本标记-->
    <link rel="stylesheet" href="https://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>

// 创建纯文本标记
        var text = new AMap.Text({
            text:'111111',
            anchor:'center', // 设置文本标记锚点
            draggable:true,
            cursor:'pointer',
            angle:10,
            style:{
                'padding': '.75rem 1.25rem',
                'margin-bottom': '1rem',
                'border-radius': '.25rem',
                'background-color': 'white',
                'width': '15rem',
                'border-width': 0,
                'box-shadow': '0 2px 6px 0 rgba(114, 124, 245, .5)',
                'text-align': 'center',
                'font-size': '20px',
                'color': 'blue'
            },
        position: [116.396923,39.918203]
    });

    text.setMap(map);

矢量图形

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/overlays/vector-overlay

折线 Polyline

// 折线的节点坐标数组,每个元素为 AMap.LngLat 对象
var path = [
    new AMap.LngLat(116.368904,39.913423),
    new AMap.LngLat(116.382122,39.901176),
    new AMap.LngLat(116.387271,39.912501),
    new AMap.LngLat(116.398258,39.904600)
];

// 创建折线实例
var polyline = new AMap.Polyline({
    path: path,  
    borderWeight: 2, // 线条宽度,默认为 1
    strokeColor: 'red', // 线条颜色
    lineJoin: 'round' // 折线拐点连接处样式
});

// 将折线添加至地图实例
map.add(polyline);

多边形 Polygon 、圆形 Circle 、矩形 Rectangle 、 椭圆形 Ellipse

几何计算

距离、长度、面积

高德开放平台官网:https://lbs.amap.com/api/jsapi-v2/guide/geometry/geometry

  • 计算两点间的实际距离 AMap.GeometryUtil.distance
  • 计算点到线段的最短距离 AMap.GeometryUtil.distanceToSegment
  • 计算点到路径的最短距离 AMap.GeometryUtil.distanceToLine
  • 计算路径的实际长度 AMap.GeometryUtil.distanceOfLine
  • 计算封闭区域的面积 AMap.GeometryUtil.ringArea

计算两点间的实际距离

当需要计算两个地理位置间的实际地面距离时,可以使用静态方法 AMap.GeometryUtil.distance,返回数据以米为单位

var p1 = [116.434027, 39.941037];
var p2 = [116.461665, 39.941564];
// 返回 p1 到 p2 间的地面距离,单位:米
var dis = AMap.GeometryUtil.distance(p1, p2);

可移动两点的直线距离

  1. 创建两个点,设置可以拖动
  2. 准备一条线段
  3. 准备一个文本
  4. 计算

(定位点—武汉)

    // 可移动两点的直线距离
       //1. 创建两个点,设置可以拖动
       var m1= new AMap.Marker({
        map:map,        //将m1这个点添加到AMap中
        draggable:true, //设置该点可以拖动
        position:new AMap.LngLat(114.255,30.621),
        icon: '2.png', // 添加 Icon 图标 URL
       })

       var m2= new AMap.Marker({
        map:map,        //将m1这个点添加到AMap中
        draggable:true, //设置该点可以拖动
        position:new AMap.LngLat(114.334,30.579),
        icon: '2.png', // 添加 Icon 图标 URL
       })

       //让地图根据覆盖物调整地图显示区域
       map.setFitView()

       //2. 准备一条线段
       var line= new AMap.Polyline({
        strokeColor:'#80d8ff',  //描边的颜色
        isOutline:true,         //包含轮廓
        outerlineColor:'white'  //轮廓颜色
       })
       line.setMap(map)

       //3. 准备一个文本
       var text = new AMap.Text({
            text:'',
            style:{
                'background-color':'#29b6f6',
                'border-color':'#e1f5fe',
                'font-size':'16px',
            }, 
       })
       text.setMap(map)
   
       //4.计算
       function compute(){
            //得到m1,m2的经纬度
            var p1 = m1.getPosition()
            var p2 = m2.getPosition()

            //希望文本显示在两个经纬度的中间
            //divideBy() 除法
            var textPos = p1.divideBy(2).add(p2.divideBy(2))//(p1+p2)/2

            //distance() 计算两点的直线距离
            //Math.round() 取整
            var distance = Math.round(p1.distance(p2))

            //定义路径
            var path = [p1,p2]
            line.setPath(path)  //绘制线段,根据p1,p2的坐标

            //为text填充值
            text.setText('距离为'+distance+'米')
            //设置文字的显示区域
            text.setPosition(textPos)
       }
       compute()
       m1.on('dragging',compute)
       m2.on('dragging',compute)

GeoJSON

GEOJSON官网:https://geojson.org/

GeoJSON is a format for encoding a variety of geographic data structures.

GeoJSON是一种用于编码各种地理数据结构的格式

{
      "type": "Feature",     //要素
      "geometry": {        //几何信息 
    "type": "Point",    //包括点、线、多边形、多个点、多条线和多个边形
       "coordinates": [125.6, 10.1]     //经纬度坐标点
      },
      "properties": {        //自定义属性信息
        "name": "Dinagat Islands"    
      }
}

数据的持久化

持久化的方式

使用GDB数据库,将数据保存在地理数据库中

使用GeoJSON,将数据保存到GeoJSON格式的文件中

GeoJSON- 封装数据读写函数

---------->getdata.js

//从localStorage读取数据
 function getData(){
    //如果本地localStorage不存在数据
    if(!localStorage.getItem('geojson')){
        localStorage.setItem('geojson','[]')
    }
    else
    {return JSON.parse(localStorage.getItem('geojson'))}
}

//将数据保存到localStorage中
function saveData(data)
{
    localStorage.setItem('geojson',JSON.stringify(data))
}

<script src="getdata.js"></script> 

GeoJSON - 数据持久化实现

//在加载配置中的plugins插件中添加'AMap.GeoJSON'才能够使用。(官方文档好像并没有说明,可能也是我没看到)

    AMap.plugin(['AMap.GeoJSON',],function(){})

    //定义一个全局变量,用于保存GeoJSON
    var geojson = new AMap.GeoJSON({
        geoJSON:null,
    })

    //本地不为空,导入数据
    if(JSON.stringify(getData())!='[]'){
        //导入数据/显示/添加在地图上
        geojson.importData(getData())
    }
    map.add(geojson)

    //动态绘制点(动态数据更新)
    map.on('click',function(event){
            var marker = new AMap.Marker({
            position: event.lnglat,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
            offset: new AMap.Pixel(-10, -10),
            icon:'2.png',
        });
        //通过geojson对象来管理覆盖物
        geojson.addOverlay(marker)
        //保存数据(将geojson对象转换成标准GeoJSON数据)
        saveData(geojson.toGeoJSON())
        console.log(geojson)
    })

    console.log(geojson)

GeoJSON - 新旧数据的点击事件

 //使用新创建的覆盖物的点击事件
     //动态数据
    map.on('click',function(event){
            var marker = new AMap.Marker({
            position: event.lnglat,   // 经纬度对象,也可以是经纬度构成的一维数组[116.39, 39.9]
            offset: new AMap.Pixel(-10, -10),
            icon:'2.png',
        });

        //使用新创建的覆盖物的点击事件
        marker.on('click',function(e){
            console.log(e.lnglat,'点击了')
        })


    
        //通过geojson对象来管理覆盖物
        geojson.addOverlay(marker)
        //保存数据(将geojson对象转换成标准GeoJSON数据)
        saveData(geojson.toGeoJSON())
        console.log(geojson)
    })




//恢复旧数据的点击事件
    //本地不为空,导入数据
    if(JSON.stringify(getData())!='[]'){
        //导入数据/显示/添加在地图上
        geojson.importData(getData())

        //恢复旧数据的点击事件---eachOverlay() 得到geojson中的每一个点
        geojson.eachOverlay(function(item){
            item.on('click',function(e){
                console.log(e.lnglat,'旧的数据点击了')
            })
        })
    }

GeoJSON - 自定义属性的使用

    //自定义属性
            extData:{
                _geoJsonProperties:{
                    //gid 点的唯一标识
                    gid:geojson.getOverlays().length+1,
                    //click 点击次数
                    click:0,
                }
            }

getExtData
ext._geoJsonProperties.属性

         //使用新创建的覆盖物的点击事件

        marker.on('click',function(e){
            console.log(e.lnglat,'点击了')

            //让点击的marker对象的click属性+1
            var ext=marker.getExtData()
            ext._geoJsonProperties.click=ext._geoJsonProperties.click+1
            var click = ext._geoJsonProperties.click
            console.log('点击了'+click+'次')

            saveData(geojson.toGeoJSON())

        })

GeoJSON - 点击后的消息提示

    //使用新创建的覆盖物的点击事件
        marker.on('click',function(e){
            console.log(e.lnglat,'点击了')

            //让点击的marker对象的click属性+1
            var ext=marker.getExtData()
            ext._geoJsonProperties.click=ext._geoJsonProperties.click+1
            var click = ext._geoJsonProperties.click
            console.log('点击了'+click+'次')

            //使用消息提示框显示
            var infowindow = new AMap.InfoWindow({
                anchor:'top-center',
                content:`<div>打卡了${click}次</div>`
            })

            //显示(打开信息窗口)
            infowindow.open(map,marker.getPosition())
            

            saveData(geojson.toGeoJSON())
        })

GeoJSON - 路径规划

<div class="input-card">
    <h4>推荐浏览路线</h4>
    <div class="input-item">
        <button class="btn" onclick=startDH()>开始动画</button>
    </div>
</div>


function startDH(){
        console.log("开始动画")

        //实现路径规划
        AMap.plugin('AMap.Driving',function(){
            var Driving= new AMap.Driving({
                map:map,

                //驾车的路径规划策略---官方文档
                policy:AMap.DrivingPolicy.LEAST_TIME,
            })
            //设置起点和终点
            var start = new AMap.LngLat(106.5620,29.5626)
            var end = new AMap.LngLat(121.516043,31.217199)

            //绘制路线
            Driving.search(start,end,function(status,res){
                if(status=='complete'){
                    console.log('ok')
                }
                else console.log('nonono ')
            })
        })
    }

GeoJSON - 实现路径途径点

//通过geojson得到每一个点的坐标
            var opts = {
                waypoints:[]
            }
            geojson.eachOverlay(function(item){
                opts.waypoints.push(item.getPosition())
            })

//绘制路线
            Driving.search(start,end,opts,function(status,res){

GeoJSON - 轨迹模拟动画

//动画插件
    AMap.plugin(['AMap.MoveAnimation',],function(){})

function startDH(){
        console.log("开始动画")

        //实现路径规划
        AMap.plugin('AMap.Driving',function(){
            var Driving= new AMap.Driving({
                map:map,
                //驾车的路径规划策略
                policy:AMap.DrivingPolicy.LEAST_TIME,
            })
            //设置起点和终点
            var start = new AMap.LngLat(106.5620,29.5626)
            var end = new AMap.LngLat(121.516043,31.217199)

            //通过geojson得到每一个点的坐标
            var opts = {
                waypoints:[]
            }
            geojson.eachOverlay(function(item){
                opts.waypoints.push(item.getPosition())
            })

            //绘制路线
            Driving.search(start,end,opts,function(status,res){
                if(status=='complete'){

                    //实现轨迹模拟
                    
                    //小车标记
                    var marker = new AMap.Marker({
                        map:map,
                        position:start,
                        icon:'1.png',
                        offset:new AMap.Pixel(-26,-13),
                        //自动调转车头
                        autoRotation:true,
                        angle:-180,
                    }) 

                    //模拟已过路径
                    var passedPolyline = new AMap.Polyline({
                        map:map,
                        strokeColor:"#AF5", //线的颜色
                        strokeWeight:6,     //线宽度
                    })
                    
                    //线经过的路径---当点移动时,使用passedPolyline函数
                    marker.on('moving',function(e){
                        passedPolyline.setPath(e.passedPath)
                    })
                    //地图合适的显示效果
                    map.setFitView()

                    var lineArr=[]

                    //........item.path 所需要经过的路径
                    res.routes[0].steps.forEach(function(item){
                        lineArr.push(...item.path)
                    })
                    
                    //每隔一段时间移动---lineArr 所经过的路径
                    marker.moveAlong(lineArr,{
                        duration:500,       //更新界面的时间
                        autoRoatation:true, //车头的方向
                    })
                }
                else console.log('nonono ')
            })
        })
    }

模拟轨迹/官方

<!doctype html>
<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://a.amap.com/jsapi_demos/static/demo-center/css/demo-center.css"/>
    <style>
        html, body, #container {
            height: 100%;
            width: 100%;
        }

        .input-card .btn{
            margin-right: 1.2rem;
            width: 9rem;
        }

        .input-card .btn:last-child{
            margin-right: 0;
        }
    </style>
</head>
<body>
<div id="container"></div>
<div class="input-card">
    <h4>轨迹回放控制</h4>
    <div class="input-item">
        <input type="button" class="btn" value="开始动画" id="start" onclick="startAnimation()"/>
        <input type="button" class="btn" value="暂停动画" id="pause" onclick="pauseAnimation()"/>
    </div>
    <div class="input-item">
        <input type="button" class="btn" value="继续动画" id="resume" onclick="resumeAnimation()"/>
        <input type="button" class="btn" value="停止动画" id="stop" onclick="stopAnimation()"/>
    </div>
</div>
<script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=您申请的key值"></script>
<script>
    var marker, lineArr = [[116.478935,39.997761],[116.478939,39.997825],[116.478912,39.998549],[116.478912,39.998549],[116.478998,39.998555],[116.478998,39.998555],[116.479282,39.99856],[116.479658,39.998528],[116.480151,39.998453],[116.480784,39.998302],[116.480784,39.998302],[116.481149,39.998184],[116.481573,39.997997],[116.481863,39.997846],[116.482072,39.997718],[116.482362,39.997718],[116.483633,39.998935],[116.48367,39.998968],[116.484648,39.999861]];

    var map = new AMap.Map("container", {
        resizeEnable: true,
        center: [116.397428, 39.90923],
        zoom: 17
    });

    marker = new AMap.Marker({
        map: map,
        position: [116.478935,39.997761],
        icon: "https://webapi.amap.com/images/car.png",
        offset: new AMap.Pixel(-26, -13),
        autoRotation: true,
        angle:-90,
    });

    // 绘制轨迹
    var polyline = new AMap.Polyline({
        map: map,
        path: lineArr,
        showDir:true,
        strokeColor: "#28F",  //线颜色
        // strokeOpacity: 1,     //线透明度
        strokeWeight: 6,      //线宽
        // strokeStyle: "solid"  //线样式
    });

    var passedPolyline = new AMap.Polyline({
        map: map,
        // path: lineArr,
        strokeColor: "#AF5",  //线颜色
        // strokeOpacity: 1,     //线透明度
        strokeWeight: 6,      //线宽
        // strokeStyle: "solid"  //线样式
    });


    marker.on('moving', function (e) {
        passedPolyline.setPath(e.passedPath);
    });

    map.setFitView();

    function startAnimation () {
        marker.moveAlong(lineArr, 200);
    }

    function pauseAnimation () {
        marker.pauseMove();
    }    

    function resumeAnimation () {
        marker.resumeMove();
    }

    function stopAnimation () {
        marker.stopMove();
    }
</script>
</body>
</html>

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!