ArcGIS for JS 实战:范围裁剪(只保留特定区域显示),实现精准地理范围聚焦 ️

在 ArcGIS for JavaScript 开发中,经常会遇到 “只显示指定区域,隐藏其他范围” 的需求,比如区域数据可视化、特定地理范围分析等场景。本文适用于 ArcGIS Maps SDK for JavaScri pt 4.28~4.33 版本,结合天地图底图,带大家一步步实现 “特定区域保留显示” 功能,代码可直接复用!

工具 /插件/系统 名版本说明
ArcGIS JS API4.28~4.33地图核心能力(底图加载、视图渲染)
天地图服务-提供街道、卫星、地形等底图数据源

效果图

在这里插入图片描述

一、核心思路:图层混合模式实现 “范围裁剪” ✂️

实现 “只保留特定区域” 的核心原理是利用 GraphicsLayer** 的 blendMode: "destination-in" 属性**:

  • destination-in 表示 “只显示当前图层与下层图层重叠的区域”,非重叠区域会被透明化

  • 我们只需绘制一个 “目标保留区域” 的面图形,结合该混合模式,就能实现 “裁剪” 效果

  • 搭配天地图底图,可快速构建带区域聚焦的地图应用

二、完整代码解析

1. 基础页面结构与样式

首先搭建 HTML 骨架,设置地图容器占满全屏,确保地图显示无偏差:




    
    
    
    ArcGIS for JS 只保留特定区域
    
    
    
    <script src="https://js.arcgis.com/4.33/"></script>


    
    
<script type="module"> // 核心逻辑代码在这里... </script>

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("地图加载完成,已显示特定保留区域!");
});

三、关键注意事项 ⚠️

  1. 坐标顺序问题:ArcGIS 中 rings 坐标格式为 [经度, 纬度],不要和 [纬度, 经度] 混淆,否则区域会显示异常;

  2. 混合模式生效条件GraphicsLayer 必须放在最上层(图层顺序:底图 → 业务层 → 裁剪层),否则混合模式不生效;

  3. 天地图加载依赖tiandituLoader.js 需要正确配置天地图 Key(需自行申请天地图开发者账号,免费版足够测试);

  4. 多区域支持rings 数组支持多个子数组,可实现 “多个不连续区域同时保留”(如多个城市、多个地块)。

四、所有代码

index.html





    
    
    Highlight a country with an effect | Sample | ArcGIS Maps SDK for JavaScript 4.33
    
    
    <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>