基于SuperMap REST-地图服务的B/S端简易图层样式编辑器实现
一、项目概述
在GIS(地理信息系统)应用开发中,图层样式的动态修改是一个常见需求。本文介绍一个基于 SuperMap iClient Leaflet 开发的简易图层样式编辑器,支持多地图管理和图层样式的实时调整。
基于SuperMap REST-地图服务的前端图层样式编辑器
功能特点
- 多地图管理:支持多个REST地图服务的加载和管理
- 图层可见性控制:通过复选框切换图层显示/隐藏
- 图层顺序调整:拖拽排序改变图层叠加顺序
- 样式实时修改:支持修改图层填充颜色和透明度
- REST API交互:通过SuperMap REST API实现样式持久化
二、技术栈
| 技术 | 版本 | 说明 |
|---|---|---|
| SuperMap iClient Leaflet | 最新 | GIS地图组件库 |
| Leaflet | 1.9.4 | 开源地图库 |
| HTML5 | - | 页面结构 |
| CSS3 | - | 样式设计 |
| JavaScript | ES6+ | 业务逻辑 |
三、核心功能实现
3.1 项目结构
├── 多地图管理与图层样式管理.html # 主页面
└── 依赖资源(CDN加载)
├── leaflet.js
├── iclient-leaflet-es6.min.js
└── leaflet.css
3.2 地图初始化
javascript
var map;
var mapLayers = [];
var layerStyles = {};
var allLayersData = {};
var mapConfigs = [
{ id: 'base', name: '成都市底图', url: 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/成都市底图', visible: true },
{ id: 'main', name: '成都市主城区', url: 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/成都市主城区', visible: true },
{ id: 'shop', name: '成都市商店', url: 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/成都市商店', visible: true }
];
function initMap() {
new L.supermap.MapService(mapConfigs[0].url).getMapInfo().then((res) => {
map = L.map('map', {
crs: L.CRS.EPSG4326,
center: [30.76, 103.94],
maxZoom: 18,
zoom: 12,
wrapX: false
});
mapConfigs.forEach((config) => {
addMapLayer(config);
});
renderMapList();
loadLayerStyles();
});
}
关键技术点:
- 使用
L.supermap.MapService获取地图信息,确保坐标系正确 - 通过
L.supermap.TiledMapLayer创建瓦片图层 - 批量加载多个地图服务
3.3 图层管理面板
javascript
function renderMapList() {
var list = document.getElementById('mapList');
list.innerHTML = '';
mapLayers.forEach((item, index) => {
var li = document.createElement('li');
li.className = 'map-item';
li.setAttribute('data-index', index);
li.setAttribute('draggable', 'true');
li.innerHTML = `
<input type="checkbox" ${item.config.visible ? 'checked' : ''} data-index="${index}">
<span class="map-name">${item.config.name}</span>
<span class="drag-handle">⋮⋮</span>
`;
li.addEventListener('dragstart', handleDragStart);
li.addEventListener('dragover', handleDragOver);
li.addEventListener('drop', handleDrop);
li.addEventListener('dragend', handleDragEnd);
var checkbox = li.querySelector('input[type="checkbox"]');
checkbox.addEventListener('change', function(e) {
e.stopPropagation();
toggleLayerVisibility(index);
});
list.appendChild(li);
});
}
核心功能:
- 动态渲染图层列表
- 支持拖拽排序
- 复选框控制图层可见性
3.4 拖拽排序实现
javascript
var draggedIndex = -1;
function handleDrop(e) {
e.preventDefault();
var dropIndex = parseInt(e.target.getAttribute('data-index'));
if (draggedIndex !== -1 && draggedIndex !== dropIndex) {
var draggedItem = mapLayers[draggedIndex];
mapLayers.splice(draggedIndex, 1);
mapLayers.splice(dropIndex, 0, draggedItem);
reorderLayers();
renderMapList();
}
document.querySelectorAll('.map-item').forEach(item => item.classList.remove('drag-over'));
}
function reorderLayers() {
mapLayers.forEach(item => {
if (item.config.visible) {
map.removeLayer(item.layer);
}
});
mapLayers.forEach(item => {
if (item.config.visible) {
item.layer.addTo(map);
}
});
}
实现原理:
- 使用HTML5拖拽API实现列表排序
- 通过移除再添加图层实现顺序调整
3.5 图层样式读取
javascript
function loadLayerStyles() {
var mapSelect = document.getElementById('mapSelect');
mapSelect.innerHTML = '<option value="">请选择地图</option>';
mapConfigs.forEach((config) => {
var option = document.createElement('option');
option.value = config.name;
option.textContent = config.name;
mapSelect.appendChild(option);
});
mapConfigs.forEach((config) => {
var url = config.url + '/layers.json';
fetch(url)
.then(response => response.json())
.then(data => {
allLayersData[config.name] = data;
})
.catch(error => {
console.error('加载图层样式失败:', error);
});
});
}
技术要点:
- 调用SuperMap REST API获取图层配置
- 缓存图层数据到
allLayersData对象
3.6 颜色格式转换
javascript
function rgbaToHex(rgba) {
var r = Math.round(rgba.red).toString(16).padStart(2, '0');
var g = Math.round(rgba.green).toString(16).padStart(2, '0');
var b = Math.round(rgba.blue).toString(16).padStart(2, '0');
return '#' + r + g + b;
}
function hexToRgba(hex, alpha) {
var r = parseInt(hex.slice(1, 3), 16);
var g = parseInt(hex.slice(3, 5), 16);
var b = parseInt(hex.slice(5, 7), 16);
return { red: r, green: g, blue: b, alpha: Math.round(alpha * 255) };
}
转换逻辑:
- SuperMap使用RGBA对象格式(
{red, green, blue, alpha}) - HTML颜色选择器使用十六进制格式(
#RRGGBB) - 需要双向转换适配不同格式
3.7 样式更新API
javascript
function updateLayerStyle(mapName, layerName, color) {
var url = 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/' + encodeURIComponent(mapName) + '/layers.json';
var updatedLayersData = JSON.parse(JSON.stringify(allLayersData[mapName]));
updateLayerColorRecursively(updatedLayersData, layerName, color);
fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
body: JSON.stringify(updatedLayersData)
})
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error('更新失败');
})
.then(data => {
allLayersData[mapName] = updatedLayersData;
showStatus('样式更新成功!页面即将刷新...', 'success');
setTimeout(function() {
location.reload();
}, 1000);
})
.catch(error => {
showStatus('更新失败: ' + error.message, 'error');
console.error('更新图层样式失败:', error);
});
}
REST API调用流程:
- 构造图层配置更新URL
- 深拷贝图层数据避免污染原数据
- 递归更新目标图层颜色
- 使用PUT请求提交更新
- 成功后刷新页面加载新样式
核心实现逻辑:
- 方法:PUT
- 接口:iServer REST地图服务的layers接口
- 接口参考文档 :https://support.supermap.com/DataWarehouse/WebDocHelp/iServer/mergedProjects/SuperMapiServerRESTAPI/root/maps/map/layers/layers.htm
3.8 递归更新图层颜色
javascript
function updateLayerColorRecursively(layers, layerName, color) {
if (Array.isArray(layers)) {
layers.forEach(layer => {
updateLayerColorRecursively(layer, layerName, color);
});
} else if (typeof layers === 'object' && layers !== null) {
if (layers.name === layerName && layers.style) {
layers.style.fillForeColor = color;
}
if (layers.subLayers && layers.subLayers.layers) {
updateLayerColorRecursively(layers.subLayers.layers, layerName, color);
}
}
}
递归逻辑:
- 支持图层组嵌套结构
- 匹配图层名称更新样式
- 递归处理子图层
四、界面设计
4.1 布局结构
html
<div id="controlPanel">
<div class="tab-container">
<div class="tab active" data-tab="mapManager">地图管理</div>
<div class="tab" data-tab="styleManager">样式管理</div>
</div>
<div id="mapManager" class="tab-content active">
<!-- 图层列表 -->
</div>
<div id="styleManager" class="tab-content">
<!-- 样式编辑控件 -->
</div>
</div>
4.2 样式设计
css
#controlPanel {
position: absolute;
top: 20px;
right: 20px;
width: 320px;
background: rgba(255, 255, 255, 0.95);
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.tab {
flex: 1;
padding: 10px;
text-align: center;
font-size: 13px;
font-weight: bold;
color: #666;
cursor: pointer;
border-bottom: 2px solid transparent;
}
.tab.active {
color: #1E9FFF;
border-bottom-color: #1E9FFF;
}
设计特点:
- 半透明背景增强地图可见性
- 卡片式设计配合阴影效果
- 蓝色主题(#1E9FFF)统一风格
- 响应式交互反馈
五、使用说明
5.1 环境要求
- SuperMap iServer:部署地图服务
- 服务地址 :
http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/ - CORS配置:确保服务允许跨域请求
5.2 使用前提
在使用本工具前,需确保iServer服务端配置正确:
-
关闭缓存功能:在iServer服务管理界面中,关闭对应地图服务的"缓存"功能,确保更新的样式可以及时刷新生效
-
开启可编辑能力:在iServer服务管理界面中,开启对应地图服务的"可编辑"能力,确保PUT请求可以正常响应
5.3 操作步骤
-
地图管理
- 勾选/取消勾选控制图层显示
- 拖拽调整图层叠加顺序
-
样式管理
- 选择目标地图
- 选择目标图层
- 调整填充颜色(颜色选择器)
- 调整透明度(滑动条)
- 点击"更新样式"按钮保存
六、注意事项
- 跨域问题:需在iServer中配置CORS或使用代理
- 服务权限:确保REST服务有写入权限
- 图层类型:当前仅支持矢量图层样式修改
- 样式属性 :当前仅修改
fillForeColor属性,可扩展支持其他样式属性
七、扩展方向
- 更多样式属性:支持边框颜色、线条宽度、符号样式等
- 批量操作:支持多选图层批量修改样式
- 样式模板:预设样式方案快速应用
- 历史记录:支持样式修改回滚
- 图层过滤:按图层类型/名称筛选
八、完整代码
完整代码
html
<!--********************************************************************
* Copyright© 2000 - 2025 SuperMap Software Co.Ltd. All rights reserved.
*********************************************************************-->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>多地图管理与图层样式管理</title>
<style>
body { margin: 0; overflow: hidden; background: #fff; width: 100%; height: 100%; position: absolute; top: 0; font-family: 'Microsoft YaHei', sans-serif; }
#map { margin: 0 auto; width: 100%; height: 100%; }
#controlPanel { position: absolute; top: 20px; right: 20px; width: 320px; background: rgba(255, 255, 255, 0.95); border-radius: 10px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); padding: 15px; z-index: 1000; }
.panel-header { font-weight: bold; font-size: 14px; color: #333; margin-bottom: 12px; padding-bottom: 8px; border-bottom: 1px solid #eee; display: flex; align-items: center; gap: 8px; }
.panel-header::before { content: ''; width: 4px; height: 16px; background: #1E9FFF; border-radius: 2px; }
.map-list { list-style: none; padding: 0; margin: 0; max-height: 150px; overflow-y: auto; }
.map-item { display: flex; align-items: center; padding: 10px; margin-bottom: 6px; background: #f8f9fa; border-radius: 6px; cursor: move; transition: all 0.2s; }
.map-item:hover { background: #e9ecef; }
.map-item.dragging { opacity: 0.5; }
.map-item.drag-over { border: 2px dashed #1E9FFF; }
.map-item input[type="checkbox"] { margin-right: 10px; width: 16px; height: 16px; cursor: pointer; }
.map-item .map-name { flex: 1; font-size: 13px; color: #333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.map-item .drag-handle { width: 20px; height: 20px; display: flex; align-items: center; justify-content: center; color: #999; cursor: grab; }
.map-item .drag-handle:active { cursor: grabbing; }
.style-panel { margin-top: 15px; }
.color-picker-container { display: flex; align-items: center; gap: 10px; margin-bottom: 15px; }
.color-label { font-size: 13px; color: #666; white-space: nowrap; }
#colorPicker { width: 50px; height: 40px; border: none; border-radius: 6px; cursor: pointer; padding: 0; }
.opacity-container { margin-bottom: 15px; }
.opacity-label { font-size: 13px; color: #666; margin-bottom: 8px; display: block; }
#opacitySlider { width: 100%; height: 6px; -webkit-appearance: none; appearance: none; background: #ddd; border-radius: 3px; outline: none; }
#opacitySlider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 18px; height: 18px; background: #1E9FFF; border-radius: 50%; cursor: pointer; transition: transform 0.2s; }
#opacitySlider::-webkit-slider-thumb:hover { transform: scale(1.2); }
#opacityValue { font-size: 13px; color: #1E9FFF; font-weight: bold; }
.layer-select-container { margin-bottom: 15px; }
#layerSelect { width: 100%; padding: 8px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 13px; background: white; cursor: pointer; }
#updateBtn { width: 100%; padding: 10px; background: linear-gradient(135deg, #1E9FFF, #007BFF); color: white; border: none; border-radius: 6px; font-size: 14px; font-weight: bold; cursor: pointer; transition: all 0.3s; }
#updateBtn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(30, 159, 255, 0.4); }
#updateBtn:active { transform: translateY(0); }
.status-message { margin-top: 10px; padding: 10px; border-radius: 6px; font-size: 12px; display: none; }
.status-success { background: #d4edda; color: #155724; }
.status-error { background: #f8d7da; color: #721c24; }
.tab-container { display: flex; margin-bottom: 15px; border-bottom: 1px solid #eee; }
.tab { flex: 1; padding: 10px; text-align: center; font-size: 13px; font-weight: bold; color: #666; cursor: pointer; transition: all 0.2s; border-bottom: 2px solid transparent; }
.tab.active { color: #1E9FFF; border-bottom-color: #1E9FFF; }
.tab-content { display: none; }
.tab-content.active { display: block; }
</style>
</head>
<body>
<div id="map" style="margin: 0 auto; width: 100%; height: 100%"></div>
<div id="controlPanel">
<div class="tab-container">
<div class="tab active" data-tab="mapManager">地图管理</div>
<div class="tab" data-tab="styleManager">样式管理</div>
</div>
<div id="mapManager" class="tab-content active">
<div class="panel-header">图层列表</div>
<ul id="mapList" class="map-list"></ul>
</div>
<div id="styleManager" class="tab-content">
<div class="panel-header">图层样式</div>
<div class="layer-select-container">
<select id="mapSelect">
<option value="">请选择地图</option>
</select>
</div>
<div class="layer-select-container">
<select id="layerSelect">
<option value="">请选择图层</option>
</select>
</div>
<div class="color-picker-container">
<span class="color-label">填充颜色:</span>
<input type="color" id="colorPicker" value="#D0FFF0">
</div>
<div class="opacity-container">
<div class="opacity-label">透明度:<span id="opacityValue">100%</span></div>
<input type="range" id="opacitySlider" min="0" max="100" value="100">
</div>
<button id="updateBtn">更新样式</button>
<div id="statusMessage" class="status-message"></div>
</div>
</div>
<script type="text/javascript" src="https://iclient.supermap.io/web/libs/leaflet/1.9.4/leaflet.js"></script>
<script type="text/javascript" src="https://iclient.supermap.io/dist/leaflet/iclient-leaflet-es6.min.js"></script>
<link rel="stylesheet" href="https://iclient.supermap.io/web/libs/leaflet/1.9.4/leaflet.css" />
<script type="text/javascript">
var map;
var mapLayers = [];
var layerStyles = {};
var allLayersData = {};
var mapConfigs = [
{ id: 'base', name: '成都市底图', url: 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/成都市底图', visible: true },
{ id: 'main', name: '成都市主城区', url: 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/成都市主城区', visible: true },
{ id: 'shop', name: '成都市商店', url: 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/成都市商店', visible: true }
];
function initMap() {
new L.supermap.MapService(mapConfigs[0].url).getMapInfo().then((res) => {
map = L.map('map', {
crs: L.CRS.EPSG4326,
center: [30.76, 103.94],
maxZoom: 18,
zoom: 12,
wrapX: false
});
mapConfigs.forEach((config) => {
addMapLayer(config);
});
renderMapList();
loadLayerStyles();
});
}
function addMapLayer(config) {
var layer = new L.supermap.TiledMapLayer(config.url);
if (config.visible) {
layer.addTo(map);
}
mapLayers.push({ config: config, layer: layer });
}
function renderMapList() {
var list = document.getElementById('mapList');
list.innerHTML = '';
mapLayers.forEach((item, index) => {
var li = document.createElement('li');
li.className = 'map-item';
li.setAttribute('data-index', index);
li.setAttribute('draggable', 'true');
li.innerHTML = `
<input type="checkbox" ${item.config.visible ? 'checked' : ''} data-index="${index}">
<span class="map-name">${item.config.name}</span>
<span class="drag-handle">⋮⋮</span>
`;
li.addEventListener('dragstart', handleDragStart);
li.addEventListener('dragover', handleDragOver);
li.addEventListener('drop', handleDrop);
li.addEventListener('dragend', handleDragEnd);
var checkbox = li.querySelector('input[type="checkbox"]');
checkbox.addEventListener('change', function(e) {
e.stopPropagation();
toggleLayerVisibility(index);
});
list.appendChild(li);
});
}
var draggedIndex = -1;
function handleDragStart(e) {
draggedIndex = parseInt(e.target.getAttribute('data-index'));
e.target.classList.add('dragging');
e.dataTransfer.effectAllowed = 'move';
}
function handleDragOver(e) {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
var items = document.querySelectorAll('.map-item');
items.forEach(item => item.classList.remove('drag-over'));
if (e.target.classList.contains('map-item')) {
e.target.classList.add('drag-over');
}
}
function handleDrop(e) {
e.preventDefault();
var dropIndex = parseInt(e.target.getAttribute('data-index'));
if (draggedIndex !== -1 && draggedIndex !== dropIndex) {
var draggedItem = mapLayers[draggedIndex];
mapLayers.splice(draggedIndex, 1);
mapLayers.splice(dropIndex, 0, draggedItem);
reorderLayers();
renderMapList();
}
document.querySelectorAll('.map-item').forEach(item => item.classList.remove('drag-over'));
}
function handleDragEnd() {
draggedIndex = -1;
document.querySelectorAll('.map-item').forEach(item => {
item.classList.remove('dragging');
item.classList.remove('drag-over');
});
}
function toggleLayerVisibility(index) {
var item = mapLayers[index];
item.config.visible = !item.config.visible;
if (item.config.visible) {
item.layer.addTo(map);
} else {
map.removeLayer(item.layer);
}
}
function reorderLayers() {
mapLayers.forEach(item => {
if (item.config.visible) {
map.removeLayer(item.layer);
}
});
mapLayers.forEach(item => {
if (item.config.visible) {
item.layer.addTo(map);
}
});
}
function loadLayerStyles() {
var mapSelect = document.getElementById('mapSelect');
mapSelect.innerHTML = '<option value="">请选择地图</option>';
mapConfigs.forEach((config) => {
var option = document.createElement('option');
option.value = config.name;
option.textContent = config.name;
mapSelect.appendChild(option);
});
mapConfigs.forEach((config) => {
var url = config.url + '/layers.json';
fetch(url)
.then(response => response.json())
.then(data => {
allLayersData[config.name] = data;
})
.catch(error => {
console.error('加载图层样式失败:', error);
});
});
}
function parseLayerStyles(mapName) {
var select = document.getElementById('layerSelect');
select.innerHTML = '<option value="">请选择图层</option>';
if (!mapName || !allLayersData[mapName]) {
return;
}
var data = allLayersData[mapName];
layerStyles = {};
function extractLayers(layers) {
if (layers.layers) {
layers.layers.forEach(layer => {
if (layer.name && layer.style) {
layerStyles[layer.name] = layer;
var option = document.createElement('option');
option.value = layer.name;
option.textContent = layer.caption || layer.name;
select.appendChild(option);
if (layer.style.fillForeColor) {
var color = rgbaToHex(layer.style.fillForeColor);
option.style.color = color;
}
}
if (layer.subLayers && layer.subLayers.layers) {
extractLayers(layer.subLayers);
}
});
}
}
extractLayers({ layers: data });
}
function rgbaToHex(rgba) {
var r = Math.round(rgba.red).toString(16).padStart(2, '0');
var g = Math.round(rgba.green).toString(16).padStart(2, '0');
var b = Math.round(rgba.blue).toString(16).padStart(2, '0');
return '#' + r + g + b;
}
function hexToRgba(hex, alpha) {
var r = parseInt(hex.slice(1, 3), 16);
var g = parseInt(hex.slice(3, 5), 16);
var b = parseInt(hex.slice(5, 7), 16);
return { red: r, green: g, blue: b, alpha: Math.round(alpha * 255) };
}
document.getElementById('mapSelect').addEventListener('change', function(e) {
var mapName = e.target.value;
parseLayerStyles(mapName);
});
document.getElementById('layerSelect').addEventListener('change', function(e) {
var layerName = e.target.value;
if (layerName && layerStyles[layerName]) {
var style = layerStyles[layerName];
if (style.fillForeColor) {
var color = rgbaToHex(style.fillForeColor);
document.getElementById('colorPicker').value = color;
var opacity = (style.fillForeColor.alpha / 255 * 100).toFixed(0);
document.getElementById('opacitySlider').value = opacity;
document.getElementById('opacityValue').textContent = opacity + '%';
}
}
});
document.getElementById('opacitySlider').addEventListener('input', function(e) {
document.getElementById('opacityValue').textContent = e.target.value + '%';
});
document.getElementById('updateBtn').addEventListener('click', function() {
var mapName = document.getElementById('mapSelect').value;
var layerName = document.getElementById('layerSelect').value;
var color = document.getElementById('colorPicker').value;
var opacity = parseInt(document.getElementById('opacitySlider').value) / 100;
if (!mapName) {
showStatus('请先选择地图', 'error');
return;
}
if (!layerName) {
showStatus('请先选择图层', 'error');
return;
}
var rgbaColor = hexToRgba(color, opacity);
updateLayerStyle(mapName, layerName, rgbaColor);
});
function updateLayerStyle(mapName, layerName, color) {
var url = 'http://localhost:8090/iserver/services/map-ChengduFresh/rest/maps/' + encodeURIComponent(mapName) + '/layers.json';
var updatedLayersData = JSON.parse(JSON.stringify(allLayersData[mapName]));
updateLayerColorRecursively(updatedLayersData, layerName, color);
fetch(url, {
method: 'PUT',
headers: {
'Content-Type': 'application/json;charset=UTF-8'
},
body: JSON.stringify(updatedLayersData)
})
.then(response => {
if (response.ok) {
return response.json();
}
throw new Error('更新失败');
})
.then(data => {
allLayersData[mapName] = updatedLayersData;
showStatus('样式更新成功!页面即将刷新...', 'success');
setTimeout(function() {
location.reload();
}, 1000);
})
.catch(error => {
showStatus('更新失败: ' + error.message, 'error');
console.error('更新图层样式失败:', error);
});
}
function updateLayerColorRecursively(layers, layerName, color) {
if (Array.isArray(layers)) {
layers.forEach(layer => {
updateLayerColorRecursively(layer, layerName, color);
});
} else if (typeof layers === 'object' && layers !== null) {
if (layers.name === layerName && layers.style) {
layers.style.fillForeColor = color;
}
if (layers.subLayers && layers.subLayers.layers) {
updateLayerColorRecursively(layers.subLayers.layers, layerName, color);
}
}
}
function refreshMap(mapName) {
mapLayers.forEach(item => {
if (item.config.name === mapName) {
map.removeLayer(item.layer);
item.layer = new L.supermap.TiledMapLayer(item.config.url);
item.layer.addTo(map);
}
});
}
function showStatus(message, type) {
var statusEl = document.getElementById('statusMessage');
statusEl.textContent = message;
statusEl.className = 'status-message status-' + type;
statusEl.style.display = 'block';
setTimeout(() => {
statusEl.style.display = 'none';
}, 3000);
}
document.querySelectorAll('.tab').forEach(tab => {
tab.addEventListener('click', function() {
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
this.classList.add('active');
var tabId = this.getAttribute('data-tab');
document.getElementById(tabId).classList.add('active');
});
});
initMap();
</script>
</body>
</html>
结语:本文介绍的图层样式修改器为B/S端GIS应用提供了轻量化的样式管理解决方案,基于SuperMap REST API实现了样式的实时读取和更新,具有良好的扩展性和易用性。