在 Vue2 中引入高德地图和三维模型
在 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 中引入高德地图步骤:
安装高德插件
npm i @amap/amap-jsapi-loader --save
在 script 最上方引入高德的 API
import AMapLoader from '@amap/amap-jsapi-loader';
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);});}, }
添加 css 和 html 代码
完整代码
请在 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 链接。
在 Vue 安装 three
npm install three
仿照官网在 Vue 组件中导入
保存代码,并且运行我们的项目,抛出警告
我们查看 node_modules 中的代码,在 loaders 目录下,并没有 OBJLoader2,查阅官方文档的加载 obj 模型部分,需要加入 OBJLoader,这个类可以用于加载三维模型文件,高德地图也是使用这个方法,只是高德使用的 three 版本比较旧,新版本中移除了 OBJLoader2,高德中还加入贴图 MTL 的渲染,我们需要对其引入 MTLLoader。
在上面官方文档链接,我们看看它是如何引入三维模型的,如下图,先载入贴图,再载入模型,那我们通过下面代码对高德示例代码进行修改。
分析高德示例代码的构成,如下图绿色注释部分
根据 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)})}) }
在
mounted
生命钩子中调用加载模型的方法,运行后,控制台报错 TypeError: Cannot read properties of undefined (reading ‘AMaper’)问题也很简单,为什么 AMaper 没有定义,我们仔细看上面代码,这个报错来自
加载模型的回调
,因为这个回调使用箭头函数,this 指向它的上层作用域,上层作用域是一个函数,有自己的作用域,所以我们只需把上一层回调函数改为箭头函数即可。如果出现以下报错:TypeError: Cannot read properties of null (reading ‘Object3DLayer’)
原因是因为我们没有获取到 AMaper 对象,这个对象来自地图的加载,在 mounted 钩子中加载地图时,还没加载完成就进入了模型加载,所以我们需要对 mounted 钩子做如下更改,这样会强行使
initMap
完成才会进入loadModel
:因为我们使用的 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 中引入高德地图和三维模型相关推荐
- 在vue中引入高德地图
既然要用到高德地图首先要申请成为高德地图开发者,并申请使用高德地图的key这两点在这篇文章就不过多赘述,有需要的小伙伴可以查查资料,或者去高德地图api官网都有很详细的介绍.高德地图官网 简单提一下申 ...
- vue中引入高德地图Loca数据可视化
目录 引言: 关键词: 正文: 一.如何安装或者引入: 二.如何引入: 三.如何使用: 四.完整代码: 五.效果图 参考: 引言: 前面我的文章介绍了vue中引入高德地图实例的,详情可以去参考,由于需 ...
- 在vue项目中引入高德地图并使用
1.高德地图使用准备 开发之前的准备 需要注册账号, 创建应用, 创建 api key 调用地图的时候, 请求上带的 key 像高德地图服务器校验权限, 另外可以用来标识同一个程序的不同入口, 如网页 ...
- vue中引入高德地图
❤️❤️❤️ Topology可视化绘图引擎 ❤️❤️❤️ 总的来说,vue组件中使用高德地图的方式有两种,一种是vue-amap :一套专门用于vue的高德地图插件:另外一种是原生的高德地图. 方式 ...
- HTML 文件中引入高德地图
准备工作: 1.在高德开放平台,注册开发者账号: 2.登陆之后,进入"应用管理",点击"我的应用",选择右上角"创建新应用": 3.为应用添 ...
- 在vue项目中引入高德地图及其UI组件的方法
https://www.jb51.net/article/146789.htm 转载于:https://www.cnblogs.com/sweeeper/p/11282700.html
- Vue2项目使用高德地图
目录 一.账号准备 1.注册账号 2.获取key 二.快速上手 1.安装 2.创建地图 3.点标记 4.海量点标记 5.简易行政区图 6. GeoJSON 三.绑定事件 总结 一.账号准备 1.注册账 ...
- vue+element中引入百度地图
❤️❤️❤️ Topology可视化绘图引擎 ❤️❤️❤️ 前言: 您好,我是csdn-尔嵘,如果您需要雨伞,可以去TaoBao搜:华,诚,荣,邦,百,货 谢谢您的支持! 1.首先你需要下载npm模 ...
- vue 高德地图标记_vue-element-admin 引入高德地图并做海量点标记
第一步: 首先在index.html入口文件中添加引入高德地图的js,并填写自己在官网申请的key.如果没有申请不填写也是可以的. plugin:项目中如果有需要引入插件则使用没有直接去掉就行. 第二 ...
- react 逆地理 高德地图_react中使用高德地图的原生API
干货,无话 1.react-create-app,创建新react项目: 2.npm install react-amap,引入高德地图的封装: 3.编写组件index.js: import Reac ...
最新文章
- linux进程--进程组、会话、守护进程(八)
- 用户 'sa' 登录失败。原因: 未与信任 SQL Server 连接相关联
- [GXOI/GZOI2019]旧词——树链剖分+线段树
- MFC中打开文件对话框:CFileDlg
- UIView封装动画--iOS利用系统提供方法来做关键帧动画
- cad布局打印出图-01-模型空间打印
- [转载] python中的bin()方法
- html内容写入txt文件内容,写入内容到文件里面 - FileWriter《 HTML5:文件系统 》
- NYOJ759 你知道这个规律吗
- ODBC连接达梦数据库配置
- 研究生硕士论文开题报告中的进度和安排该怎么写?
- Mac软件打开时闪退怎么办?苹果电脑软件崩溃解决办法
- hadoop学习之路(5)
- 网络钓鱼攻击技术分析及防范
- DW1000开发笔记(一)DW1000芯片概览
- 软件测试之项目实战,必须知道的事与测试面试项目测试流程......
- python elasticsearch bulk_关于ElasticSearch Bulk的用法
- 【COCOS2DX-游戏开发之二四】 quick-cocos2dx
- php上传txt文件读取乱码
- 思博伦Landslide CORE帮助UQ现网测试