修改Arcgis for js源码使WMSLayer.js支持cql_filter

背景

由于项目的地图服务要迁移到国产操作系统上,以前用Arcgis发布的地图服务都要改用geoserver重新发布。由此产生了一系列的问题,这里主要记录一下arcgis for js加载WMS服务时需要对多个子图层进行过滤的解决方法。
arcgis for js 的版本是 4.20

单一的WMS服务

如果你的WMS服务只有一个,没有子图层,那你可以直接使用WMSLayer中customLayerParameters的属性,在其中定义“cql_filter”来实现过滤效果,具体用法见arcgis官网

基本原理

事实上在项目中单一的地图服务很少见,不过我们还是要先从单一的WMS服务中看看带过滤的请求发出来时是什么样的。我们可以先通过geoserver中图层预览功能设置过滤条件,查看具体的请求参数
在这里插入图片描述

在这里插入图片描述
在这个请求里与过滤有关的两个参数分别是LAYERSCQL_FILTER,通过LAYERS指定加载图层,通过CQL_FILTER指定过滤条件,最终实现了对单一图层的过滤。
而当我们要加载多个子图层是请求就会变成下面这样
在这里插入图片描述
不设置过滤条件的话服务也是可以正常加载的
在这里插入图片描述

这个时候如果我们添加过滤条件
在这里插入图片描述
会看到geoserver报错 Layers and filters are mismatched, you need to provide one filter for each layer
在这里插入图片描述
通过查看geoserver的官方文档可以看到,在多layer时要给每个layer分别设置cql_fliter并以;隔开。
那如果某一部分图层不需要过滤呢?那也得设置,就设置成1=1吧,重点是过滤条件的顺序要和LAYERS中的顺序相同,不要搞乱。
我们对三个子图层分别设置了过滤条件,如下
在这里插入图片描述
在这里插入图片描述

ok,服务可以加载出来并对指定图层完成了过滤。
基本原理搞清了,下面就搞起来,让arcgis的WMSLayer支持cql_filter。

WMSSubLayer.js

在开始之前,让我们先看看arcgis是怎么如何加载WMS服务的,这是官网的代码

// Typical usage
let layer = new WMSLayer({
  url: // url to the service,
  sublayers: [{
    name: // name of the sublayer,
    legendUrl: // url to the legend
  }]
});

这里的sublayers就是我们要加载的子图层,它对应的类是WMSSublayer,遗憾的是在WMSSublayer的文档中并没有找到类似于customParameterscustomLayerParameters的属性,不然就可以直接拿来用了。
既然没有那就自己动手。多图层过滤,我们又要保证过滤条件的顺序与请求中LAYERS顺序相同,以我的直觉还是把过滤条件放在子图层中设置更好,让我们最终能这样用

// Typical usage
let layer = new WMSLayer({
  url: // url to the service,
  sublayers: [{
    name: // name of the sublayer,
    cqlFilter: //过滤条件1
    legendUrl: // url to the legend
  }{
    name: // name of the sublayer,
    cqlFilter: //过滤条件2
    legendUrl: // url to the legend
  }{
    name: // name of the sublayer,
    legendUrl: // url to the legend
  }]
});

我们首先要修改WMSSubLayer.js使它支持我们新增的属性cqlFilter
让我们找到WMSSubLayer.js的源码,格式化一下,并增加下面这些代码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
ok,搞定。WMSSubLayer的对象已经拥有cqlFilter这个属性啦。

WMSLayer.js

接下来,我们就要修改WMSLayer的代码,请求毕竟还是从他这发出来的。
还是一样,找到WMSLayer.js的源码,格式化一下方便修改。
debug一下可以看到,请求是从fetchImage这个方法发出来的
在这里插入图片描述
而这个方法里,看名字都能看出来_mixCustomParameters就是我们要修改的最终目标。
废话不多说,直接上代码,首先要先增加一个mixSubLayersCqlFilter方法,用来整理所有子图层的cqlFilter参数。

function mixSubLayersCqlFilter(sublayers) {
    if (!sublayers || !sublayers.length) return null;
    const m = {};
    for (let i = 0; i < sublayers.length; i++) {
        let l = sublayers[i];
        if (l.cqlFilter)
            m[l.name] = l.cqlFilter;
    }
    return m;
}

接着就要在请求中增加cql_filter来达到我们多图层过滤的目的,将_mixCustomParameters方法改成这样

h._mixCustomParameters = function (b) {
	let mp = mixSubLayersCqlFilter(this.allSublayers.items);
	if (!this.customLayerParameters && !this.customParameters && !mp) return b;
	let ls = b.layers.split(",");
	let cqlFilters = [];
	for (let i = 0; i < ls.length; i++) {
	    if (mp[ls[i]]) {
	        cqlFilters.push(mp[ls[i]]);
	    } else {
	        cqlFilters.push("1=1");
	    }
	}
	const a = {
	    ...this.customParameters,
	    ...this.customLayerParameters
	};
	a['cql_filter'] = cqlFilters.join(";");
	for (const d in a) b[d.toLowerCase()] = a[d];
	return b
};

最终测试

将修改后的文件重新压缩一下,替换原文件。(记得备份,出问题了不负责)
按我们的过滤需求创建一个新图层

let layer = new WMSLayer({
  url:  basemap_url + "/sand/wms",
  sublayers: [{
    name: "mstRv",
    cqlFilter: "RV_CD='FFD4EA00000L'"
  }{
    name: "mstRvLabel"
  }{
    name: "countyGeo",
    maxScale: 288895.2771443219,
    cqlFilter: "code like '4113%'"
  }]
});

跑一下代码
在这里插入图片描述
没有问题,地图服务按要求加载出来了,再看看请求
在这里插入图片描述
也是没啥问题的

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值