Openlayers调用ArcGis地图服务之二 —— 动态地图(/export)

1.2 Openlayers调用ArcGis地图服务之动态地图(/export)

下面使用ArcGis官方服务作为示例直接调用(如果使用自己的私有服务,可能先要获取token)

各个库版本如下:

javascript 复制代码
    "ol": "^10.8.0",
    "proj4": "^2.20.8",
    "vue3-openlayers": "^12.2.2"

目录

  • [1.2 动态地图【地图服务的查询接口(/export)】](#1.2 动态地图【地图服务的查询接口(/export)】)
    • [1.2.1 介绍](#1.2.1 介绍)
    • [1.2.2 判断](#1.2.2 判断)
    • [1.2.3 调用](#1.2.3 调用)
      • [1.2.3.1 在线预览](#1.2.3.1 在线预览)
      • [1.2.3.2 在线调用](#1.2.3.2 在线调用)
      • [1.2.3.3 Openlayers调用](#1.2.3.3 Openlayers调用)
      • [1.2.3.4 Vue3-Openlayers调用](#1.2.3.4 Vue3-Openlayers调用)
    • [1.2.4 对比使用调用动态地图的方式调用有切片的地图服务](#1.2.4 对比使用调用动态地图的方式调用有切片的地图服务)
      • [1.2.4.1 Openlayers调用](#1.2.4.1 Openlayers调用)

1.2 动态地图【地图服务的查询接口(/export)】

1.2.1 介绍

动态地图是指服务器在收到客户端的每次请求时,根据当前请求的范围、比例尺、图层设置、样式等参数,实时渲染生成一张完整的地图图片(或切分成多个瓦片动态生成),然后返回给客户端。

核心特征:

  • 实时渲染:每次请求都重新绘制地图,数据始终是最新的。

  • 灵活:客户端可以动态控制显示哪些图层、应用过滤条件、改变符号样式等。

  • 较高延迟:服务器需要实时进行空间查询、符号化、输出图片,对计算资源消耗大,响应速度较慢。

  • 适合业务数据:常用于需要频繁更新、用户交互性强的地理信息展示(如实时监控、数据编辑、临时分析)。

  • 典型应用:ArcGIS 动态地图服务(MapServer 的 /export 接口)、WMS(Web Map Service)的 GetMap 操作。

1.2.2 判断

判断一个ArcGis地图服务是否可以使用动态服务形式调用,可以查看地图服务的基本信息,比如ArcGis官方服务2

因为动态地图主要使用/export接口,所以看到下图中Supported Operations中有Export Map就基本可以判断支持动态地图

同时结合下面信息:

  • 信息1

注意 :图中的Single Fused Map Cache: false和不存在Tile Info说明该地图服务没有切分缓存,可以以/export接口导出的形式支持动态地图

  • 信息2

指包含两个子图层,可以在生成动态地图时使用参数控制显示隐藏

(其实在上一篇1.1.2中Single Fused Map Cache: true和存在Tile Info字段的切片地图服务,Supported Operations中也有Export Map,所以也可以以/export接口导出的形式支持动态地图,但是因为Single Fused Map Cache: true,地图图片是预先渲染好并拼接成一张大图的。因此,无论 layers 参数如何设置,它都只能返回这张已经做好的、包含了所有图层的完整图片(下面有对比))

1.2.3 调用

1.2.3.1 在线预览

点击红框内的ArcGIS JavaScript,即可在线预览

可以看到在线预览调用的是动态地图

1.2.3.2 在线调用

点击红框内的Export Map,即可在线调用

点击提交后,可以看到按照提交参数导出了layer0

1.2.3.3 Openlayers调用



可以看到,通过调整Layers参数,服务器会实时生成不同的图片,而且不像切片拼接,而是只有一个请求返回完整图片

javascript 复制代码
<template>
  <div class="map-page">
    <h1>OpenLayers 动态地图 - Oil Sands</h1>
    <div class="map-controls">
      <label>
        <input type="checkbox" v-model="showPoints" @change="updateLayers" />
        显示项目点 (Points)
      </label>
      <label>
        <input
          type="checkbox"
          v-model="showBoundaries"
          @change="updateLayers"
        />
        显示项目边界 (Boundaries)
      </label>
    </div>
    <div id="dynamic-ol-map" ref="mapContainer" class="map-container"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import ImageLayer from "ol/layer/Image";
import ImageArcGISRest from "ol/source/ImageArcGISRest";
import { register } from "ol/proj/proj4";
import proj4 from "proj4";

const mapContainer = ref<HTMLDivElement>();
let map: Map | null = null;

// EPSG:3400 投影定义 (NAD83 / Alberta Lambert Conformal Conic)
proj4.defs(
  "EPSG:3400",
  "+proj=lcc +lat_1=49 +lat_2=55 +lat_0=52 +lon_0=-114.6666666666667 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs",
);
register(proj4);

// 图层显示状态
const showPoints = ref(true);
const showBoundaries = ref(true);

let dynamicLayer: ImageLayer<ImageArcGISRest> | null = null;

// 获取可见图层列表
const getVisibleLayers = () => {
  const layers: string[] = [];
  if (showPoints.value) layers.push("0"); // OSProjectPoints2015
  if (showBoundaries.value) layers.push("1"); // OSProjectBoundaries2015
  return layers;
};

// 更新图层
const updateLayers = () => {
  if (dynamicLayer) {
    const source = dynamicLayer.getSource();
    if (source) {
      source.updateParams({ LAYERS: "show:" + getVisibleLayers().join(",") });
      source.refresh();
    }
  }
};

onMounted(() => {
  // 创建 ArcGIS REST 动态地图图层
  dynamicLayer = new ImageLayer({
    source: new ImageArcGISRest({
      ratio: 1,
      params: {
        LAYERS: "show:" + getVisibleLayers().join(","),
      },
      url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/OilSandsProjectBoundaries/MapServer/export",
    }),
  });

  // 创建地图
  map = new Map({
    target: mapContainer.value!,
    layers: [dynamicLayer],
    view: new View({
      projection: "EPSG:3400",
      center: [597849, 6184094], // 油砂区域中心坐标
      zoom: 0,
      minZoom: 0,
      maxZoom: 10,
    }),
  });
});

onUnmounted(() => {
  if (map) {
    map.setTarget(undefined);
    map = null;
  }
});
</script>

<style scoped>
.map-page {
  padding: 20px;
}

h1 {
  margin-bottom: 15px;
  color: #333;
}

.map-controls {
  margin-bottom: 15px;
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.map-controls label {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.map-controls input[type="checkbox"] {
  cursor: pointer;
}

.map-container {
  width: 100%;
  height: 600px;
  border: 2px solid #ddd;
  border-radius: 8px;
}
</style>
1.2.3.4 Vue3-Openlayers调用


可以看到,通过调整Layers参数,服务器会实时生成不同的图片,但是因为使用ol-tile-layer,所以的服务器返回的是多个切片,然后在浏览器拼接

javascript 复制代码
<template>
  <div class="map-page">
    <h1>Vue3-OpenLayers 动态地图 - Oil Sands</h1>
    <div class="map-controls">
      <label>
        <input type="checkbox" v-model="showPoints" @change="updateLayers" />
        显示项目点 (Points)
      </label>
      <label>
        <input
          type="checkbox"
          v-model="showBoundaries"
          @change="updateLayers"
        />
        显示项目边界 (Boundaries)
      </label>
    </div>
    <ol-map
      :loadTilesWhileAnimating="true"
      :loadTilesWhileInteracting="true"
      class="map-container"
    >
      <ol-view :center="center" :zoom="zoom" :projection="projection" />
      <ol-tile-layer>
        <OlSourceTileArcGISRest
          ref="dynamicSource"
          :url="mapUrl"
          :params="layerParams"
        />
      </ol-tile-layer>
    </ol-map>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted } from "vue";
import ImageArcGISRest from "ol/source/ImageArcGISRest";
import { register } from "ol/proj/proj4";
import proj4 from "proj4";

// EPSG:3400 投影定义 (NAD83 / Alberta Lambert Conformal Conic)
proj4.defs(
  "EPSG:3400",
  "+proj=lcc +lat_1=49 +lat_2=55 +lat_0=52 +lon_0=-114.6666666666667 +x_0=0 +y_0=0 +datum=NAD83 +units=m +no_defs",
);
register(proj4);

// 图层显示状态
const showPoints = ref(true);
const showBoundaries = ref(true);

const dynamicSource = ref<{ source: ImageArcGISRest } | null>(null);

// 获取可见图层列表
const getVisibleLayers = () => {
  const layers: string[] = [];
  if (showPoints.value) layers.push("0"); // OSProjectPoints2015
  if (showBoundaries.value) layers.push("1"); // OSProjectBoundaries2015
  return layers;
};

// 图层参数
const layerParams = computed(() => ({
  LAYERS: "show:" + getVisibleLayers().join(","),
}));

const mapUrl =
  "https://sampleserver6.arcgisonline.com/arcgis/rest/services/OilSandsProjectBoundaries/MapServer/export";

const center = ref([597849, 6184094]); // 油砂区域中心坐标
const zoom = ref(0);
const projection = ref("EPSG:3400");

// 更新图层
const updateLayers = () => {
  if (dynamicSource.value?.source) {
    dynamicSource.value.source.updateParams({
      LAYERS: "show:" + getVisibleLayers().join(","),
    });
    dynamicSource.value.source.refresh();
  }
};
</script>

<style scoped>
.map-page {
  padding: 20px;
}

h1 {
  margin-bottom: 15px;
  color: #333;
}

.map-controls {
  margin-bottom: 15px;
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.map-controls label {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.map-controls input[type="checkbox"] {
  cursor: pointer;
}

.map-container {
  width: 100%;
  height: 600px;
  border: 2px solid #ddd;
  border-radius: 8px;
  overflow: hidden;
}
</style>

1.2.4 对比使用调用动态地图的方式调用有切片的地图服务

1.2.4.1 Openlayers调用
javascript 复制代码
<template>
  <div class="map-page">
    <h1>OpenLayers 动态地图</h1>
    <div class="map-controls">
      <label>
        <input type="checkbox" v-model="showRoads" @change="updateLayers" />
        显示道路 (Roads)
      </label>
      <label>
        <input type="checkbox" v-model="showWater" @change="updateLayers" />
        显示水体 (Water)
      </label>
      <label>
        <input type="checkbox" v-model="showUrban" @change="updateLayers" />
        显示城市 (Urban)
      </label>
      <label>
        <input type="checkbox" v-model="showLanduse" @change="updateLayers" />
        显示土地 (Landuse)
      </label>
    </div>
    <div id="dynamic-ol-map" ref="mapContainer" class="map-container"></div>
  </div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import ImageLayer from "ol/layer/Image";
import ImageArcGISRest from "ol/source/ImageArcGISRest";

const mapContainer = ref<HTMLDivElement>();
let map: Map | null = null;

// 图层显示状态
const showRoads = ref(true);
const showWater = ref(true);
const showUrban = ref(true);
const showLanduse = ref(true);

let dynamicLayer: ImageLayer<ImageArcGISRest> | null = null;

// 获取可见图层列表
const getVisibleLayers = () => {
  const layers: string[] = [];
  if (showRoads.value) layers.push("0"); // Roads
  if (showWater.value) layers.push("1"); // Water
  if (showUrban.value) layers.push("2"); // Urban
  if (showLanduse.value) layers.push("3"); // Landuse
  return layers;
};

// 更新图层
const updateLayers = () => {
  if (dynamicLayer) {
    const source = dynamicLayer.getSource();
    if (source) {
      source.updateParams({ LAYERS: "show:" + getVisibleLayers().join(",") });
      source.refresh();
    }
  }
};

onMounted(() => {
  // 创建 ArcGIS REST 动态地图图层
  dynamicLayer = new ImageLayer({
    source: new ImageArcGISRest({
      ratio: 1,
      params: {
        LAYERS: "show:" + getVisibleLayers().join(","),
      },
      url: "https://sampleserver6.arcgisonline.com/arcgis/rest/services/MtBaldy_BaseMap/MapServer/export",
    }),
  });

  // 创建地图
  map = new Map({
    target: mapContainer.value!,
    layers: [dynamicLayer],
    view: new View({
      projection: "EPSG:32611",
      center: [457000, 3796000],
      zoom: 5,
      resolutions: [
        4233.341800016934, 2116.670900008467, 1058.3354500042335,
        529.1677250021168, 264.5838625010584, 132.2919312505292,
        66.1459656252646, 33.0729828126323, 16.53649140631615,
        8.268245703158074, 4.134122851579037, 2.0670614257895186,
        1.0335307128947593,
      ],
    }),
  });
});

onUnmounted(() => {
  if (map) {
    map.setTarget(undefined);
    map = null;
  }
});
</script>

<style scoped>
.map-page {
  padding: 20px;
}

h1 {
  margin-bottom: 15px;
  color: #333;
}

.map-controls {
  margin-bottom: 15px;
  display: flex;
  gap: 20px;
  flex-wrap: wrap;
}

.map-controls label {
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.map-controls input[type="checkbox"] {
  cursor: pointer;
}

.map-container {
  width: 100%;
  height: 600px;
  border: 2px solid #ddd;
  border-radius: 8px;
}
</style>




可以看到,虽然Layers传参不同(新版写法为Layers show:0,1,2,3或者Layers hide:0,1,2,3 老版写法没有Layers 0,1,2),但是显示的图片都是相同的

相关推荐
沐言人生4 分钟前
82.4k 星!把十几万行代码变成知识图谱,新人终于不用硬啃了
前端·后端·github
溪语流沙4 分钟前
【Web全栈进阶】JWT无状态认证:签发、校验、刷新
前端·git·python·github
在繁华处10 分钟前
2.1 上下文:决定 Agent 能力上限的关键
前端·人工智能·microsoft
ndsc_d10 分钟前
2026年有哪些好用的AI UI设计工具?主流工具功能和适用场景对比
前端·人工智能·ui·ai·设计师·ai ui·ai ui工具
溪语流沙32 分钟前
【每天一个CSS | Day18】会摆动的拟物怀表:黄铜、皮革与催眠摆
前端·css3·html5
Lvan的前端笔记38 分钟前
docker:基于docker的前端部署方案
前端·docker·状态模式
程序人生88838 分钟前
从“把隐私文件上传到别人云端“到本地可控:DocConverter Web 立项初心与架构选型
前端·图像处理·人工智能·opencv·架构·ocr·文心一言
开开心心就好1 小时前
视频里的图片怎么提取?双击一下就导出
java·前端·人工智能·spring·智能手机·intellij-idea·excel
爱喝水的小周1 小时前
实验十 Vue‑Router 王者荣耀战绩查询 APP 开发实践
前端·javascript·vue.js
yexianglunbai1 小时前
Vue 3 全面详解:从核心特性到工程化实践
前端·javascript·vue.js