基于Vue项目从零开始学ArcGIS(1),详细说明如何把ArcGIS引入项目基本使用

1,221 阅读7分钟

前言:

最近因为工作需要学习Arcgis Api For Javascript后面简称Arcgis,在网上找了很多文字资料和视频,发现ArcGIS教学要么是版本比较老的、要么是基于原生的教学,如果放到Vue框架上用法多少有点变化,并且官方文档还是全英文的综合下来确实有点杂。所以我整合多个学习资料学习的过程中,顺便搞个Vue3+ArcGIS的系列教程,到时偶尔更新一个效果小功能,除了在做笔记的过程中希望能有同行从中得到学习。

这一章节主要说说怎么把ArcGIS引入Vue项目并且基础使用,最后再实现一个如下图所示二三维地图联动的小功能。后续持续学习再继续更新内容和案例。

20240427191438_rec_.gif

一、Vue3引入ArcGIS安装

项目是基于Vue3的,我是随手架个空框架练手的,具体怎么架就不细说了,直接入正文。

(1)npm引入

npm install @arcgis/core
或者
yarn yarn add @arcgis/core

(2)挂载在项目

在main.js文件中引入样式

import '@arcgis/core/assets/esri/themes/light/main.css';

(3)页面引用

在使用到地图的地方引入必要的视图,如下三个最常用的

  • Map: 存放所有图层
  • MapView: 显示2D图层,并且图层的事件和配置都写在里面(即负责用户的交互)
  • SceneView: 显示3D视图,并且图层的事件和配置都写在里面(即负责用户的交互)
<script setup>

import Map from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView";
import SceneView from "@arcgis/core/views/SceneView";

</script>

二、最简单的地图展示

上面执行了引入安装的步骤,下面直接引入一个完整的地图效果。

大概思路是通过引入的new Map初始化一个视图,然后通过 new MapView去显示一个2D的图层,并且new MapView里面有各种当前地图配置属性,以下每一行代码都添加了注释其中核心配置在new MapView中,下面附带效果动图

20240428143338_rec_.gif

核心代码(1):先创建一个地图实例这个步骤是必需的,其中basemap属性是设置以什么形式的显示地图,例如下图这两种形式(更多去直接去官网查找这个属性看看有什么类型)

image.png

  mymap = new Map({
    basemap: "satellite", // 设置地图类型为标注影像混合切片
  });

核心代码(2):new MapView创建一个2D的地图,里面有各 种配置,但containermap是必需要有的。

myview = new MapView({
    container: "viewDiv", // 挂载在那个DOM
    map: mymap, // 绑定的map对象
    center: [113.5, 23.2], // 设置视图的中心点
    zoom: 8, // 设置视图初始的缩放级别
  });

结合出来完整的代码


<template>
  <main>
    <div id="viewDiv"></div>
  </main>
</template>

<script setup>
import { onMounted } from "vue";
import Map from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView";
/**
 * Map: 存放所有图层
 * MapView: 显示2D图层,并且图层的事件和配置都写在里面(即负责用户的交互)
 */

let mymap = null;
let myview = null;

onMounted(() => {
  initMap();
});
// 初始化地图
const initMap = () => {
  mymap = new Map({
    basemap: "satellite", // 设置地图类型为标注影像混合切片
  });

  myview = new MapView({
    container: "viewDiv", // 挂载在那个DOM
    map: mymap, // 绑定的map对象
    center: [113.5, 23.2], // 设置视图的中心点
    zoom: 8, // 设置视图初始的缩放级别
  });

  myview.ui.remove(["zoom", "attribution"]);  // 把缩放按钮去掉,和把底部的介绍去掉
};
</script>

<style scoped>
#viewDiv {
  width: 100%;
  height: 90vh;
}
</style>

三、实现一个二三维联动的小功能

简单解释:

1、先用new Mapnew MapView初始化一个2D地图,然后用new Mapnew SceneView初始化一个3D地图。

2、用一个中间属性active存放当前选中操作的地图,然后用view.watch监听地图当前是不是在交互(例如缩放和拖动),如果是就触发changeEvent方法把交互的内容同步到另一个地图实现联动。

3、第67行处的when方法: 作用是进入页面初始化完成的时候会自动执行里面的函数myview3.goTo, goTo即到达某个坐标或者默认的缩放大小

20240428145427_rec_.gif

核心代码(1): 先用new Mapnew MapView初始化一个2D地图,然后用new Mapnew SceneView初始化一个3D地图

// 这里2D
  mymap2 = new Map({
    basemap: "terrain", 
  });
  myview2 = new MapView({
    container: "view2", // 挂载在那个DOM
    map: mymap2, // 绑定的map对象
  });

// 这里3D
  mymap3 = new Map({
    basemap: "satellite", 
  });
  myview3 = new SceneView({
    container: "view3", // 挂载在那个DOM
    map: mymap3, // 绑定的map对象
  });

