准备工作:

  1. 高德开发者账号(必须经过认证)
  2. 高德web_service_key(web服务key)

参考文档:

猎鹰服务-服务端 https://lbs.amap.com/api/track/lieying-kaifa/api/service

js多边形绘制https://lbs.amap.com/demo/javascript-api-v2/example/overlay-editor/polygon-editor-avoidpolygon/

注意事项:

  1. 申请好对应的key之后,需要先创建对应的service,一个key之下最多有15个service
  2. 每个service之间的数据并不互通
  3. 正常开发测试不会触发高德流量预警

创建猎鹰服务service

public function createService()
{
    $params = [
        'name' => input('name'),
        'desc' => input('desc'),//创建不同的service时,请更换描述
        'key' => input('key'),//webapi key
    ];
    $url = 'https://tsapi.amap.com/v1/track/service/add';
    $arr = [
        'name' => $params['name'],
        'desc' => $params['desc'],
        'key' => $params['key'],
    ];
    $res = $this->send_post($url, $arr);//res中包含唯一值sid,请务必将sid保存
    print_r($res);exit;
}

公共方法

public function send_post($url, $post_data) {

    $postdata = http_build_query($post_data);
    $options = array(
        'http' => array(
            'method' => 'POST',
            'header' => 'Content-type:application/x-www-form-urlencoded',
            'content' => $postdata,
            'timeout' => 15 * 60 // 超时时间(单位:s)
        )
    );
    $context = stream_context_create($options);
    $result = file_get_contents($url, false, $context);

    return $result;
}

创建围栏

//创建圆形围栏
public function createCircle($name, $desc,$key,$sid,$center,$radius)
{
    $url = 'https://tsapi.amap.com/v1/track/geofence/add/circle';
    $arr = [
        'name' => $name,//每一个围栏的名称不能相同
        'desc' => $desc,//每一个围栏的描述不能相同
        'key' => $key,
        'sid' => $sid,
        'center' => $center,//格式如x,y--经度在前纬度在后
        'radius' => $radius,//单位:米,整数,最小1最大50000
    ];
    $res = $this->send_post($url, $arr);//gfid围栏的唯一标识,务必保存
    print_r($res);exit;
}

//创建多边形围栏
public function createPolygon($name, $desc, $points,$key,$sid)
{
    $url = 'https://tsapi.amap.com/v1/track/geofence/add/polygon';
    $arr['key'] = $key;
    $arr['sid'] = $sid;
    $arr['name'] = $name;
    $arr['desc'] = $desc;
    $arr['points'] = $points;//经度1,纬度1;经度2,纬度2;|||注意:经纬度之间用英文逗号分割,不同的点之间用英文分号分割
    //且这些点组成的最大面积必须小于100平方公里(是面积不是距离),若想大于100平方公里请找高德客服
    //points点的顺序必须是顺时针或者是逆时针,例:矩形的情况下第二个点不可为第一个点的对角点
    //points最少传三个最多传100
    $res = $this->send_post($url, $arr);//gfid围栏的唯一标识,务必保存
    print_r($res);exit;
}
//线行围栏:就是一条直线,允许在直线上左右偏差1-300米
//行政区围栏:根据行政区划编码进行区域划分

行政区划编码表点击下载,仅供参考

查询围栏

public function geofenceList($arr)
{
    $url = 'https://tsapi.amap.com/v1/track/geofence/list?key=' . $arr['key'] . '&sid=' . $arr['sid'];//不传gfids分页返回所有的围栏传了就返回gfids包含的围栏
    $res = file_get_contents($url);
    return json_decode($res, true);
}

删除围栏

public function delGeoFence($gfids,$arr)
{
    $url = 'https://tsapi.amap.com/v1/track/geofence/delete';
    $arr['key'] = 'web服务key';
    $arr['sid'] = '对应的sid';
    $arr['gfids'] = $gfids;//可以传多个,以英文逗号分割,最大为100--如果需全部删除,传#all删除所有的
    $res = $this->send_post($url, $arr);//删除A成功了就会返回A
    return json_decode($res, true);
}

