标签 GIS 下的文章

0、开始

本篇文章介绍如何使用高德地图 Web API,在地图中显示具有高度和面的自定义多边形标注。

1、准备工作

首先申请高德地图的key。申请完毕之后,新建一个空白的 html 页面,引入需要的资源:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>高德地图开发示例</title>
    <style>
        html,
        body,
        #map {
            height: 100%;
        }
        body {
            margin: 0;
        }
    </style>
</head>

<body>
    <div id="map"></div>
</body>

</html>
<script src="https://webapi.amap.com/maps?v=2.0&key=your_key"></script>
<script src="https://webapi.amap.com/loca?v=2.0.0&key=your_key"></script>
<script>
    //我们就在这里编写代码
</script>

2、初始化

初始化地图:

var map = new AMap.Map('map', {
    zoom: 17.6,
    viewMode: '3D', //使用3D模式才能显示3D标注
    pitch: 45, //倾斜角度
    mapStyle: 'amap://styles/darkblue', //使用黑色地图看起来更神秘…
    center: [116.40,39.92], //使用故宫作为地图中心点
    showBuildingBlock: false, //不显示建筑块
    showLabel: false, //不显示街道名之类的标签
});

接着初始化Loca

var loca = window.loca = new Loca.Container({ map });

3、获取多边形数据

接受的数据是标准GeoJSON格式的,我们需要准备GeoJSON格式的数据。格式如下:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "properties": {},
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            lng,
                            lat
                        ],
                        ......
                    ]
                ]
            }
        },
        ......
    ]
}

有4种方法获取数据

  1. 使用阿里的DataV.GeoAtlas地理小工具,不过,对于一些偏远地区,地图上没有道路和建筑,一片空白,没办法按照所需目标的轮廓标注多边形,而卫星地图模式清晰度非常差。
  2. 使用高德地图官方提供的地图快速生成工具,利用“添加标注”功能,把需要标注的区域标注好,然后点击“获取代码”按钮,找到features变量,这里面包含了我们想要的数据,但并不是GeoJSON格式,不过这对于程序员来说非常简单,只需要非常简单的处理,就能获取到上面代码中coordinates部分需要的数组,这里不再赘述。
  3. 使用这个GeoJSON在线编辑器,它的卫星地图比较清晰,但有三个缺点:1是可能需要科学上网,它自带3种地图模式,第一种不能显示。另外,地图缩放后,需要拖动一下地图,才能触发地图的加载。2是标注对于高德地图有所偏移,需要处理,一般是将获取到的经纬度统一加减一些比较小的数值,大约是在小数点后3、4位。3是经度的表示方法可能与高德地图不同,例如-243.63281249999997,需要如下处理:

    360 - Math.abs(-243.63281249999997)

  4. 当然,也可以使用坐标拾取器,一个点一个点地获取和填写coordinates数组。需要注意的是,必须要登录高德地图网站,才能获取精确的位置。

这里使用第二种方法,获取到故宫的外形如下:

{
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "id": 10647,
            "properties": {},
            "geometry": {
                "type": "Polygon",
                "coordinates": [
                    [
                        [
                            116.39156454,
                            39.92287908
                        ],
                        [
                            116.40190578,
                            39.92322019
                        ],
                        [
                            116.40229494,
                            39.91337002
                        ],
                        [
                            116.39189816,
                            39.91294358
                        ],
                        [
                            116.39156454,
                            39.92287908
                        ]
                    ]
                ]
            },
            "bbox": [
                116.39156454,
                39.91294358,
                116.40229494,
                39.92322019
            ]
        }
    ],
    "gid": 7711
}

新建polygon.json,将上面的数据粘贴进去。

4、将数据添加到地图上

代码如下:

var geo = new Loca.GeoJSONSource({
    url: './polygon.json',
});

var pl = new Loca.PolygonLayer({
    zIndex: 120,
    opacity: 0.8,
    shininess: 10,
    hasSide: true,
});

pl.setSource(geo);

pl.setStyle({
    //设置不同面的颜色
    topColor: 'rgba(43,83,144,0.5)',
    sideTopColor: 'rgba(43,83,144,0.5)',
    sideBottomColor: 'rgba(43,83,144,0.5)',
    height: 2000, //物体的高度
    altitude: 0,
});

loca.add(pl);

这段代码非常简单。需要注意的是,高德的文档或者示例代码可能不一致,如果你遇到代码不起作用的情况,需要尝试改为 API 文档中的代码或者示例代码中的代码。

下面是显示效果:

1.png

这是某工厂的建筑:

2.png

除了三维多边形,还可以添加许多东西,详情参考Loca数据可视化API

End

0、保存Map实例

NOTE:

如何引入天地图SDK请参考以前的文章

首先要做的肯定是保存Map实例,可以保存在Vue实例上:

this.Map = new T.Map(......);

或者保存在window上:

window.Map = new T.Map(......);

1、创建标注

创建标注使用的是工具类。下面都用点(Marker)来作为例子。

在页面中创建一个按钮,使用它的click事件来打开标注工具

<button @click="btnClick">添加点</button>

为了看起来不违和,你可以把这个按钮的样式做成和地图原生控件一样。

click事件中打开标注工具:

