WebGIS中栅格图层的设计【系列1-5】
1. 前言
我们在上一章里了解到WebGIS中栅格图层的本质——地图图片。而从之前的第二章到第五章,我们详细的介绍了地图图片的获取原理和方法。所以在设计栅格图层前,我们已经知道了栅格图层中数据是如何获得的,剩下的便是怎样将这个过程用一种符合面向对象的设计原则来进行实现。
2.栅格数据获得的流程
这里我再次将栅格数据获得的流程描述一遍:
首先,得到屏幕范围内的地图四角坐标,根据此四角坐标算出屏幕范围内地图最靠近的地图级别,以及此时瓦片的行号范围以及列号范围,然后按照行号和列号拼接出瓦片请求,进行瓦片加载。最后将得到的瓦片按照顺序拼接成一整块地图,进而在前端显示出来。
3.实际中的问题
设计前我们提出这样一个问题:
我们栅格数据的来源可能有很多种,比如在线地图和离线地图。同时,在线地图可能是由不同的请求方式而获得的数据,离线地图也同样可能是来自于不同的切图格式。
我们本身是不能确定用户使用哪一种数据来源,或者用户是否会中途改变数据来源。
4.思路
仔细分析上面提出的问题,结合面向对象设计中的继承、封装、多态三个特性,我们可以抽象出这样的一种设计思路:
(1)设计一个类,此类为所有的栅格图层最高的父类——BaseLayer。在该类中定义一些所有类皆需要的要素,同时提供最基础的方法,比如事件监听方法。
(2)设计一个过度的类——ImageLayer,此类继承于BaseLayer,但是在此类中对部分共同的方法进行实现。比如瓦片的请求中,行号和列号是每一种栅格图层均需要有的,并且瓦片的拼接方式也是通用的。所以由这几个共同点,可以定义一些与此相关的方法。
(3)设计具体的栅格图层类,比如设计针对于ArcGIS在线地图的类、针对于超图在线地图的类、针对于WMS请求方式的类等等。而这些具体类均继承于ImageLayer。
5.UML图
根据第4节中的思路,我们这里给出一种栅格图层的设计方式:
6.对栅格图层设计的详解
从UML图中可以看出,我们首先提炼出了每种瓦片图层所共有的一个基类,即BaseLayer,在这个基类中包括了组成每一种图层所必须有的几个属性,例如瓦片图层的本质-Canvas,以及每一个瓦片图层的几何边境范围还有对地图事件的监听和移除方法等。
而所有瓦片图层涉及到的核心算法,即获取瓦片的行列号、瓦片在屏幕中的坐标等均是首先在继承于BaseLayer中的ImageLayer里进行定义以及部分共同算法的编写。其中getMapByGeoExtent是核心的算法,此算法的功能是将范围内的瓦片的url进行换算以及通过url进行瓦片请求和加载。
每一个具体的瓦片图层类均是直接继承于ImageLayer,然后在具体瓦片图层中实现对瓦片行列号的换算,以及瓦片的URL的换算。在地图加载事件触发后,进行execTileRequest方法进而调用基类父类ImageLayer中的geoMapByExtent方法。
7.优化栅格图层的设计
根据栅格图层设计的原理,可以在两个方面进行优化。一个是瓦片请求时,请求的地图范围的优化;一个是对请求得到的瓦片按照一定的规则缓存到内存中。
7.1瓦片请求范围的优化
如果地图每次只请求屏幕范围内的瓦片,那么每当地图平移被触发就会进行瓦片请求,这样会让前端经常处于瓦片请求状态。但是同样,瓦片请求的范围也不能过大,过大会造成请求瓦片时用户等待时间成正比。所以,在屏幕范围外设置一个合理的缓存范围,使每次请求时请求的地图范围为屏幕范围加上缓存范围之和。(screenBoundary+toleranceBoundary)是很必要的。
7.2瓦片的缓存
如果每次请求的瓦片均需要从服务器或者浏览器的瓦片缓存中获取,这势必将延长前端地图的展现时间,如果能直接将瓦片缓存到内存中,然后遇到相同瓦片时直接从内存中读取,这比上述两种方式都要快,能加快前端地图的显示。但是同样,瓦片不能缓存太多,这样对内存来说负荷太大,并且很多瓦片用过一次后,可能后来很长时间都不会用到,所以需要用一定的调度规则以及合理的内存容器大小来放置和管理瓦片。
8.优化的实现
8.1请求范围优化的实现
在实际项目中,有的项目是默认在屏幕范围所对应的瓦片范围上,另外在四周扩充一个或多个瓦片的宽度范围。而有的项目,对此不做任何处理,因为我们实际上获得的瓦片范围,其本身就是大于屏幕所对应的地理范围的。
对于想人为扩充一个或多个瓦片宽度范围的读者,可以在本系列第三章中,计算瓦片实际起始号时,人为的将瓦片起始号进行变动。在变动瓦片起始号后,后面计算出来的请求瓦片的实际地理范围等参数均需作出相关调整。
当然,最简单的是不人为做此优化,因为如我上面所说,我们通过公式算出来的瓦片范围本身就是比屏幕地理范围要大的。优化在基本算法中就已经实现了。
8.2瓦片缓存机制的实现
我们可以定义一个大小固定的容器,其中内容是通过键值对来存储。每个瓦片的URL是独一无二的,可以当做Key。而容器中瓦片的调度规则为使用频率排序加先进先出原则。详细流程如下:
(1)容器中新添加的瓦片放在所有瓦片的上面,Max(index)。
(2)容器中被调用的瓦片重新放在所有瓦片的上面(Max(index)),而其他瓦片均自动向前进一位(index-1)
(3)当容器装满时,将最低层的瓦片删除,即index为0的瓦片被删除。
9.总结
基于之前章节的知识,我们在这一章里没有多描述栅格数据的获取原理和方法,而是把重点都放在了栅格图层的设计上面,在最后我们介绍了两个优化栅格图层设计的思路。栅格图层作为WebGIS中地形图的显示核心,设计一个好的栅格图层组织方式是至关重要的,否则会照成地形图显示过慢,或者不能很好的支持多种地形图来源。并且如果设计的不合理,会照成大量的代码冗余,导致任何扩展或者维护均会非常困难。当然,这里给出的这种设计框架肯定不是最好的,希望我能给读者抛砖迎玉。下一章开始,要开始连续几个篇章来讲解矢量图层的设计了。我会从矢量图层的数据来源、坐标转换和最后的设计实现来跟大家一起全面的探索WebGIS中的矢量图层。欢迎大家持续关注。