查询指定坐标和围栏的关系

public function locationStatus($location, $gfids)
{
    //gfids如果传了就只判断传入的值,可以传多个,以英文逗号分割
    //如果不传就判断与传入sid下所有围栏的关系
    $arr['key'] = '4f61f40afc5f0af9e42fcb7290209d5a';
    $arr['sid'] = '1008773';
    $url = 'https://tsapi.amap.com/v1/track/geofence/status/location?key=' . $arr['key'] . '&sid=' . $arr['sid'] . '&location=' . $location . '&gfids=' . $gfids;
    $res = file_get_contents($url);//data-results-in 0=不在1=在
    return json_decode($res, true);
}

js部分(fastadmin为例,前端纯小白,仅供参考)

<script src="/assets/js/jquery.min.js"></script>
<script src="https://a.amap.com/jsapi_demos/static/demo-center/js/demoutils.js"></script>
<script type="text/javascript"
        src="https://webapi.amap.com/maps?v=1.4.15&key=jsapi---key&plugin=AMap.Geocoder,AMap.MouseTool"></script>
<script type="text/javascript">
    window._AMapSecurityConfig = {
        securityJsCode: 'jsapikey对应的安全密钥,申请完jsapikey之后就能看到',
    }
</script>
<script type="text/javascript">
    // 表单提交
   $('#submit').click(() => {
        $.ajax({
            url: '/admin.php/road/road/add',
            type: 'post',
            dataType: 'json',
            data: $('form').serialize(),
            success: res => {
                console.log(res.code)
                if (res.code == 1) {
                    window.close();
                    Fast.api.close();
                    location.href = '/admin.php/road.road/index'
                    window.parent.location.reload();
                }

            }
        })
        return false
    })


    // var nodeData = {:json_encode($treeList); };

    //一、初始化 "地图中心"
    var lon = "{$row.lon}" ? "{$row.lon}" : 116.397413;
    var lat = "{$row.lat}" ? "{$row.lat}" : 39.920912;

    //二、初始地图中心点
    var map1 = new AMap.Map("container", {
        center: [lon, lat],
        resizeEnable: true,
        zoom: 10
    });

    //二、初始地图中心点
    var map2 = new AMap.Map("container2", {
        center: [lon, lat],
        resizeEnable: true,
        zoom: 10
    });

    let mouseTool1 = new AMap.MouseTool(map1)
    mouseTool1.on('draw', event => {
        console.log(event.obj.getPath())
        let a = event.obj.getPath()
        let b = ''
        a.forEach((item, index) => {
            if (b) {
                b = b + ';' + item.lng + ',' + item.lat
            } else {
                b = item.lng + ',' + item.lat
            }
        })
        $('#map_lat_1').val(b)
        mouseTool1.close()
    })
    // 绘制围栏
    $('#map1').click( () => {
        mouseTool1.close(true)
        mouseTool1.polygon({
            strokeColor: "#FF33FF",
            strokeOpacity: 1,
            strokeWeight: 6,
            strokeOpacity: 0.2,
            fillColor: '#1791fc',
            fillOpacity: 0.4,
            // 线样式还支持 'dashed'
            strokeStyle: "solid",
            // strokeStyle是dashed时有效
            // strokeDasharray: [30,10],
        })
        return false
    })

    let mouseTool2 = new AMap.MouseTool(map2)
    mouseTool2.on('draw', event => {
        let a = event.obj.getPath()
        let b = ''
        a.forEach((item, index) => {
            if (b) {
                b = b + ';' + item.lng + ',' + item.lat
            } else {
                b = item.lng + ',' + item.lat
            }
        })
        $('#map_lat_2').val(b)
        mouseTool2.close()
    })
    // 绘制围栏
    $('#map2').click( () => {
        mouseTool2.close(true)
        mouseTool2.polygon({
            strokeColor: "#FF33FF",
            strokeOpacity: 1,
            strokeWeight: 6,
            strokeOpacity: 0.2,
            fillColor: '#1791fc',
            fillOpacity: 0.4,
            // 线样式还支持 'dashed'
            strokeStyle: "solid",
            // strokeStyle是dashed时有效
            // strokeDasharray: [30,10],
        })
        return false
    })

