PGIS大数据量点位显示方案

PGIS大数据量点位显示方案

问题描述

PGIS在地图上显示点位信息时,随点位数量的增加浏览器响应速度会逐渐变慢,当同时显示上千个点时浏览器会变得非常缓慢,以下是进行的测试:

测试环境:

  • 服务器:

CPU:Intel(R) Xeon(R) 2.00GHz ,4核

内存:2G

  • 客户端:

CPU: E5200@ 2.59GHz, 2核

内存:2G

下面是测试结果:

点位数量

IE内存占用

平均响应时间

放大缩小

点击响应时间

100

44.22M

基本无延时

1 S

基本无延时

400

49.09M

0.1 S

1.5 S

基本无延时

900

62.67M

0.3 S

3 S

基本无延时

1500

67.85M

1.5 S

5 S

基本无延时

10000

164.104M

不能拖动

不能缩放

 

原因分析

以下是从PGIS显示原理和平台代码实现方式两个方面进行的分析。

PGIS显示原理

山海经纬PGIS利用微软的VML技术在地图上描绘一个点位,每个点位信息最终都生成一个div图层,覆盖到地图图层上。当同时显示上千个点时,浏览器要同时渲染上千个div图层,非常影响性能。

平台显示点位信息的方法

平台在批量显示点位信息时,分3个步骤进行:

  1. 首先查询平台业务数据库,获得安装点编号的集合。
  2. 根据安装点编号集合拼接查询条件,到PGIS空间数据库中查询需要显示的安装点集合。
  3. 循环PGIS查询出来的安装点集合,显示到地图上。在循环中同时查询业务数据库,获得每个安装点的详细信息,作为弹出信息窗的内容。

现行做法存在的问题

  1. 业务数据库中没有存安装点的坐标,需要同时查询业务库和PGIS空间库才能将安装点显示出来。
  2. 安装点明细信息没有进行缓存,每显示一个安装点都需要查询一次业务数据库。
  3. 一次将所有点位显示出来,当点位太多时影响浏览器的响应速度,很多图标叠加在一起也影响界面的美观性。

优化措施

根据以上分析,可以从以下几个方面进行优化。

视野范围内加载

  • 思路

    可以考虑只加载在视野范围内的安装点,以减少浏览器渲染的压力。

  • 分析

    将当前所有点位信息储存在一个数组中。当需要批量显示点位信息时,找出数组中在当前视野范围内的点并进行展示。

  • 实现

以下是用到的PGIS相关接口:

  1. 查询当前地图显示范围:var boundsMBR =_MapApp.getBoundsLatLng()。
  2. 查询指定点是否在指定显示范围内:boundsMBR.containsPoint(Point)
  3. 隐藏一个图层。 PGIS没有提供隐藏一个图层的接口,但一个图层根本上来说是一个div,可以通过隐藏div来实现:pOverLay.div.style.display='none';
  4. 删除一个图层: _MapApp.removeOverlay(pOverLay)

具体的代码:

//隐藏当前视窗范围外的图层

function hidePointsOutOfBounds(){

var boundsMBR=_MapApp.getBoundsLatLng();

var zoomlevel=_MapApp.getZoomLevel();

for(var i=0;i<layerarray.length;i++){

pOverLay = layerarray[i];

if(boundsMBR.containsPoint(pOverLay.getPoint())){

if(layerflag &&((i+1)%zoomlevel!=0)){

_MapApp.removeOverlay(pOverLay);

pOverLay.div.style.display='none';

}else{

if(pOverLay.div.style.display=='none'){

pOverLay.div.style.display='';

_MapApp.addOverlay(pOverLay);

}

}

}else{

if(pOverLay.div.style.display==''){

_MapApp.removeOverlay(pOverLay);

pOverLay.div.style.display='none';

}

}

}

}

分层加载

  • 思路

    如果一次将所有点位显示出来,相邻的点位会紧挨在一起,整个地图看起来元素很多,也不方便用户进行操作。可以考虑分层加载方法减少同时加载的点位数量。

  • 分析

    给每个点位设定层级范围,地图显示时获得当前比例尺层级,只显示当前层级下指定的点位。

  • 实现

    新增安装点层级表。表结构如下:

    MONITOR_POINT_LAYR

名称

代码

数据类型

注释

默认值

安装点编号

POINTCODE

NVARCHAR2(16)

   

最大层级

MAXLAYER

NVARCHAR2(2)

   

最小层级

MINLAYER

NVARCHAR2(2)

   

