ArcGIS for JS 实战:范围裁剪(只保留特定区域显示),实现精准地理范围聚焦 🗺️
在 ArcGIS for JavaScript 开发中,经常会遇到 "只显示指定区域,隐藏其他范围" 的需求,比如区域数据可视化、特定地理范围分析等场景。本文适用于 ArcGIS Maps SDK for JavaScri pt 4.28~4.33 版本,结合天地图底图,带大家一步步实现 "特定区域保留显示" 功能,代码可直接复用!
文章目录
- [ArcGIS for JS 实战:范围裁剪(只保留特定区域显示),实现精准地理范围聚焦 🗺️](#ArcGIS for JS 实战:范围裁剪(只保留特定区域显示),实现精准地理范围聚焦 🗺️)
-
- 效果图
- [一、核心思路:图层混合模式实现 "范围裁剪" ✂️](#一、核心思路:图层混合模式实现 “范围裁剪” ✂️)
- 二、完整代码解析📝
-
- [1. 基础页面结构与样式](#1. 基础页面结构与样式)
- [2. 核心模块引入与天地图加载](#2. 核心模块引入与天地图加载)
- [3. 定义 "保留区域" 的地理范围 📍](#3. 定义 “保留区域” 的地理范围 📍)
- [4. 构建 "裁剪层":关键的 GraphicsLayer 🎨](#4. 构建 “裁剪层”:关键的 GraphicsLayer 🎨)
- [5. 组合图层并初始化地图 🚀](#5. 组合图层并初始化地图 🚀)
- [三、关键注意事项 ⚠️](#三、关键注意事项 ⚠️)
- [四、所有代码 🚀](#四、所有代码 🚀)
工具 /插件/系统 名 | 版本 | 说明 |
---|---|---|
ArcGIS JS API | 4.28~4.33 | 地图核心能力(底图加载、视图渲染) |
天地图服务 | - | 提供街道、卫星、地形等底图数据源 |
效果图

一、核心思路:图层混合模式实现 "范围裁剪" ✂️
实现 "只保留特定区域" 的核心原理是利用 GraphicsLayer
** 的 blendMode: "destination-in"
属性**:
-
destination-in
表示 "只显示当前图层与下层图层重叠的区域",非重叠区域会被透明化 -
我们只需绘制一个 "目标保留区域" 的面图形,结合该混合模式,就能实现 "裁剪" 效果
-
搭配天地图底图,可快速构建带区域聚焦的地图应用
二、完整代码解析📝
1. 基础页面结构与样式
首先搭建 HTML 骨架,设置地图容器占满全屏,确保地图显示无偏差:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<!-- 适配移动端,防止地图缩放异常 -->
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>ArcGIS for JS 只保留特定区域</title>
<style>
/* 地图容器全屏样式 */
html, body, #viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<!-- 引入ArcGIS核心样式和JS库 -->
<link rel="stylesheet" href="https://js.arcgis.com/4.33/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.33/"></script>
</head>
<body>
<!-- 地图渲染容器 -->
<div id="viewDiv"></div>
<script type="module">
// 核心逻辑代码在这里...
</script>
</body>
</html>
2. 核心模块引入与天地图加载
通过 $arcgis.import
引入 ArcGIS 核心模块,同时加载天地图底图(需提前准备 tiandituLoader.js
工具类,也可以直接在《天地图底图加载》)中直接复制。
// 1. 引入ArcGIS核心模块
const [Map, MapView, GraphicsLayer, GroupLayer] =
await $arcgis.import([
"@arcgis/core/Map.js", // 地图实例
"@arcgis/core/views/MapView.js", // 地图视图
"@arcgis/core/layers/GraphicsLayer.js", // 矢量图形层
"@arcgis/core/layers/GroupLayer.js" // 图层组(用于管理多个图层)
]);
// 2. 加载天地图底图(矢量图+注记层)
import { loadTiandituBasemap } from './js/tiandituLoader.js';
const {
vecLayer: worldImagery, // 天地图矢量底图
cvaLayer: tileLayer // 天地图注记层(显示地名)
} = await loadTiandituBasemap();
3. 定义 "保留区域" 的地理范围 📍
通过 rings
数组定义多边形坐标(支持多环,可用于包含 "飞地" 场景),坐标格式为 [经度, 纬度]
, spatialReference 设为 4326
(WGS84 坐标系):
// 定义保留区域的多边形坐标(示例为两个闭合区域)
const rings = [
// 第一个区域(示例范围)
[[123.09306581, 43.90257375],
[123.82517908, 43.58244008],
[124.26830027, 42.49823921],
[120.41507254, 41.97045084],
[120.33800799, 43.61034574],
[123.09306581, 43.90257375]], // 闭合坐标(首尾一致)
// 第二个区域(可理解为"飞地")
[[124.52760067, 45.86828802],
[121.05156665, 44.74454778],
[125.90119475, 44.46513338],
[124.52760067, 45.86828802]]
];
4. 构建 "裁剪层":关键的 GraphicsLayer 🎨
创建 GraphicsLayer
并设置 blendMode: "destination-in"
,这是实现 "只保留特定区域" 的核心步骤:
const graphicsLayer = new GraphicsLayer({
blendMode: "destination-in", // 核心混合模式:只显示重叠区域
title: "特定保留区域",
graphics: [
new Graphic({
geometry: {
type: "polygon", // 图形类型:多边形
rings: rings, // 绑定上面定义的区域坐标
spatialReference: { wkid: 4326 } // 坐标系
},
symbol: { // 多边形样式(因混合模式,颜色仅影响重叠区域透明度)
type: "simple-fill",
color: [0, 0, 0, 1], // 黑色不透明(确保重叠区域完全显示)
outline: { // 区域边界样式
color: [255, 0, 0], // 红色边界
width: 2 // 边界宽度
}
},
})
]
});
5. 组合图层并初始化地图 🚀
将天地图底图、注记层、裁剪层组合成 GroupLayer
,避免图层层级混乱,最后初始化地图视图:
// 1. 组合图层(顺序:底图 → 注记 → 裁剪层)
const groupLayer = new GroupLayer({
layers: [worldImagery, tileLayer, graphicsLayer],
opacity: 1 // 整体图层透明度
});
// 2. 创建地图实例
const map = new Map({
layers: [groupLayer] // 绑定图层组
});
// 3. 创建地图视图(控制地图显示)
const view = new MapView({
container: "viewDiv", // 绑定地图容器
map: map, // 绑定地图实例
center: [125.8425456, 43.85312804], // 初始中心点坐标
zoom: 8, // 初始缩放级别(根据区域大小调整)
constraints: {
minScale: 19499143, // 最小缩放级别(防止缩太小看到无关区域)
maxScale: 5000 // 最大缩放级别(防止放太大模糊)
},
popup: null // 暂时关闭弹窗(如需启用,可删除此配置)
});
// 可选:地图加载完成后提示
view.when(() => {
console.log("地图加载完成,已显示特定保留区域!");
});
三、关键注意事项 ⚠️
-
坐标顺序问题 :ArcGIS 中
rings
坐标格式为[经度, 纬度]
,不要和[纬度, 经度]
混淆,否则区域会显示异常; -
混合模式生效条件 :
GraphicsLayer
必须放在最上层(图层顺序:底图 → 业务层 → 裁剪层),否则混合模式不生效; -
天地图加载依赖 :
tiandituLoader.js
需要正确配置天地图 Key(需自行申请天地图开发者账号,免费版足够测试); -
多区域支持 :
rings
数组支持多个子数组,可实现 "多个不连续区域同时保留"(如多个城市、多个地块)。
四、所有代码 🚀
index.html
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Highlight a country with an effect | Sample | ArcGIS Maps SDK for JavaScript 4.33</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
#messageDiv {
padding-left: 10px;
padding-right: 10px;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.33/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.33/"></script>
<script type="module">
const [Map, MapView, TileLayer, Graphic, GraphicsLayer, GroupLayer] =
await $arcgis.import([
"@arcgis/core/Map.js",
"@arcgis/core/views/MapView.js",
"@arcgis/core/layers/TileLayer.js",
"@arcgis/core/Graphic.js",
"@arcgis/core/layers/GraphicsLayer.js",
"@arcgis/core/layers/GroupLayer.js"
]);
import { loadTiandituBasemap } from './js/tiandituLoader.js';
const {
config,
getUrlTemplate,
WebTileLayer,
vecLayer: worldImagery,
cvaLayer: tileLayer,
tileInfo } = await loadTiandituBasemap();
const rings = [[[123.09306581, 43.90257375], [123.82517908, 43.58244008], [124.26830027, 42.49823921],
[120.41507254, 41.97045084], [120.33800799, 43.61034574], [123.09306581, 43.90257375]],
[[124.52760067, 45.86828802], [121.05156665, 44.74454778], [125.90119475, 44.46513338], [124.52760067, 45.86828802]]
]
const graphicsLayer = new GraphicsLayer({
blendMode: "destination-in",
title: "layer",
graphics: [
new Graphic({
geometry: {
type: "polygon",
rings,
spatialReference: { wkid: 4326 }
},
attributes: {
objectid: 1,
// name:,
longitude: 116.397428,
latitude: 39.90923
},
symbol: {
type: "simple-fill",
color: [0, 0, 0, 1],
outline: {
color: [0, 0, 0],
width: 2
}
},
}),
],
});
const groupLayer = new GroupLayer({
layers: [
worldImagery,
tileLayer,
graphicsLayer,
],
opacity: 1,
});
const map = new Map({
layers: [groupLayer]
});
const view = new MapView({
container: "viewDiv",
map: map,
center: [125.8425456, 43.85312804], // 鍖椾含鍧愭爣
popup: null,
constraints: {
minScale: 19499143,
},
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>