</script>

html部分,fastadmin为例,仅供参考

<form id="add-form" class="form-horizontal" role="form"  method="POST" action="">

   
    <div class="form-group">
        <label class="control-label col-xs-12 col-sm-2">{:__('起点所在位置')}:</label>
        <button class="btn" id="map1">绘制围栏</button>
        <input type="text" id="map_lat_1" name="row[lng_lat_1]">
        <div class="col-xs-12 col-sm-12" id="map_box">
            <div id="container"></div>
            <div class="input-card hidden" id="map_box_1">
                <div class="input-item">
                    <div class="input-item-prepend"><span class="input-item-text">经纬度</span></div>
                    <input id='lnglat' data-rule="required" type="text" value="">
                </div>
                <!--<div class="input-item">
                    <div class="input-item-prepend"><span class="input-item-text">地址</span></div>
                    <input id='address' data-rule="required" type="text" readonly value="">
                </div>

                <div>
                    <input id="regeo" type="button" class="btn describe" value="经纬度 -> 地址">
                </div>-->
            </div>
        </div>
    </div>
    
    <div class="form-group">
        <label class="control-label col-xs-12 col-sm-2">{:__('终点所在位置')}:</label>
        <button class="btn" id="map2">绘制围栏</button>
        <input type="text" id="map_lat_2" name="row[lng_lat_2]">
        <div class="col-xs-12 col-sm-12" id="map_box2">
            <div id="container2"></div>
            <div class="input-card hidden" id="map_box_2">
                <div class="input-item">
                    <div class="input-item-prepend"><span class="input-item-text">经纬度</span></div>
                    <input id='lnglat2' data-rule="required" type="text" value="">
                </div>
                <!--<div class="input-item">
                    <div class="input-item-prepend"><span class="input-item-text">地址</span></div>
                    <input id='address' data-rule="required" type="text" readonly value="" name="row[address]">
                </div>

                <div>
                    <input id="regeo" type="button" class="btn describe" value="经纬度 -> 地址">
                </div>-->
            </div>
        </div>
    </div>

    <div class="form-group layer-footer">
        <label class="control-label col-xs-12 col-sm-2"></label>
        <div class="col-xs-12 col-sm-8">
            <button type="button" id="submit" class="btn btn-success btn-embossed">{:__('OK')}</button>
            <button type="reset" class="btn btn-default btn-embossed">{:__('Reset')}</button>
        </div>
    </div>
</form>
<link rel="stylesheet" href="/assets/css/amap.css"/>
<style>
    #map_box #container {
        width: 100%;
        height: 580px;
    }

    .describe {
        width: 10rem;
        margin-left: 3.8rem;
        display: inline;
    }

    .amap-icon img {
        width: 25px;
        height: 34px;
    }

    .amap-marker-label {
        border: 0;
        background-color: transparent;
    }

    #map_box {
        position: relative !important;
    }

    #map_box_1 {
        position: absolute !important;
        width: 28rem;
    }
    #map_box2 #container2 {
        width: 100%;
        height: 580px;
    }

    #map_box2 .input-card {
        display: flex;
        flex-direction: column;
        min-width: 0px;
        overflow-wrap: break-word;
        background-color: rgb(255, 255, 255);
        background-clip: border-box;
        width: 22rem;
        border-width: 0px;
        border-radius: 0.4rem;
        box-shadow: rgb(114 124 245 / 50%) 0px 2px 6px 0px;
        /*position: fixed;*/
        bottom: 1rem;
        right: 1rem;
        flex: 1 1 auto;
        padding: 0.75rem 1.25rem;
        position: absolute !important;
</style>