在 Vue2 中引入高德地图和三维模型

  • 概述
  • 注册高德 web key
  • 在 Vue 中引入高德地图
  • 在 Vue 引入三维模型
    • 地图展示的配置
    • async、awiat 方式加载地图
    • 加载三维模型
  • 最终效果
  • 最终代码

概述

最近在做一个前端项目,需要在地图上引入一个三维模型,前端使用 Vue2,好在现在都有功能丰富的地图 API 供开发者调用(腾讯地图、百度地图、高德地图等等),在此项目中我们采用高德开放平台提供的 API,但是在引入三维模型遇到了各种问题,在这里把引入三维模型所遇到的问题和实现流程做个汇总。

注册高德 web key

网址:高德开发平台

登陆成功后,我们进入应用管理注册我们的应用,如下:

创建完应用后,我们添加服务,在服务中我们选择 Web 端(JS API) ,高德的大部分 API 都在这里,添加完毕后我们能获取到一个 key,后续需在 Vue2 中使用。

至此,高德部分的应用注册完成,为了专注于如何引入三维模型,在这里我使用 vue-cli 创建一个空白项目来引入高德地图。

首先这里默认你已经有了自己的 vue2 项目,不过多阐述 vue2 项目的创建

在 Vue 中引入高德地图

打开高德开放的文档,很容易找到我们需要找的 api 文档,如下:

高德开放平台 Web 端 API 文档