核心代码(2):用一个中间属性active存放当前选中操作的地图,然后用view.watch监听地图当前是不是在交互(例如缩放和拖动),如果是就触发changeEvent方法把交互的内容同步到另一个地图实现联动

// 用于存放当前正在操作的地图
  let active = null   
  // 遍历两种视图分别进行监听
  views = [myview2, myview3];
  
  for (const view of views) {
    /* 作用:监听视图是否正在与用户交互,例如拖动和旋转或者动画
    *  interacting:当前是否在跟用户交互是则返回true     animation:是否在执行动画效果
    */ 
    view.watch(["interacting", "animation"], () => {
      active = view; // 把本视图作为当前激活视图
      changeEvent(active); // 对当前执行视图执行sync方法
    });
    
    // 监听视点变化时不将本视图作为激活视图
    view.watch("viewpoint", () => {
      changeEvent(view);
    });
  }
  
   // 通过这个方法把正在发生变化的地图同步给别一个地图实现双方联动
 let changeEvent = (source) => {
    if (source !== active || !active || !active.viewpoint) {
      return;
    }
    for (const view of views) {
      // 将激活视图的中心点,传递给不激活的,从而实现联动
      if (view !== active) {
        view.viewpoint = active.viewpoint;
      }
    }
  };

核心代码(3):第67行处的when方法: 作用是进入页面初始化完成的时候会自动执行里面的函数myview3.goTo, goTo即到达某个坐标或者默认的缩放大小

注意:要放在上面两个核心代码步骤之后

 myview2.when(() => {
    myview3.goTo({
      target: [113.5, 23.2],
      zoom: 7,
    });
  });

结果出来小功能的完整代码

<template>
  <h3>二三维视图联动效果</h3>
  <div class="about">
    <div id="view2"></div>
    <div id="view3"></div>
  </div>
</template>

<script setup>
import { onMounted } from "vue";
import Map from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView";
import SceneView from "@arcgis/core/views/SceneView.js";

let 
  mymap2 = null,
  mymap3 = null,
  myview2 = null, // 展示2维视图
  myview3 = null, // 展示3维视图
  active, // 存放当前选中激活的视图
  views = [];


onMounted(() => {
  initMap();
});

// 初始化地图
const initMap = () => {
  mymap3 = new Map({
    basemap: "satellite", 
  });
  mymap2 = new Map({
    basemap: "terrain", 
  });

  // 2维视图的逻辑-------------------------------------------------------------------
  myview2 = new MapView({
    container: "view2", // 挂载在那个DOM
    map: mymap2, // 绑定的map对象
  });


  // 3维视图的逻辑--------------------------------------------------------------------------
  myview3 = new SceneView({
    container: "view3", // 挂载在那个DOM
    map: mymap3, // 绑定的map对象
  });


  // 遍历两种视图
  views = [myview2, myview3];
  for (const view of views) {
    // 监听视图是否正在与用户交互,例如拖动和旋转或者动画
    // interacting:当前是否在跟用户交互是则返回true     animation:是否在执行动画效果
    view.watch(["interacting", "animation"], () => {
      active = view; // 把本视图作为当前激活视图
      changeEvent(active); // 对当前执行视图执行sync方法
    });
    // 监听视点变化时不将本视图作为激活视图
    view.watch("viewpoint", () => {
      changeEvent(view);
    });
  }

  //when方法: 进入页面初始化完成的时候会自动执行里面的函数myview3.goTo, goTo即到达某个坐标或者默认的缩放大小
  myview2.when(() => {
    myview3.goTo({
      target: [113.5, 23.2],
      zoom: 7,
    });
  });
};

  // 把激活的视图点动态传给未激活视图,实现实时联动
  // 如果当前存在激活视图,则执行下面语句
 let changeEvent = (source) => {
    if (source !== active || !active || !active.viewpoint) {
      return;
    }
    for (const view of views) {
      // 将激活视图的中心点,传递给不激活的,从而实现联动
      if (view !== active) {
        view.viewpoint = active.viewpoint;
      }
    }
  };
</script>

<style scoped>
.about {
  height: 80vh;
  display: flex;
  align-items: center;
  /* flex-direction: column; */
}
.about div:nth-child(1) {
  width: 50%;
  min-height: 80vh;
  /* border: 1px solid teal; */
}
.about div:nth-child(2) {
  width: 50%;
  min-height: 80vh;
  /* border: 1px solid teal; */
}
</style>

小结:

学了一下发现其实入门不难,但这个库有点庞大想要处处说到学到是不可能的,文档里面属性非常多而且还是纯英文的,所以通过各种功能事例去学习感觉比对照文档看一个个属性是干麻的效果会更好,ArcGIS经典的易学难精的一个东西。