概述
需求大致是這樣的:有一個全國的土地利用數(shù)據(jù),要根據(jù)用戶權(quán)限實現(xiàn)從省級、市級和區(qū)級不同級別的區(qū)劃的不同展示,問題是數(shù)據(jù)沒有關(guān)聯(lián)區(qū)劃數(shù)據(jù)。針對上述這個問題,我探索出了一種將區(qū)劃數(shù)據(jù)發(fā)布成一個純色(全白樣式)服務(wù),對需要展示的區(qū)域進(jìn)行篩選后和原服務(wù)進(jìn)行疊加,在通過代碼將白色轉(zhuǎn)成透明色的實現(xiàn)方式。
實現(xiàn)思路
大致實現(xiàn)邏輯如下邏輯圖。

image.png
實現(xiàn)效果

合并后未摳圖

摳圖后

疊加到頁面后
實現(xiàn)代碼
前端使用openlayers調(diào)用,代碼如下:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="stylesheet"
type="text/css">
<style>
html,
body,
.map {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.15.1/build/ol.js"></script>
<title>OpenLayers example</title>
</head>
<body>
<div id="map" class="map"></div>
<script type="text/javascript">
// 創(chuàng)建地圖
var map = new ol.Map({
target: 'map',
layers: [
// 底圖
new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'https://webst0{1-4}.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}'
})
}),
// 使用ImageWMS源調(diào)用后端合并的WMS服務(wù)
new ol.layer.Image({
source: new ol.source.ImageWMS({
url: 'http://localhost:8888/wms-merged',
params: {
'SERVICE': 'WMS',
'VERSION': '1.1.1',
'REQUEST': 'GetMap',
'FORMAT': 'image/png',
'TRANSPARENT': 'true'
},
serverType: 'geoserver',
crossOrigin: 'anonymous'
})
})
],
view: new ol.View({
center: ol.proj.fromLonLat([104.06, 30.67]),
zoom: 5
})
});
</script>
</body>
</html>
后端服務(wù)使用node,實現(xiàn)代碼如下:
const express = require('express');
const axios = require('axios');
const { createCanvas, loadImage } = require('canvas');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 8888;
// 啟用CORS
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
next();
});
// WMS合并服務(wù)
app.get('/wms-merged', async (_, res) => {
try {
const {
SERVICE = 'WMS',
VERSION = '1.1.1',
REQUEST = 'GetMap',
FORMAT = 'image/png',
TRANSPARENT = 'true',
WIDTH,
HEIGHT,
SRS = 'EPSG:3857',
BBOX
} = req.query;
if (!WIDTH || !HEIGHT || !BBOX) {
return res.status(400).send('缺少必要的參數(shù): WIDTH, HEIGHT, BBOX');
}
const width = parseInt(WIDTH);
const height = parseInt(HEIGHT);
// 創(chuàng)建Canvas
const canvas = createCanvas(width, height);
const ctx = canvas.getContext('2d');
// 基礎(chǔ)WMS URL
const wmsBaseUrl = 'http://localhost:8086/geoserver/lzugis/wms';
// 圖層配置
const layers = [
{
name: 'lzugis:base_county',
params: {
SERVICE,
VERSION,
REQUEST,
FORMAT,
TRANSPARENT
}
},
{
name: 'lzugis:base_city',
params: {
SERVICE,
VERSION,
REQUEST,
FORMAT,
TRANSPARENT,
CQL_FILTER: "province <> '甘肅省'" // 這個參數(shù)可以前端傳過來
}
}
];
// 構(gòu)建每個圖層的URL
const buildLayerUrl = (layerConfig) => {
const params = new URLSearchParams();
// 添加基礎(chǔ)參數(shù)
Object.keys(layerConfig.params).forEach(key => {
params.append(key, layerConfig.params[key]);
});
// 添加圖層特定參數(shù)
params.append('LAYERS', layerConfig.name);
params.append('WIDTH', width.toString());
params.append('HEIGHT', height.toString());
params.append('SRS', SRS);
params.append('BBOX', BBOX);
return `${wmsBaseUrl}?${params.toString()}`;
};
// 加載并繪制兩個圖層
const imageUrls = layers.map(buildLayerUrl);
const images = await Promise.all(imageUrls.map(url =>
axios.get(url, { responseType: 'arraybuffer' })
.then(response => loadImage(Buffer.from(response.data)))
));
// 繪制第一個圖層
ctx.drawImage(images[0], 0, 0, width, height);
// 繪制第二個圖層
ctx.drawImage(images[1], 0, 0, width, height);
// 處理白色透明
const imageData = ctx.getImageData(0, 0, width, height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
// 檢查是否為白色(RGB值都接近255)
if (data[i] > 240 && data[i + 1] > 240 && data[i + 2] > 240) {
// 設(shè)置為透明
data[i + 3] = 0;
}
}
ctx.putImageData(imageData, 0, 0);
// 設(shè)置響應(yīng)頭并發(fā)送圖片
res.setHeader('Content-Type', 'image/png');
canvas.pngStream().pipe(res);
} catch (error) {
console.error('WMS合并錯誤:', error);
res.status(500).send('服務(wù)器內(nèi)部錯誤');
}
});
// 靜態(tài)文件服務(wù)
app.use(express.static(path.join(__dirname)));
// 啟動服務(wù)器
app.listen(PORT, () => {
console.log(`服務(wù)器運行在 http://localhost:${PORT}`);
});