在WebGIS开发过程中那个,我们不可避免地要对地图要素(点、线、面等)进行表达,对矢量要素的绘制表达通常又是WebGIS的技术热点问题之一。
目前,常见的浏览器矢量绘制方法有SVG、VML、Canvas三种,flash不在本次讨论的范围内。简单回顾一下这三种方式,
SVG(ScaleVector Graphics可缩放矢量图形) ,2000年8月由W3C制定的,是一个开放标准,基于可扩展标记语言(XML),用于描述二维矢量图形的一种图形格式,严格遵从XML语法,用文本格式的描述性语言来描述图像内容。SVG包括3种类型的对象: 矢量图形(包括直线、曲线在内的图形边)、点阵图像和文本;
VML(The Vector Markup Language矢量可标记语言),微软1999年9月附带IE5.0发布的,应用在IE浏览器中(IE5-7/8),在VML中使用两个基本的元素:shape和group。这两个元素定义了VML的全部结构;shape描述一个矢量图形元素,而group用来将这些图形结合起来,这样它们可以作为一个整体进行处理。
另外一种方式就是基于HTML的Canvas标签来实现
Canvas标签是HTML5的一部分,最初由苹果内部使用自己Mac OS X WebKit推出,供应用程序使用像仪表盘的构件和Safari浏览器使用,允许脚本语言动态渲染位图像。
以上是三种比较常见的浏览器客户端矢量绘制方法,那么在用ArcGIS JS API进行WebGIS开发采用的是哪种方式呢?
默认情况下ArcGIS JSAPI里是采用SVG的方式来进行矢量绘制的,但是对IE7/8或之前的版本则是用的VML方法。
知道了底层的矢量绘制方法,还得说道说道客户端的要素表达方式。使用过ArcGIS JS API的应该很熟悉两个概念:symbol和renderer,这是WebGIS里地图要素表达不可或缺的,一个用来表达显示特征,另一个则是渲染效果。symbol很好理解,无非是按要素几何类型设置的轮廓、填充及颜色、透明度等,那renderer是如何工作的呢,renderer其实是在浏览器本身矢量绘制功能的基础上抽象出另外一个层来,从而进一步对其中的几何形状进行操作的。
而现在要跟大家分享的是除了传统的基于symbol和renderer方式的要素表达之外,另外一种全新的基于CSS的要素表达,如果参加过今年ESRI用户大会的,相信也在技术专场讲座里看到过。
首先要问一下,为什么会出现这种新的要素表达选项呢。官方给的说法有两个方面:
一是对于习惯使用CSS的人来说是一个非常好的选择,可以很快上手;
二是可以更方便地运用CSS来给要素添加动画效果;
其实,在技术层面归根节点是对DOM元素的操作权,如果使用ArcGIS JS API的renderer,就无法基于DOM进行要素图形的操作和样式、动画设置,但可以使用ESRI封装好的完整的渲染功能,包括分类渲染、唯一值渲染、点密度渲染等;
而使用CSS来直接控制矢量要素则提供了更高的灵活性和定制化,可以根据需要设置要素样式和丰富的动画效果,但是WebGIS中常见的分类、唯一值等渲染方式都要自己代码来完成。
可以说各有利弊吧,看具体情况需要来选择。但出于对新鲜事物的好奇,我们还是一起来探究一下如何使用这种新的要素表达方式。
前面讲了诸多的理论性东西,那到底这种新表达方式是怎么用的呢?接下来的实战为你一步步揭晓。
在ArcGIS JS API里,GraphicsLayer(FeatureLayer的父类)通过新增加两个构造函数的可选参数以及一个属性来支持CSS对要素的样式设置。分别是
styling是布尔类型,代表了图层是否应用图形样式和图层渲染器,默认是true。如果设置为false,可采用CSS来设置图形样式。
dataAttributes是一个字符串或者字符串组,它对应着属性字段。这将作为每个图形节点的data attributes(HTML5里的dom元素的自定义data-***属性)。我们可以使用CSS来选择某一个或一类要素进行样式应用。data attribute的名字至少包含一个字符且不能包含大写字母。
surfaceType表示图层的矢量绘制方法,允许的值为”svg”,”canvas-2d”,”vml”,这个设置对地图上所有的矢量图层都是相同的,默认值是”SVG”(除了IE7,8用的是VML)。
接下来进行实际的一些示例操作:
刚才提到构造函数里变化,那在创建图层的时候就需要提前进行设置。首先要设置图层styling和dataAttributes属性,当styling为false时可以使用CSS,dataAttributes为图层属性表中的字段或者字段组,示例如下:
var featureLayer = new FeatureLayer(“featurelayerUrl”,{ id:”featurelayer”, styling:false; dataAttributes:[“fb_pop”] })
classbreaks = [ { attribute:"classbreak0", value:959, legendLabel:"0 - 959" }, { attribute:"classbreak1", value:1492, legendLabel:"959 - 1,492" }, { attribute:"classbreak2", value:1914, legendLabel:"1,492 - 1.914" }, ...... ]; if (featureLayer.surfaceType === "svg") { on(featureLayer, "graphic-draw", function (evt) { var tableAttr = evt.graphic.attributes.pop_urban_; var category; if (tableAttr < classbreaks[0].value) { category = classbreaks[0].attribute; } else if (tableAttr >= classbreaks[0].value && tableAttr < classbreaks[1].value) { category = classbreaks[1].attribute; } ...... // 为当前要素设置data attribute evt.node.setAttribute("data-classbreak", category); }); }
属性 |
值 |
描述 |
data-class-break |
"<Number>" |
Class break index as returned by ClassBreaksRenderer.getBreakIndex. |
data-geometry-type |
"<String>" |
Geometry type: "point", "polyline", "polygon" or "multipoint". |
data-hidden |
"" (empty string) |
Added to the graphic's node when it is hidden. |
data-selected |
"" |
Added to the graphic's node when it is selected. |
data-unique-value |
"<String>" |
Graphic's unique value as returned by UniqueValueRenderer.getUniqueValueInfo. |
另,由于是对SVG的矢量要素进行CSS设置,需要对SVG元素及操作有一定的了解。
选择了某一个或者某一类要素后就可以进行样式及动画的设置了,上面几步其实是做了一个类似分类渲染的分类,那接下来就对不同的类型进行样式和填充设置。
path[data-classbreak="classbreak0"] { stroke: rgb(255, 245, 220); stroke-width: 1pt; stroke-opacity: 0.35; fill: rgb(255, 215, 120); fill-opacity: 0.8; } path[data-classbreak="classbreak1"] { stroke: rgb(255, 233, 185); stroke-width: 1pt; stroke-opacity: 0.35; fill: rgb(255, 193, 60); fill-opacity: 0.8; }
分类渲染社会自后,继续设置要素动画效果,添加animation动画效果:
@keyframes highlight { 100% { fill-opacity: 1; stroke-width: 4; stroke: rgb(220, 20, 60); } } @-webkit-keyframes highlight { 100% { fill-opacity: 1; stroke-width: 4; stroke: rgb(220, 20, 60); } } ...... path:hover { cursor: pointer; animation-duration: 0.2s; animation-name: highlight; animation-timing-function: linear; animation-fill-mode: forwards; -webkit-animation-duration: 0.2s; -webkit-animation-name: highlight; -webkit-animation-timing-function: linear; -webkit-animation-fill-mode: forwards; }
上面简单展示了基于CSS来如何进行要素表达,那简单总结下基于renderer和css这两种要素表达方式:
Table 1 WebGIS要素表达方式总结
|
Renderer |
CSS |
优点 |
1、开箱即用的模块,封装好了常见的WebGIS渲染方法; 2、大量可参考、直接复用的代码示例; 3、Renderers应用在复杂的形状上比CSS更加容易 |
1、CSS可对SVG可以直接进行DOM元素操作; 2、CSS动画效果丰富; 3、对于习惯使用CSS的人来说可以更好地发挥优势;
|
缺点 |
Renderers是通过在浏览器本身的矢量绘制能力基础上进行抽象出来的图层上进行工作的。这种方法的限制是无法锁定指定的DOM元素。ArcGIS JS API中本身也缺少动画效果的API
|
SVG不支持CSS的z-index属性,而是按添加的顺序来绘制,会出现重叠要素覆盖的问题。如果一个小的要素先绘制,那么就可能被后来绘制的大一点的要素覆盖而变得不可见。对于这种情景,通常设置较大要素的透明度来解决。 |