ArcGIS JS 基础教程(7):Global与Local场景模式
零、写在前面
📌 本系列教程完整目录 :ArcGIS JS 系列基础教程(100个项目常用热门功能)
💡 在线示例 :完整可运行的 HTML 示例,无需任何环境配置,可直接在浏览器中打开体验
🗂️ 专栏导航 :收藏 + 关注,专栏文章第一时间送达
❤️ 一键三连:点赞(给教程充电)+ 评论(提问必回)+ 收藏(下次再看)
一、功能介绍
SceneView 支持两种场景模式:Global(全球球面模式) 和 Local(局部平面模式) ,通过 viewingMode 属性控制。
- Global 模式:在 WGS84 球面坐标系下渲染完整的地球球体,适合展示大范围、跨区域的三维数据。地球曲率真实可见,支持全球尺度漫游。
- Local 模式:在投影坐标系下将场景渲染为局部平面区域,适合城市级或园区级的精细化展示。平面投影下量算更精准,无地球曲率干扰。
两种模式对高程数据的处理方式也不同:Global 模式下高程贴合球面曲率;Local 模式下高程在投影平面上拉伸,精度更高。根据项目尺度正确选择模式,是三维场景构建的关键第一步。
二、功能实现
SceneView.viewingMode 属性决定场景模式,可选值为 "global"(默认)或 "local"。
Global 模式关键配置:
- 坐标系:WGS84(EPSG:4326),经纬度直接驱动
map.ground加载全球高程服务world-elevation- 相机参数:
camera.position使用[longitude, latitude, altitude]
Local 模式关键配置:
- 坐标系:需使用投影坐标系(如 Web Mercator EPSG:3857,或地方投影带)
- 通过设置
extent约束场景显示范围,避免平面无限延伸 - 局部模式下相机
position的 x/y 为投影平面坐标,z 仍为高程
动态切换注意: Global 与 Local 模式不能在同一个 SceneView 实例中动态切换,需要销毁原有视图、创建新的 SceneView 实例。实际项目中通常在入口页提供模式选择,或维护两个独立页面。
核心代码如下:
- 创建 Global 模式:
viewingMode: "global"(可省略,默认即为 global) - 创建 Local 模式:
viewingMode: "local",并建议同时设置constraints.clipToExtent限制渲染范围 - Local 模式需确保底图和支持的图层在投影坐标系下可用(Web Mercator 兼容性最好)
三、功能应用
| 场景 | 推荐模式 | 理由 |
|---|---|---|
| 全球物流航线可视化 | Global | 需要展示跨大洲的球面航线,地球曲率不可忽略 |
| 智慧园区精细化管理 | Local | 园区范围小,平面坐标系下量算和建模更精准 |
| 城市数字孪生(区县尺度) | Local | 城市级场景在平面投影下建筑对齐更自然 |
| 气象/海洋全球数据展示 | Global | 全球尺度的气象云图、洋流需要在球面上连续展示 |
| 应急指挥(局部区域) | Local | 局部区域分析无需地球曲率,平面量算更符合业务习惯 |
| 航空航天态势感知 | Global | 卫星轨道、飞行轨迹跨越全球,球面模式是唯一选择 |
选择原则:
- 数据范围 大于 100km (如全省、全国、全球)→ 选 Global
- 数据范围 小于 50km (如园区、城区)→ 选 Local
- 介于之间需结合业务:涉及球面几何(大圆航线)选 Global,涉及精密量算选 Local
四、核心代码
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>第6课:Global与Local场景模式</title>
<link rel="stylesheet" href="https://js.arcgis.com/5.0/esri/themes/light/main.css">
<script type="module" src="https://js.arcgis.com/5.0/"></script>
<style>
body { margin: 0; padding: 0; font-family: "Microsoft YaHei", sans-serif; }
#mapContainer { width: 100vw; height: 100vh; }
.page-title {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(255,255,255,0.95);
padding: 10px 24px;
border-radius: 6px;
font-size: 18px;
font-weight: bold;
z-index: 100;
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
}
.control-panel {
position: absolute;
top: 80px;
left: 20px;
background: rgba(255,255,255,0.95);
padding: 16px;
border-radius: 8px;
box-shadow: 0 2px 12px rgba(0,0,0,0.15);
z-index: 100;
min-width: 220px;
}
.mode-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 12px;
font-size: 13px;
font-weight: bold;
margin-bottom: 12px;
}
.badge-global { background: #1890ff; color: white; }
.badge-local { background: #52c41a; color: white; }
.btn-group { display: flex; flex-direction: column; gap: 8px; }
.btn-group button {
padding: 10px 16px;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 13px;
font-weight: 500;
}
.btn-global { background: #1890ff; color: white; }
.btn-local { background: #52c41a; color: white; }
.btn-compare { background: #722ed1; color: white; }
.btn-group button:hover { opacity: 0.85; }
.info-box {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(255,255,255,0.95);
padding: 12px 20px;
border-radius: 8px;
font-size: 13px;
line-height: 1.8;
z-index: 100;
box-shadow: 0 2px 12px rgba(0,0,0,0.15);
max-width: 600px;
}
.info-box code { background: #f0f0f0; padding: 1px 4px; border-radius: 3px; }
</style>
</head>
<body>
<h1 class="page-title">第7课:Global 与 Local 场景模式</h1>
<div class="control-panel">
<div id="modeBadge" class="mode-badge badge-global">当前模式:GLOBAL</div>
<div class="btn-group">
<button class="btn-global" id="btnGlobal">切换为 Global 模式</button>
<button class="btn-local" id="btnLocal">切换为 Local 模式</button>
<button class="btn-compare" id="btnCompare">对比:北京 vs 小范围园区</button>
</div>
</div>
<div class="info-box">
🌐 <b>Global 模式</b>:球面坐标系(WGS84),适合<code>全省/全国/全球</code>尺度<br>
📐 <b>Local 模式</b>:平面投影坐标系,适合<code>园区/城区</code>尺度,量算更精准
</div>
<div id="mapContainer"></div>
<script type="module">
const Map = await $arcgis.import("@arcgis/core/Map.js");
const SceneView = await $arcgis.import("@arcgis/core/views/SceneView.js");
const getTianditu = await $arcgis.import("https://openlayers.vip/examples/resources/tianditu.js");
// ========== 天地图图层 ==========
const vecLayers = getTianditu.default({ type: "vec_w" });
// ========== 创建 Map ==========
const map = new Map({
basemap: { baseLayers: [vecLayers.base, vecLayers.anno] },
ground: {
surface: {
elevationLayers: [{
url: "https://www.geosceneonline.cn/image/rest/services/OpenData/ChinaTerrain3D/ImageServer/"
}]
}
}
});
// ========== 初始为 Global 模式 ==========
let currentMode = "global";
window.view = new SceneView({
container: "mapContainer",
map: map,
viewingMode: "global", // 关键属性:global | local
center: [116.39, 39.9],
zoom: 10,
tilt: 60,
constraints: {
altitude: { max: 20000000 } // 限制最大高度,避免缩太小
}
});
// ========== 更新 UI 徽章 ==========
function updateBadge(mode) {
const badge = document.getElementById("modeBadge");
if (mode === "global") {
badge.className = "mode-badge badge-global";
badge.textContent = "当前模式:GLOBAL(球面)";
} else {
badge.className = "mode-badge badge-local";
badge.textContent = "当前模式:LOCAL(平面)";
}
}
// ========== 切换为 Global 模式 ==========
window.switchToGlobal = () => {
if (currentMode === "global") return;
currentMode = "global";
// 销毁旧视图,创建新视图(两模式无法动态切换同一实例)
view.destroy();
window.view = new SceneView({
container: "mapContainer",
map: map,
viewingMode: "global",
center: [116.39, 39.9],
zoom: 10,
tilt: 60
});
updateBadge("global");
};
// ========== 切换为 Local 模式 ==========
window.switchToLocal = () => {
if (currentMode === "local") return;
currentMode = "local";
view.destroy();
window.view = new SceneView({
container: "mapContainer",
map: map,
viewingMode: "local", // 关键:切换为局部平面模式
center: [116.39, 39.9],
zoom: 14,
tilt: 55,
constraints: {
clipToExtent: true, // 限制仅渲染 extent 范围内
altitude: { max: 50000 }
}
});
updateBadge("local");
};
// ========== 对比演示:分别定位到全球视角和局部园区 ==========
window.compareModes = () => {
if (currentMode === "global") {
// 当前是 Global → 飞到北京上空(展示球面效果)
view.goTo({
position: [116.39, 39.9, 2500000],
tilt: 0,
heading: 0
});
} else {
// 当前是 Local → 定位到小规模园区范围
view.goTo({
position: [116.39, 39.9, 2000],
tilt: 55,
heading: 0
});
}
};
document.getElementById("btnGlobal").onclick = switchToGlobal;
document.getElementById("btnLocal").onclick = switchToLocal;
document.getElementById("btnCompare").onclick = compareModes;
updateBadge("global");
view.when(() => console.log("Global/Local 场景模式示例加载完成!"));
</script>
</body>
</html>
五、在线示例
🔗 在线体验地址 :https://southjor.github.io/arcgis-examples/lessons/lesson7.html

操作说明:
- 点击「切换为 Local 模式」按钮,观察地球从球面变为平面的视觉效果
- 在 Global 模式下大幅缩小,可看到完整地球球体
- 在 Local 模式下放大,建筑与地面贴合更自然,无球面扭曲
六、关键API说明
| API | 说明 |
|---|---|
SceneView.viewingMode |
场景模式:"global"(球面,默认)/ "local"(平面) |
SceneView.constraints.clipToExtent |
Local 模式下是否仅渲染 extent 范围内(避免平面无限延伸) |
SceneView.constraints.altitude.max |
限制最大视角高度,Global 模式下防止缩太小看不到地球 |
camera.position |
Global 模式为 [lng, lat, alt];Local 模式 x/y 为投影坐标 |
map.ground |
两种模式下高程数据的处理和显示方式不同,Local 精度更高 |
view.destroy() |
切换模式时需先销毁旧视图实例,再创建新模式视图 |
两种模式核心差异对比
| 对比维度 | Global 模式 | Local 模式 |
|---|---|---|
| 坐标系 | WGS84(球面) | 投影坐标系(平面) |
| 地球曲率 | 有(真实球面) | 无(平面投影) |
| 适用尺度 | 全省/全国/全球 | 园区/城区 |
| 量算精度 | 球面距离(大范围准确) | 平面距离(小范围更精准) |
| 高程处理 | 贴合球面 | 平面拉伸,精度更高 |
| 性能建议 | 注意全球数据加载性能 | 可加载更高精度局部数据 |
七、系列导航
⬅️ 上一篇 :ArcGIS JS 基础教程(6):地图弹窗信息窗口
💡 小贴士:如果你在 Local 模式下使用自定义切片底图,请确保切片服务的坐标系为投影坐标系(如 EPSG:3857),否则会出现图像偏移或无法显示的问题。