esri-leaflet入门教程(5)- 动态要素加载
esri-leaflet入门教程(5)- 动态要素加载
by 李远祥
在上一章节中已经说明了esr-leaflet是如何加载ArcGIS Server提供的各种服务,这些都是服务本身来决定的,API脚本只是非常简单的调用。但如果要做一列的地图交互操作或者动态渲染等,那就必须使用地图区域跳转、查询结果渲染、动态添加图形等多种交互手段。而这些交互手段基本上离不开一些非服务类型的数据加载,我们可以将其成为动态要素。动态要素一般是在页面端进行动态绘制的。
动态要素这一说法并不是ArcGIS 或者leaflet的说法,而是笔者想了很久之后才编出来的一个名词,为的就是要使ArcGIS JavaScript API 体系与esri-leaflet能找到一个比较好的对应关系,便于ArcGIS的开发人员能够快速的切换过来。esri-leaflet 本身就是基于leaflet去做的扩展,因此,很多情况下都不能摆脱leaflet的限制,文雅点来说就是必须遵循leaflet的定义的接口规范。对于多年ArcGIS开发人员来说,刚开始的时候是有点不习惯的,因为很多时候某些功能和接口不能很好的映射回ArcGIS JavaScript API中。所以,要搞清楚esri-leaflet的使用,那就必须从leaflet本身入手。
在传统的ArcGIS JavaScript API中,要加载一些动态的要素(非直接引用服务的数据),必须使用graphic或者是graphicLayer(其实也是graphic的数组)。graphic在ArcGIS JS里面是由四个部分组成的,分别是geometry(图形)、symbol(符号)、attributes(属性)、infoTemplate(弹窗),如下图
虽然是四个参数,但并不一定要全部使用才能构建,一般来说最基本是需要一个geometry参数就行了,系统会自动给与graphic一个默认的symbol,这样构成一个最简单的graphic,就可以加载到地图上去了。总的来看,ArcGIS的API中是遵循ArcGIS数据的理念,图元(暂且这么说吧,真不知道中文怎么区分graphic和geometry)的显示是读取了要素的图形和属性,并且可以修改其符号(symbol),在地图交互时还可以绑定一些特定的弹出信息。
但在esri-leaflet中,从它提供的基础类来看,根本没有graphic和symbol,就连geometry都没有!这很让人抓狂。为了搞清楚这个关键问题,笔者特意去翻一遍leaflet的接口。终于在leaflet的基础类型中找到了关于图形的一系列接口 http://leafletjs.com/reference-1.0.3.html#layer,其分组也是相当的奇怪,名叫 Vector Layers ,乍一看还以为是一种矢量地图服务,如下图
这个里面就包含了所有的图形定义格式,传统的线、面、圆等都有了,但没有点,因为点是单独的在UI Layers 里面的Marker 。当然了没有arcgis定义的多,但基本也能满足了。再来看其定义是怎样的,点击polyline去查看其构建例子:
// create a red polyline from an array of LatLng points
var latlngs = [
[45.51, -122.68],
[37.77, -122.43],
[34.04, -118.2]
];
var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
// zoom the map to the polyline
map.fitBounds(polyline.getBounds());
通过上述代码可以发现几个问题,polyline的构建方式是需要传入点的数组,在构建的时候在其option参数中可以设置其样式,例子中就是使用了color参数,最后图形是可以直接作为Layer加载到地图中,可以与这个图形交互,通过fitBounds 方法跳转到polyline的图形位置。
也有人奇怪,点进polyline和polygon等的这些接口,居然没看到有类似的options可以实现color或者是宽度等设置。那是因为这些接口都在Path中实现,其他的如polyline、polygon、circle等都是实现了path的接口。可以查看下Path的options,如下图
可以看到传统的颜色、线宽、透明度等都可以在options里面设置。
从上面的资料基本上可以看到leaflet与ArcGIS的对应关系了。leaflet中的没有所谓的单独的图元一说,在动态要素来说,全部都是属于Layer,都实现了Layer的接口,其相当于ArcGIS体系中将graphicLayer和graphic 融合在一起,leaflet所谓的图元就是ArcGIS的 graphicLayer+graphics。这感觉还是有点乱,但基本上可以了解leaflet和ArcGIS JS体系的差异。
那么问题来了,由于esri-leaflet 中是没有实现类似ArcGIS JavaScript API中的graphic、geometry、symbol等接口,所有的操作都必须在leaflet的基础体系下完成,那这个代码该怎么编写?
我们可以通过查看esri-leaflet的例子,看看它是如何实现前端加载的。笔者查看的例子在 http://esri.github.io/esri-leaflet/examples/styling-feature-layer-polylines.html 可以看看其截图效果,对道路进行了动态的渲染。
再来看关键代码实现部分
var map = L.map('map').setView([45.5275, -122.6717], 14);
L.esri.basemapLayer('Streets').addTo(map);
var bikePaths = L.esri.featureLayer({
url: 'https://services.arcgis.com/uCXeTVveQzP4IIcx/ArcGIS/rest/services/Bike_Routes/FeatureServer/0',
style: function (feature) {
var c,o = 0.75;
switch (feature.properties.BIKEMODE) {
case 'Low traffic through street':
c = '#007D7D';
break;
case 'Bike boulevard':
c = '#00FF3C';
break;
case 'Caution area':
c = '#FF0000';
break;
case 'Local multi-use path':
c = '#00BEFF';
break;
case 'Regional multi-use path':
c = '#b1a9d0';
break;
case 'Moderate traffic through street':
c = '#FFEB00';
break;
case 'Planned multi-use path':
c = '#000000';
break;
case 'Bike lane':
c = '#328000';
o = '0.70';
break;
case 'High traffic through street':
c = '#FFA500';
break;
case 'Planned bike lane':
c = '#000000';
o = '1.0';
break;
default:
c = '#C0C0C0';
}
return {color: c, opacity: o, weight: 5};
}
}).addTo(map);
可以关键部分是获取了ArcGIS 的Featureservice 的要素,针对要素进行了style的设置,做了一个分等级和颜色的渲染。关键部分是使用了L.esri.featureLayer 接口。从这里可以看到端倪,对于动态的要素的加载,esri也是遵循了leaflet的规则,特意搞什么graphiclayer之类的特殊图层,而是想leaflet一样,直接在Layer中实现,当然这个Layer就是自家的featurelayer了。那传统的graphic前端绘制怎么办?esri-leaflet没有给出答案,笔者看到所有的基于后台服务查询的结果最终都是以featurelayer的形式展示出来,esri-leaflet中根本就没有在客户端绘制图形的接口。其实这部分答案很明确,就是使用leaflet本身的Vector Layers ,开发人员可以直接将其等同于graphiclayer就行了。
为了搞清楚真相,笔者又专门查找了 L.esri.featureLayer 的相关说明,发现其options 的属性里面的style一项居然是实现了leaflet本身的ILayer接口,如下图所示
前面我们看到的Vector Layers 部分其实也是实现了ILayer,也就是说,不管是采用什么样的方式去做动态要素的加载和交互操作,最终还是会落到ILayer和Vector Layers 中去,从ArcGIS的实现方法来看,可见一斑了。
原理清楚之后,所以的问题都可以迎刃而解了,关于代码实现部分就变得异常的简单了。接下来就可以用自己的数据按照例子进行制作一遍。例如笔者现在要按照道路的等级对道路进行实际的渲染,分别采用不同的颜色和粗细来渲染。代码很简单,跟例子差不多,不过就是替换成自己的数据。
function addFeatures() {
var featlayer = L.esri.featureLayer({
url: 'http://localhost:6080/arcgis/rest/services/dongguan/FeatureServer/2',
style: function(feature) {
var c, w, o = 0.75;
switch(feature.properties.type) {
case '44000':
c = '#007D7D';
w = 3;
break;
case '45000':
c = '#00FF3C';
w = 2;
break;
case '51000':
c = '#FFA500';
w = 3;
break;
default:
c = '#C0C0C0';
w = 1;
}
return {
color: c,
opacity: o
};
}
});
map.addLayer(featlayer);
}
这里要注意几点,首先要留意的是esri-leaflet是如何获取要素的属性的,代码中可以看到参数中使用的是 feature.properties.type 其中feature.properties是获取属性的方式,后面加点,接着是字段名(笔者的服务里面使用的是type字段分类)。可以通过arcgis server 的服务路径查看服务的字段情况,例如 http://localhost:6080/arcgis/rest/services/dongguan/FeatureServer/2 道路的要素图层信息如下图所示:
这里还要注意一点就是,arcgis server发布的服务,无论原始数据的字段是否大小写,都会一律转为小写字母,所以要特别注意。还有数据中千万别使用中文作为字段名称,这个大家懂的^_^ 。那么可以看看接下来的效果了,如下图所示
接下来就是自定义的图形加载地图上了。前面已经提及过,这类型的加载方式必须使用leaflet的方式进行。例如我们可以通过以下代码去加载一个面图形,并将其加到地图上面。
function addPolygon(){
var latlngs = [[23.17, 113.45],[23.15, 113.46],[23.19, 113.46],[23.19, 113.45]];
var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
}
其实际效果如下:
这里值得注意的有几点,一是面图形的构建是一个二维数组,数组元素记录的是xy坐标,但不是[经度,纬度],而是恰好反过来,[纬度,经度]。另外,如果要清除掉动态绘制的图形,那就必须使用ILayer的接口,就是在构建面的时候,其实声明的就是一个Layer,可以利用Layer的remove方法进行清除,在该代码实例中要清除前端的图形,那就是使用 polygon.remove();
由于leaflet对点的绘制做了特别的关照,将它放在UI Layer 而非Vector Layers 中,属于非常个性的部分,如果要加载点的数据,也是可以使用leaflet的方法来构建。但是arcgis server 中的点要素服务,如果要直接动态加载,那L.esri.featureLayer 接口中也有特殊的做法。例如如下核心代码
L.esri.basemapLayer('Streets').addTo(map);
L.esri.featureLayer({
url: 'https://services.arcgis.com/rOo16HdIMeOBI4Mb/arcgis/rest/services/Trimet_Transit_Stops/FeatureServer/0',
pointToLayer: function (geojson, latlng) {
return L.marker(latlng, {
icon: icons[geojson.properties.direction.toLowerCase()]
});
},
}).addTo(map);
可以看到,在featurelayer中使用了一个方法是pointToLayer ,强行将esri格式转为L.marker 。说到底还是使用了L.marker接口,只不过是再封装了一层转换而已。具体的代码可在 http://esri.github.io/esri-leaflet/examples/styling-feature-layer-points.html 进行查看。
上面的很多代码都是基于arcgis 的featureservice 是制作的,但也有人会说,featureservice的发布需要后台有ArcSDE支撑,如果没有ArcSDE的数据源,那岂不是连基本的动态要素绘制都不能做?其实不然,这个问题Esri的工程师应该早就想到。看接口名称叫 L.esri.featureLayer ,不代表它只能支持featureservice,在上述的动态要素加载的代码中,将featureservice改为使用mapservice,同样可以使可运行的,这个只是命名的名称让大家产生误会而已。笔者也特意尝试了一把,将原来的路径替换为 http://localhost:6080/arcgis/rest/services/dongguan/MapServer/2 ,还是能出来原来的结果,因此无需虚惊一场。
总结:总的来说,esri-leaflet在动态要素加载方面还是坚持的不错,尽管大部分的操作都是使用leaflet原有的接口实现。对于从来没有过ArcGIS开发经验的人来说,毫无历史负担,即学即用。对于ArcGIS老鸟来说,还是需要一些时间去琢磨,毕竟一些使用习惯和叫法发生了一定改变。
esri-leaflet入门教程(5)- 动态要素加载的更多相关文章
- esri-leaflet入门教程(4)-加载各类图层
esri-leaflet入门教程(4)-加载各类图层 by 李远祥 在leaflet中图层一般分为底图(Basemap)和叠加图层(Overlay).前面章节已经介绍过底图其实也是实现了TileLay ...
- Entity Framework入门教程(8)---预先加载、延迟加载、显示加载
1.预先加载 预先加载:在对一种类型的实体进行查询时,将相关的实体作为查询的一部分一起加载.预先加载可以使用Include()方法实现. 1.加载一个相关实体类型 栗子:使用Include()方法从数 ...
- 【PHP面向对象(OOP)编程入门教程】23.自动加载类 __autoload()函数
很多开发者写面向对象的应用程序时,对每个类的定义建立一个 PHP 源文件.一个很大的烦恼是不得不在每个脚本(每个类一个文件)开头写一个长长的包含文件的列表. 在软件开发的系统中,不可能把所有的类都写在 ...
- Canvas制作动态进度加载水球
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- Java_动态重新加载Class总结
在此记载Java动态重新加载Class的点点滴滴,实现之前也在网上看了很多文章,但发现不是很清晰,后来发现总结,看源码实现还是最靠谱. 直接上代码: package com.lkb.autoCode. ...
- Java_动态重新加载Class机制
Java动态重新加载Class 项目中使用到了动态重新加载Class的机制,作用是让一些代码上线之前可以在线上环境测试一下,当然,这是非常不好的测试机制,我刚来的时候也为这种机制感到惊讶—怎么可以在线 ...
- Echarts通过Ajax实现动态数据加载
Echarts(3.x版)官网实例的数据都是静态的,实际使用中往往会要求从服务器端取数据进行动态显示,官网教程里给出的异步数据加载很粗略,下面就以官网最简单的实例为例子,详细演示如下过程:1.客户端通 ...
- Android系统下的动态Dex加载
1 问题在Android系统中,一个App的所有代码都在一个Dex文件里面.Dex是一个类似Jar的存储了多有Java编译字节码的归档文件.因为Android系统使用Dalvik虚拟机,所以需要把使用 ...
- Android系统下的动态Dex加载与app速度优化
1 问题 在Android系统中,一个App的所有代码都在一个Dex文件里面.Dex是一个类似Jar的存储了多有Java编译字节码的归档文件.因为Android系统使用Dalvik虚拟机,所以需要把 ...
随机推荐
- 【转】图片缓存之内存缓存技术LruCache、软引用 比较
每当碰到一些大图片的时候,我们如果不对图片进行处理就会报OOM异常,这个问题曾经让我觉得很烦恼,后来终于得到了解决,那么现在就让我和大家一起分享一下吧.这篇博文要讲的图片缓存机制,我接触到的有两钟,一 ...
- UVa 11172 - Relational Operator
题目大意:给两个数,比较大小... #include <cstdio> int main() { int T; scanf("%d", &T); int a, ...
- UVa 11456 - Trainsorting
题目大意:给一个车辆到达车站的序列(按时间先后),可以对车辆进行以下处理:插在队首.插在队尾或者拒绝进站.车站内的车辆必须按照重量大小从大到小排列,问车站内最多能有多少辆车辆? 假设车i是第一个进站, ...
- 基于Python,scrapy,redis的分布式爬虫实现框架
原文 http://www.xgezhang.com/python_scrapy_redis_crawler.html 爬虫技术,无论是在学术领域,还是在工程领域,都扮演者非常重要的角色.相比于其他 ...
- 基于arm开发板四个按键控制四个灯亮
基于s5pv2410,cortex a8的四个按键每一个按键点了对应的灯 对于用汇编来编程的话不难,重点在于数据手册,电路图,管脚的看懂 直接上代码 .globl _start_start: ldr ...
- 基于回调的事件处理——重写onTouchEvent方法响应触摸屏事件
对于Android提供的事件处理模型,不难发现基于监听的事件处理模型具有更大的优势: 基于监听的事件模型分工更加明确,事件源.事件监听有两个类分开实现,因此具有更好的维护性. Android的事件处理 ...
- abstract、override、new、virtual、sealed使用和示例
abstract修饰类名为抽象类,修饰方法为抽象方法.如果一个类为抽象类,则这个类智能是其他某个类的基类.抽象方法在抽象类中没有函数体.抽象类中的抽象方法是没有方法体的,继承其的子类必须实现抽象类的抽 ...
- DNS没有生效的几个原因
1.记录没有正确添加 请确认你的域名记录是否完全正确的添加.线路类型正确,记录类型正确 2.域名还没有生效 这个情况还会有另外一个现象,就是域名有时候可以ping,有时候不能ping. 这是因为你当地 ...
- Canvas drawImage API
drawImage <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- JavaWeb知识回顾二
动态web资源相关 1.tomcat相关 tomcat的目录结构 bin -- tomcat服务器的批处理文件的存放目录 conf -- tomcat服务器配置文件的存放目录 lib -- tomca ...