在前台显示数据时,首先获得当前层级:

var zoomlevel=_MapApp.getZoomLevel();

然后循环安装点列表,获得每个安装点的最大层级和最小层级,判断是否满足条件:

minlevel<=Zoomlevel<=maxlayer

只有满足该条件的安装点才进行显示。

不加载标题

  • 思路

安装点标题现在默认显示在点位信息上面,可以考虑默认不显示标题,当鼠标移动到点上时再加载。

  • 分析

    每个安装点标题都占据一个单独的div层级,点位多时标题会挤在一起,影响美观性,也不方便查看。

  • 实现

    每个安装点在加载时默认隐藏标题:

    marker.hideTitle();

    添加鼠标监听事件,当鼠标移动上时显示标题,移出时隐藏标题:

marker.addListener("mouseover",function(){marker.showTitle()});    marker.addListener("mouseout",function(){marker.hideTitle()});

坐标点存储

  • 思路

    目前显示安装点需要同时查询业务库和PGIS空间数据库。业务库获得安装点明细信息,空间库获得经纬度坐标。单纯的数据展示可以考虑只查询一个数据库。设计到空间搜索等问题时再查询PGIS空间库。

  • 分析

    将安装点的坐标存到业务库中,这样在批量显示安装点时候不需要查询PGIS空间数据库就可以了。只有涉及到空间查询如点周边查询等操作时才操作PGIS空间数据库。

    另外,可以在本地业务库中建立一张安装点空间表,将空间数据储存在自己的业务库中,这样空间查询等功能就不需要依赖PGIS提供的接口了,空间字段是Oracle提供的标准格式,更便于以后功能的扩展。

  • 实现

    平台monitor_point表已经有经纬度字段来,添加安装点时将经纬度数据填进去即可。具体代码略。

    本地安装点空间表结构如下:

    MONITOR_POINT_GEOMETRY

名称

代码

数据类型

注释

默认值

安装点编号

POINTCODE

NVARCHAR2(16)

   

空间字段

GEOMETRY

MDSYS.SDO_GEOMETRY

   

数据缓存

  • 思路

    平台现在是实时查询数据库获得安装点信息,并展示在地图上。可以考虑将安装点信息缓存起来,调用的时候直接从缓存里读取数据,可以省掉查询数据库的操作。

  • 分析

    数据缓存可以在浏览器客户端缓存和服务器端缓存2种方式。

    浏览器端缓存速度最快,但需要耗费浏览器端的内存,一条安装点的所有信息约占900个字节,经过实际测试,在客户端内存中缓存2179条数据,约占1.8M内存,并不影响浏览器响应速度。但当缓存约8000个点左右时会内存溢出。

    因此可以考虑采用浏览器端和服务器端双重缓存的方案。只将基础数据(坐标点、安装点编号、名称、类型)缓存在浏览器客户端,将明细信息缓存到服务器端。

  • 实现

    首先查询数据库将安装点基础信息缓存到浏览器客户端,存在js数组里。当显示某类安装点时循环该数组将符合条件的安装点显示出来。

    在服务器端查询数据库将明细信息缓存到一个cache文件中。该文件定时刷新以保证数据的及时性。当对安装点表进行操作时也实时将数据更新到cache文件中去。

    点位聚合

    参考点位聚合方案

    专题图叠加 ※

  • 思路

    以上优化办法主要针对平台现有的地图显示需求,如果用户有大屏幕显示等特殊需求需要同时显示上千个点位,可以考虑专题图叠加功能。

  • 分析

    PGIS提供专题图叠加的接口,可以通过WMS协议调用第三方地图图片(如GeoServer)叠加到地图上。利用GeoServer等地图服务预先将安装点图层生成出来,利用PGIS的专题图叠加接口调用该图层。

  • 实现
  1. 首先利用GeoServer生成一个安装点图层。
  2. 利用PGIS的接口调用该图层进行展示:

var legendfunc=new LegendFunc();

legendfunc.format=geoserverURL+"/wms?service=WMS&version=1.1.0&request=

GetMap&layers="+layers+"&bbox=EZBOX&width=EZWIDTH

&height=EZHEIGHT&srs=EPSG:4326&format=image/png

&TRANSPARENT=true&cql_filter="+escape(cql_filter)+"

&styles="+styles;

legendfunc.open(_MapApp);

上一篇:mysql insert插入时实现如果数据表中主键重复则更新,没有重复则插入的四种方法


下一篇:EF如何操作内存中的数据和加载外键数据:延迟加载、贪婪加载、显示加载