跟着高德开放平台的在 Vue 中引入高德地图步骤:

  1. 安装高德插件

    npm i @amap/amap-jsapi-loader --save
    
  2. 在 script 最上方引入高德的 API

    import AMapLoader from '@amap/amap-jsapi-loader';
    
  3. methods 中添加初始化地图的方法,并在 mounted 周期回调中调用方法

    mounted() {this.initMap()
    },
    methods: {initMap() {AMapLoader.load({key: "", // 申请好的Web端开发者Key,首次调用 load 时必填version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: [""], // 需要使用的的插件列表,如比例尺'AMap.Scale'等}).then((AMap) => {this.map = new AMap.Map("container", {//设置地图容器idviewMode: "3D", //是否为3D地图模式zoom: 5, //初始化地图级别center: [105.602725, 37.076636], //初始化地图中心点位置});}).catch((e) => {console.log(e);});},
    }
    
  4. 添加 css 和 html 代码

  5. 完整代码

    请在 key 中填写前面注册的 key

    <template><div id="app"><div id="container"></div></div>
    </template><script>
    import AMapLoader from "@amap/amap-jsapi-loader";
    export default {name: "App",data() {return {map: null,};},mounted() {this.initMap()},methods: {initMap() {AMapLoader.load({key: "xxxxxxxxxxxxxxxxxxxxxx", // 申请好的Web端开发者Key,首次调用 load 时必填version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: [""], // 需要使用的的插件列表,如比例尺'AMap.Scale'等}).then((AMap) => {this.map = new AMap.Map("container", {//设置地图容器idviewMode: "3D", //是否为3D地图模式zoom: 5, //初始化地图级别center: [105.602725, 37.076636], //初始化地图中心点位置});}).catch((e) => {console.log(e);});},}
    };
    </script><style>
    #app {margin: 0;padding: 0;
    }
    #container {padding: 0px;margin: 0px;width: 100%;height: 100vh;
    }
    </style>
    

在 Vue 引入三维模型

先在高德查找相关文档,好在高德是提供了一个原生的 html 中引入三维模型的方式

那么现在就是要解决 html 代码向 Vue 代码的转化

我们先分析哪部分代码是核心代码,我们很容易找到加载地图和加载模型两个部分是核心代码:

你可能不知道中间的 AMap.Lights 是干嘛的,我们可以借助它提供的实时运行代码的方式发现,就是模型的光线,在这里存在第一个坑,在后面解决这个坑。

地图展示的配置

我们先来看上图第一个框中的 map 对象,它创建了一个 map 实例,我们把这部分搬到之前初始化代码的地方

效果如下:

async、awiat 方式加载地图

我们回到高德示例,如下图,发现我们需要 new AMap 对象上的各种属性,为了方便后续使用,我们需要将高德初始化后的 AMap 保存在 data 中,但官方给我们 Vue 引入高德的示例是基于 Promise 的,Promise 采用异步编程,所以在 then 中接收参数是不能在同一个函数中的 then 方法以外使用的,此时我们需要修改代码,使用 async 和 await 的方式。

data() 中创建变量,我这里取名为 AMaper,并且修改代码为 async 和 await 模式,如下:

<script>
import AMapLoader from "@amap/amap-jsapi-loader";
export default {name: "App",data() {return {map: null,AMaper: null};},mounted() {this.initMap()},methods: {// 使用 async、await 修改代码async initMap() {try {this.AMaper = await AMapLoader.load({key: "54349c69d7f32d086f7e4110c2889090",version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15plugins: [""], // 需要使用的的插件列表,如比例尺'AMap.Scale'等})this.map = new this.AMaper.Map("container", {viewMode:'3D',showBuildingBlock:false,center:[116.472605,39.992075],pitch:55,zoom:17});} catch (e) {// 初始化失败的异常捕获console.log(e)}}}
};
</script>

接下去对示例代码的 Lights 光效部分加入 Vue,在 initMap() 的 try 代码 最后加入下面代码光效:

// 初始化光线
this.map.AmbientLight = new this.AMaper.Lights.AmbientLight([1,1,1],1);
this.map.DirectionLight = new this.AMaper.Lights.DirectionLight([1,0,-0.5],[1,1,1],1);

检查控制台,发现报错 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘AmbientLight’)

这个错误肯定不陌生,当 this.AMaper.Lights 获取到的结果为 undefined 就获取不到后面的属性,则抛出这个异常,经过查看官方的文档,发现这个三维模型的实例代码是基于 1.x 的高德 API 版本,我们使用的 2.0 而且之前查看的文档也是 2.0 的文档,我们把 AMaperLoader.load() 中的 version: “2.0” 去除,默认就使用了 1.4.15 版本,报错解决,即删除下面框内代码:

加载三维模型

将示例的 loadModel 方法搬到 Vue 中,搬过来后能够发现各种问题:

Step1: 简单处理 map 和 AMap 问题,将它们改为我们 data 的对象即可,操作比较简单,首先我们发现了一个回调函数如下图,这种函数的写法有自己的函数作用域,我们无法通过 this 获取到 data 中的数据,最简单的做法是将其改为箭头函数。

修改后如下:

Step2: 导入 threejs 库,代码中很明显可以看到一个很红的波浪线 THREE,我们需要对其进行引入,先看看 npm 中有没有 three,那必然是有的,npm 的 threejs 链接。

  1. 在 Vue 安装 three

    npm install three
    
  2. 仿照官网在 Vue 组件中导入

  3. 保存代码,并且运行我们的项目,抛出警告

  4. 我们查看 node_modules 中的代码,在 loaders 目录下,并没有 OBJLoader2,查阅官方文档的加载 obj 模型部分,需要加入 OBJLoader,这个类可以用于加载三维模型文件,高德地图也是使用这个方法,只是高德使用的 three 版本比较旧,新版本中移除了 OBJLoader2,高德中还加入贴图 MTL 的渲染,我们需要对其引入 MTLLoader。

  5. 在上面官方文档链接,我们看看它是如何引入三维模型的,如下图,先载入贴图,再载入模型,那我们通过下面代码对高德示例代码进行修改。

  6. 分析高德示例代码的构成,如下图绿色注释部分

  7. 根据 threejs 官网的方式对高德代码进行重新布局,重写后的代码如下:

    loadModel() {new MTLLoader().load('https://a.amap.com/jsapi_demos/static/demo-center/model/1519/1519.mtl', /**贴图回调 */ function ( materials ) {// 回调中加载 obj 模型new OBJLoader().setMaterials(materials).load('https://a.amap.com/jsapi_demos/static/demo-center/model/1519/1519.obj', /**加载模型的回调 */ ( event ) => {var object3Dlayer = new this.AMaper.Object3DLayer();var meshes = event.detail.loaderRootNode.children;for(var i=0;i<meshes.length;i++){var vecticesF3 = meshes[i].geometry.attributes.position;var vecticesNormal3 = meshes[i].geometry.attributes.normal;var vecticesUV2 = meshes[i].geometry.attributes.uv;           var vectexCount =  vecticesF3.count;var mesh = new this.AMaper.Object3D.MeshAcceptLights();var geometry = mesh.geometry;var c,opacity;var material = meshes[i].material[0]||meshes[i].material;if(material.map)mesh.textures.push('https://a.amap.com/jsapi_demos/static/demo-center/model/1519/1519.bmp')          c = material.color;opacity = material.opacityfor(var j=0;j<vectexCount;j+=1){var s = j*3;geometry.vertices.push(vecticesF3.array[s],vecticesF3.array[s+2],-vecticesF3.array[s+1]);           if(vecticesNormal3) {geometry.vertexNormals.push(vecticesNormal3.array[s],vecticesNormal3.array[s+2],-vecticesNormal3.array[s+1]);}if(vecticesUV2) {geometry.vertexUVs.push(vecticesUV2.array[j*2],1-vecticesUV2.array[j*2+1]);}geometry.vertexColors.push(c.r,c.g,c.b,opacity)}mesh.DEPTH_TEST = material.depthTestmesh.transparent = opacity<1;mesh.scale(6,6,6)mesh.rotateZ(-48)mesh.position(new this.AMaper.LngLat(116.472605,39.992075))object3Dlayer.add(mesh)}      this.map.add(object3Dlayer)})})
    }
    
  8. mounted 生命钩子中调用加载模型的方法,运行后,控制台报错 TypeError: Cannot read properties of undefined (reading ‘AMaper’)

    问题也很简单,为什么 AMaper 没有定义,我们仔细看上面代码,这个报错来自 加载模型的回调 ,因为这个回调使用箭头函数,this 指向它的上层作用域,上层作用域是一个函数,有自己的作用域,所以我们只需把上一层回调函数改为箭头函数即可。

  9. 如果出现以下报错:TypeError: Cannot read properties of null (reading ‘Object3DLayer’)

    原因是因为我们没有获取到 AMaper 对象,这个对象来自地图的加载,在 mounted 钩子中加载地图时,还没加载完成就进入了模型加载,所以我们需要对 mounted 钩子做如下更改,这样会强行使 initMap 完成才会进入 loadModel

  10. 因为我们使用的 threejs 和高德示例的版本有出入,会出现以下错误:TypeError: Cannot read properties of undefined (reading ‘loaderRootNode’)

    采用最简单粗暴的方式,在控制台输出 event 对象,我们发现新版本中直接将 children 提到对象的最外面,如下:

    修改原来的代码,如下:

最终效果

最终代码

<template><div id="app"><div id="container"></div></div>
</template><script>
import AMapLoader from "@amap/amap-jsapi-loader";
import { OBJLoader } from 'three/examples/jsm/loaders/OBJLoader';
import { MTLLoader } from 'three/examples/jsm/loaders/MTLLoader';
export default {name: "App",data() {return {map: null,AMaper: null};},async mounted() {await this.initMap()this.loadModel()},methods: {async initMap() {try {this.AMaper = await AMapLoader.load({// 这里写你的 web keykey: "xxxxxxxxxxxxxxxxxxxx",plugins: [""],})this.map = new this.AMaper.Map("container", {viewMode:'3D',showBuildingBlock:false,center:[116.472605,39.992075],pitch:55,zoom:17});// 初始化光线this.map.AmbientLight = new this.AMaper.Lights.AmbientLight([1,1,1],1);this.map.DirectionLight = new this.AMaper.Lights.DirectionLight([1,0,-0.5],[1,1,1],1);} catch (e) {console.log(e)}},loadModel() {new MTLLoader().load('https://a.amap.com/jsapi_demos/static/demo-center/model/1519/1519.mtl', /**贴图回调 */ ( materials ) => {// 回调中加载 obj 模型new OBJLoader().setMaterials(materials).load('https://a.amap.com/jsapi_demos/static/demo-center/model/1519/1519.obj', /**加载模型的回调 */ ( event ) => {var object3Dlayer = new this.AMaper.Object3DLayer();var meshes = event.children;for(var i=0;i<meshes.length;i++){var vecticesF3 = meshes[i].geometry.attributes.position;var vecticesNormal3 = meshes[i].geometry.attributes.normal;var vecticesUV2 = meshes[i].geometry.attributes.uv;           var vectexCount =  vecticesF3.count;var mesh = new this.AMaper.Object3D.MeshAcceptLights();var geometry = mesh.geometry;var c,opacity;var material = meshes[i].material[0]||meshes[i].material;if(material.map)mesh.textures.push('https://a.amap.com/jsapi_demos/static/demo-center/model/1519/1519.bmp')          c = material.color;opacity = material.opacityfor(var j=0;j<vectexCount;j+=1){var s = j*3;geometry.vertices.push(vecticesF3.array[s],vecticesF3.array[s+2],-vecticesF3.array[s+1]);           if(vecticesNormal3) {geometry.vertexNormals.push(vecticesNormal3.array[s],vecticesNormal3.array[s+2],-vecticesNormal3.array[s+1]);}if(vecticesUV2) {geometry.vertexUVs.push(vecticesUV2.array[j*2],1-vecticesUV2.array[j*2+1]);}geometry.vertexColors.push(c.r,c.g,c.b,opacity)}mesh.DEPTH_TEST = material.depthTestmesh.transparent = opacity<1;mesh.scale(6,6,6)mesh.rotateZ(-48)mesh.position(new this.AMaper.LngLat(116.472605,39.992075))object3Dlayer.add(mesh)}       this.map.add(object3Dlayer)})})}}
};
</script><style>
#container {padding: 0px;margin: 0px;width: 100%;height: 100vh;
}
</style>

在 Vue2 中引入高德地图和三维模型相关推荐

  1. 在vue中引入高德地图

    既然要用到高德地图首先要申请成为高德地图开发者,并申请使用高德地图的key这两点在这篇文章就不过多赘述,有需要的小伙伴可以查查资料,或者去高德地图api官网都有很详细的介绍.高德地图官网 简单提一下申 ...

  2. vue中引入高德地图Loca数据可视化

    目录 引言: 关键词: 正文: 一.如何安装或者引入: 二.如何引入: 三.如何使用: 四.完整代码: 五.效果图 参考: 引言: 前面我的文章介绍了vue中引入高德地图实例的,详情可以去参考,由于需 ...

  3. 在vue项目中引入高德地图并使用

    1.高德地图使用准备 开发之前的准备 需要注册账号, 创建应用, 创建 api key 调用地图的时候, 请求上带的 key 像高德地图服务器校验权限, 另外可以用来标识同一个程序的不同入口, 如网页 ...

  4. vue中引入高德地图

    ❤️❤️❤️ Topology可视化绘图引擎 ❤️❤️❤️ 总的来说,vue组件中使用高德地图的方式有两种,一种是vue-amap :一套专门用于vue的高德地图插件:另外一种是原生的高德地图. 方式 ...

  5. HTML 文件中引入高德地图

    准备工作: 1.在高德开放平台,注册开发者账号: 2.登陆之后,进入"应用管理",点击"我的应用",选择右上角"创建新应用": 3.为应用添 ...

  6. 在vue项目中引入高德地图及其UI组件的方法

    https://www.jb51.net/article/146789.htm 转载于:https://www.cnblogs.com/sweeeper/p/11282700.html

  7. Vue2项目使用高德地图

    目录 一.账号准备 1.注册账号 2.获取key 二.快速上手 1.安装 2.创建地图 3.点标记 4.海量点标记 5.简易行政区图 6. GeoJSON 三.绑定事件 总结 一.账号准备 1.注册账 ...

  8. vue+element中引入百度地图

    ❤️❤️❤️ Topology可视化绘图引擎 ❤️❤️❤️ 前言: 您好,我是csdn-尔嵘,如果您需要雨伞,可以去TaoBao搜:华,诚,荣,邦,百,货  谢谢您的支持! 1.首先你需要下载npm模 ...

  9. vue 高德地图标记_vue-element-admin 引入高德地图并做海量点标记

    第一步: 首先在index.html入口文件中添加引入高德地图的js,并填写自己在官网申请的key.如果没有申请不填写也是可以的. plugin:项目中如果有需要引入插件则使用没有直接去掉就行. 第二 ...

  10. react 逆地理 高德地图_react中使用高德地图的原生API

    干货,无话 1.react-create-app,创建新react项目: 2.npm install react-amap,引入高德地图的封装: 3.编写组件index.js: import Reac ...

最新文章

  1. linux进程--进程组、会话、守护进程(八)
  2. 用户 'sa' 登录失败。原因: 未与信任 SQL Server 连接相关联
  3. [GXOI/GZOI2019]旧词——树链剖分+线段树
  4. MFC中打开文件对话框:CFileDlg
  5. UIView封装动画--iOS利用系统提供方法来做关键帧动画
  6. cad布局打印出图-01-模型空间打印
  7. [转载] python中的bin()方法
  8. html内容写入txt文件内容,写入内容到文件里面 - FileWriter《 HTML5:文件系统 》
  9. NYOJ759 你知道这个规律吗
  10. ODBC连接达梦数据库配置
  11. 研究生硕士论文开题报告中的进度和安排该怎么写?
  12. Mac软件打开时闪退怎么办?苹果电脑软件崩溃解决办法
  13. hadoop学习之路(5)
  14. 网络钓鱼攻击技术分析及防范
  15. DW1000开发笔记(一)DW1000芯片概览
  16. 软件测试之项目实战,必须知道的事与测试面试项目测试流程......
  17. python elasticsearch bulk_关于ElasticSearch Bulk的用法
  18. 【COCOS2DX-游戏开发之二四】 quick-cocos2dx
  19. php上传txt文件读取乱码
  20. 思博伦Landslide CORE帮助UQ现网测试

热门文章

  1. 关于FileOpen2插件安装apk时闪退的解决办法
  2. 【SAS BASE】SAS格式、缺失值表示、命名规则及路径
  3. C2872 “detail”: 不明确的符号
  4. 也就整了一万字的「数据指标体系」指南。
  5. 亚马逊买家多账号如何运行管理?
  6. 纯HTML+js实现鼠标滚轮动态调整缩放图片大小
  7. 怎么把QQ音乐里wav格式转换成MP3
  8. 图片转excel软件有哪些?这些软件你值得拥有
  9. 【题解】LuoGu5369:[PKUSC2018]最大前缀和
  10. 以什么样的模式和方式来解决问题或创造价值?