一、思路
为切片图层添加水印方法目前知道的有两种:
一种是类似超图切片服务的方式,从服务返回来的切片本身就带上了水印,如下图。但是这种方法对于普通开发来说不太现实。
另一种是等切片传回前端,在前端对切片进行二次处理,本文主要讲述如何对传回的切片进行处理。
二、流程
首先准备一张用于做水印的透明图片,如下图,然后将图片转换为base码,方便在代码中调用。
核心方法
通过监听切片的加载回调方法
-
获取加载完的切片,然后根据切片的尺寸,用canvas创建一个画布;
-
将切片的src对应的图片绘制到画布上,这样就获得了一个和src图片内容一样的画布;
-
将预先准备好的水印图片通过平铺的方法叠加到画布上,然后将画布输出为图片,这样就可以获取到叠加水印的图片;
- 最后用处理完的输出的图片替换掉原来的切片图片,就可以得到添加水印的效果;
var img = new Image();
img.src = "data:image/png;your img"
var source2 = new ol.source.ImageArcGISRest({
crossOrigin: "anonymous", // 需要开启才能对切片进行操作
url: "your url",
})
source2.on("imageloadend", function (evt) {
// var image = evt.tile.getImage();
var image = evt.image.getImage(); // 获取切片
canvas = document.createElement('CANVAS'); // 创建画布
canvas.width = image.width;
canvas.height = image.height;
canvas.style.width = image.width + 'px';
canvas.style.height = image.height + 'px'; // 根据切片大小设置画布尺寸
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width, image.height); // 将切片图片绘制到画布上
ctx.rect(0, 0, image.width, image.height);
ctx.fillStyle = ctx.createPattern(img, "repeat"); // 平铺预先准备好的水印
ctx.fill();
image.src = canvas.toDataURL("image/png"); // 将添加完水印的图片绑定到切片上
});
图层加载方法
以arcgis服务为例,可以是以Tile方法进行tile切片加载,也可以用Image直接加载图片
上面的核心代码示例中是用Image的方法进行处理,用image方法进行加载,后台服务会直接返回与当前界面尺寸接近的图片
直接对整张图片进行操作也可以达到添加水印的效果,但是这样会出现一个问题,每次缓存中的图片不足以提供view的视界,就会对服务进行请求,而请求回来的又是一张接近的图片,再对水印进行操作的话,水印就会又从新的图片的左上角进行计算平铺,这样就会导致水印的位置永远都是相对于屏幕不变,而不是跟随切片进行移动。
替换成空白图层的话这种效果就会很明显,即只要获取了新的切片,水印就会刷新回最初的位置,和屏幕的相对位置一致。也就是说,只要界面刷新了图片,图层水印就会回到下图所示的位置。
上面这种效果显然不是水印图层想要的效果,所有推荐使用 tile 切片的方式进行加载
var source2 = new ol.source.TileArcGISRest({
crossOrigin: "anonymous",
url: "your url",
})
source2.on("tileloadend", function (evt) {
// source2.on("imageloadend", function (evt) {
var image = evt.tile.getImage(); // 获取切片
// var image = evt.image.getImage(); // 获取切片
canvas = document.createElement('CANVAS'); // 创建画布
canvas.width = image.width;
canvas.height = image.height;
canvas.style.width = image.width + 'px';
canvas.style.height = image.height + 'px'; // 根据切片大小设置画布尺寸
var ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, image.width, image.height); // 将切片图片绘制到画布上
ctx.rect(0, 0, image.width, image.height);
ctx.fillStyle = ctx.createPattern(img, "repeat"); // 平铺预先准备好的水印
ctx.fill();
image.src = canvas.toDataURL("image/png"); // 将添加完水印的图片绑定到切片上
});
通过tile方法加载得到的切片是大小一致的切片,如果视界发升变动,需要刷新底图,只需要对视界变动位置的切片进行请求,再对新的切片进行操作就可以了。
并且水印操作是对每个切片进行操作的,所以水印的相对位置始终绑定切片,因此不会出现水印回刷的情况。
投影影响
上面的例子是建立在view的投影与layer的投影一致的情况下的,如果view的投影与layer的投影不一致,在回调事件中对图片进行处理的话,会导致图片产生割裂效果
此处推测应该是切片加载完还要进行进一步处理,所以导致图片缺失。可以通过发布一个新的与view的投影一致的空图层来跳过这个问题,对空图层进行监听,设置空图层的显隐效果,同时可以实现多个图层共用一个水印图层的效果,避免对每个图层进行操作,消耗过多的性能。