btnClick(){
  //如果标注工具已经存在,先关闭它
  window.marktool && window.marktool.close();

  //创建一个Icon实例
  let icon = new T.Icon({
    iconUrl: 'https://x.y.z/1.png'
  });

  //实例化工具
  let marktool = new T.MarkTool(window.Map, {
    icon,
    follow: true
  });

  marktool.open();
  window.marktool = marktool;
}

现在,点击添加点按钮的时候,鼠标指针将变成你定义的icon的样式,点击地图,就会在点击的位置留下一个标记。

2、给标记添加自定义的数据

标记肯定代表了某个实际的东西,需要补充额外的内容。可以在上一步给marktool注册一个mouseup事件,给刚刚创建的标记添加一个click事件,以便我们进行更多的操作:

//别忘了先保存一下Vue实例this:
let _this = this;
//onMarkMarked是Vue的Method
//e.currentMarker代表当前标记
marktool.addEventListener('mouseup', function (e) {
  _this.onMarkMarked(e.currentMarker);
});

VueonMarkMarked方法中:

onMarkMarked(marker){
  let _this = this;
  //直接添加数据
  marker.MyData = {foo: 'bar', baz: 'balabala...'};
  //保存marker,使页面中任何代码都能访问,就能任意赋值了
  //但要注意,currentMark保存的是当前标记,创建新标记时,它代表的是新的标记
  _this.currentMark = marker;
}

Vue的其他方法中给它赋值:

onModelClosed(){
  this.currentMark.myname = this.inputName;
  //......

  //可以在控制台看到marker实例中包含自定义的数据
  console.log(this.currentMark);
}

3、保存标记数据

首先获取到标记:

let markers = window.Map.getOverlays();

返回的是一个标记数组,如果有多个标记,根据需要,可能需要循环处理。这里假设只有一个marker标记。
标记信息含有很多无用的信息,我们需要的一般都是标记的坐标、自定义的数据。标记的样式由于是提前定义好的,所以并不会通过标记获取。

let lnglat = markers[0].getLnglat();
let { myname, MyData } = markers[0];

此时就可以保存到数据库了。


END

UPDATE:8/16

天地图的JavaScript3.0 API中提供了一些方法,在4.0的文档中没有,但是仍然可用,比如设置地图的样式:

map.setMapType(...)

1、引入天地图API

按需引入,在需要用到天地图API的时候,动态创建script标签:

//某组件
...
mounted() {
    this.initMap();
},
...
//methods
initMap(){
    let script = document.getElementById('MapDivId');
    if (script) {
        return this._initMap();
    }

    const _this = this;
    script = document.createElement('script');
    script.id = 'MapDivId';
    script.src = 'https://tianditu.gov.cn/xxxxxxxx';
    script.onload = function () {
        _this._initMap();
    };

    document.body.appendChild(script);
}

二、初始化地图

...
_initMap() {
    //添加卫星图层,下面这个url是固定的,我只找到这种默认显示卫星图层的办法
    let satelliteLayerUrl = "http://t0.tianditu.gov.cn/img_w/wmts?" + "SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles" + "&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&tk=您的密钥";
    let layer = new T.TileLayer(satelliteLayerUrl, { minZoom: 3, maxZoom: 18 });
    window.GIS.Map = new T.Map('Map', { layers: [layer] });
    // 定位到一个默认的坐标,例如北京。这里的坐标是虚构的
    window.GIS.Map.centerAndZoom(new T.LngLat(123.45678, 30.1234), 12);

    //添加地图类型控件
    let ctrlMapType = new T.Control.MapType([
        {
            title: '卫星混合',
            icon: 'http://api.tianditu.gov.cn/v4.0/image/map/maptype/satellitepoi.png',
            layer: TMAP_HYBRID_MAP
        },
        {
            title: '地图',
            icon: 'http://api.tianditu.gov.cn/v4.0/image/map/maptype/vector.png',
            layer: TMAP_NORMAL_MAP
        }
    ]);
    window.GIS.Map.addControl(ctrlMapType);

    //添加缩放控件
    let ctrlZoom = new T.Control.Zoom();
    window.GIS.Map.addControl(ctrlZoom);
    ctrlZoom.setPosition(T_ANCHOR_BOTTOM_RIGHT);

    //添加比例尺控件
    let ctrlScale = new T.Control.Scale();
    window.GIS.Map.addControl(ctrlScale);
},
...

三、添加各种标注工具

首先编写HTML结构,定位到地图上的某个位置,并绑定一个click事件,这部分很简单,效果如下:

1.png

然后编写click事件代码:

<span class="icon xxxx" @click="openPolygonTool"></span>
openPolygonTool() {
    if (window.GIS.handler) window.GIS.handler.close();
    let handler = new T.PolygonTool(window.GIS.Map);
    handler.open();
    window.GIS.handler = handler;
}

效果如下:

2.png

四、保存标注数据

一般在打开标注工具的时候,注册一个相关事件,这样,在结束标注的时候,就能获取到标注的数据。多边形的结束事件是draw

openPolygonTool() {
    ...
    handler.addEventListener('draw', function(e){
        console.log(e);
    });
    handler.open();
    ...
}

到这里,就可以把需要的数据存储起来了。

END