这几天公司有一个要结合高德地图的智慧园区的项目(大致就是在3d地图中加载自己的three.js模型)
1.首先要引入高德地图
官方文档给出来的引用方法
<template>
<div id="container"></div>
</template>
<script>
import AMapLoader from "@amap/amap-jsapi-loader";
export default {
data() {
return {
map: null,
};
},
mounted() {
//DOM初始化完成进行地图初始化
this.initMap();
},
methods: {
initMap() {
AMapLoader.load({
key: "", // 申请好的Web端开发者Key,首次调用 load 时必填
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [""], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
})
.then((AMap) => {
this.map = new AMap.Map("container", {
//设置地图容器id
viewMode: "3D", //是否为3D地图模式
zoom: 5, //初始化地图级别
center: [105.602725, 37.076636], //初始化地图中心点位置
});
})
.catch((e) => {
console.log(e);
});
},
},
};
</script>
<style scoped>
#container {
padding: 0px;
margin: 0px;
width: 100%;
height: 800px;
}
</style>
因为新的key中增加了秘钥(不加载的话,我们的自定义地图无法加载)
created() {
window._AMapSecurityConfig = {
securityJsCode:"",//初始化时加载秘钥
};
},
2.接下来就是加载three.js了(这就是封装完成的组件)
<template>
<!-- 高德地图加载器 -->
<div class="geomap" ref="geomap" id="container"></div>
</template>
<script>
import * as THREE from "three"; //三维
import AMapLoader from "@amap/amap-jsapi-loader"; //高德地图
export default {
name: "geomap", //高德地图加载器
props: {
// 传入要获取的地图信息
AMapinfo: {
type: [Object],
default: () => {
return {
version: "2.0", // 指定要加载的 JSAPI 的版本,缺省时默认为 1.4.15
plugins: [], // 需要使用的的插件列表,如比例尺'AMap.Scale'等
amap: {
rotateEnable: false, //控制地图是否可以旋转
pitchEnable: false, //控制地图是否可以倾斜
pitch: 65, //初始化角度
viewMode: "3D", //是否为3D地图模式
zoom: 20, //初始化地图级别
center: [121.187344, 31.46736], //初始化地图中心点位置
mapStyle: "amap://styles/id", //初始化地图样式
},
};
},
},
// 传入模型函数
initLoader: {
type: [Function],
},
// 传入光源数组
lightlist: {
type: [Array],
default: () => {
return [
{
type: "AmbientLight", //光的类型
color: 0xffffff, //光的颜色
intensity: 1, //光照强度
posiy: [0, 0, 0], //光照位置
},
];
},
},
},
data() {
return {
map: null, //地图对象
scene: null, //场景对象Scene
camera: null, //相机对象
render: null, //渲染器对象
isclick: null, //判断鼠标状态
customCoords: null, //初始化数据转换工具
security: "", // 初始化时加载秘钥
key: "", // 申请好的Web端开发者Key,首次调用 load 时必填
gllayer: null, //three数据
isadd: false, //是否添加
aminonte: true,
};
},
created() {
window._AMapSecurityConfig = {
securityJsCode: this.security,
};
},
mounted() {
// 初始化地图数据
this.initMap();
},
methods: {
// 添加全局方法
addmeth() {
// 设置在什么缩放比例的时候隐藏
this.map.on("zoomend", () => {
if (this.map.getZoom() < 16.9) {
this.map.remove(this.gllayer);
this.isadd = true;
} else {
if (this.isadd) {
this.map.add(this.gllayer);
this.isadd = false;
}
}
});
// 监听窗口尺寸变化
window.addEventListener("resize", this.changeSize, false);
// 监听鼠标按下
window.addEventListener("mousedown", this.mouseDown, false);
// 监听鼠标移动
window.addEventListener("mousemove", this.mouseMove, false);
// 监听鼠标弹起
window.addEventListener("mouseup", this.mouseUp, false);
},
// 添加3d
addthree() {
// 初始化数据转换工具
this.customCoords = this.map.customCoords;
// 经纬度数据转换
this.customCoords.lngLatsToCoords([this.AMapinfo.amap.center]);
// 引入three图层
this.gllayer = new AMap.GLCustomLayer({
// 图层的层级c
zIndex: 2000,
// 初始化的操作,创建图层过程中执行一次。
init: (gl) => {
this.render = new THREE.WebGLRenderer({
context: gl, // 地图的 gl 上下文
alpha: true,
});
// 初始化场景对象
this.initScene();
// 初始化模型
this.initLoader();
// 初始化光源
this.initLight();
// 初始化相机
this.initCamera();
// 自动清空画布这里必须设置为 false,否则地图底图将无法显示
// 这里我们的地图模式是 3D,所以创建一个透视相机,
// 相机的参数初始化可以随意设置,因为在 render 函数中,每一帧都需要同步相机参数,
//因此这里变得不那么重要。
// 如果你需要 2D 地图(viewMode: '2D'),那么你需要创建一个正交相机
// 环境光照和平行光
this.render.autoClear = false;
},
render: () => {
this.renderer();
},
});
// 把three图层引入地图
this.map.add(this.gllayer);
// 渲染图层
this.animate();
// 设置动画
this.tweenUpdate();
},
// 监听鼠标按下
mouseDown(event) {
this.isclick = {
clientX: event.clientX,
clientY: event.clientY,
};
},
// 监听鼠标移动
mouseMove(event) {
this.aminonte = false;
if (!this.isclick) {
if (this.$refs.geomap) {
var list = this.countmouse(event);
if (list.length > 0) {
// 传出鼠标移动事件
this.$emit("change", "move", list);
}
}
}
},
// 监听鼠标弹起
mouseUp(event) {
// 如果相等说明是点击事件
if (
(this.isclick.clientX === event.clientX) &
(this.isclick.clientY === event.clientY)
) {
// 传出点击事件
this.isclick = null;
if (this.$refs.geomap) {
var list = this.countmouse(event);
if (list.length > 0) {
this.$emit("change", "click", list);
}
}
} else {
this.isclick = null;
}
},
// 判断当前点击的事件
countmouse(event) {
let raycaster = new THREE.Raycaster();
let mouse = new THREE.Vector2();
//将鼠标点击位置的屏幕坐标转换成threejs中的标准坐标
var dom = this.$refs.geomap.getBoundingClientRect();
if (
event.clientX >= dom.left &&
event.clientY >= dom.top &&
event.clientX <= dom.left + this.$refs.geomap.offsetWidth &&
event.clientY <= dom.top + this.$refs.geomap.offsetHeight
) {
mouse.x = (event.clientX / this.$refs.geomap.offsetWidth) * 2 - 1;
mouse.y = -(event.clientY / this.$refs.geomap.offsetHeight) * 2 + 1;
// 通过鼠标点的位置和当前相机的矩阵计算出raycaster
raycaster.setFromCamera(mouse, this.camera);
// 获取raycaster直线和所有模型相交的数组集合
var list = raycaster.intersectObjects(this.scene.children, true);
if (list.length > 0) {
return list;
} else {
return [];
}
} else {
return [];
}
},
// 监听尺寸变化
changeSize() {
//窗口宽高比
var k = this.$refs.geomap.offsetWidth / this.$refs.geomap.offsetHeight;
this.camera.aspect = k;
this.camera.updateProjectionMatrix();
},
// 初始化地图数据
initMap() {
AMapLoader.load({
key: this.key,
version: this.AMapinfo.version,
plugins: this.AMapinfo.plugins,
})
.then((AMap) => {
// 初始化地图
this.map = new AMap.Map("container", this.AMapinfo.amap);
// 监听事件
this.addmeth();
// 添加动画
this.addthree();
})
.catch((e) => {
this.$message.error(e);
});
},
// 初始化场景对象
initScene() {
// 初始化场景
this.scene = new THREE.Scene();
// 旋转场景
this.scene.rotation.x = (Math.PI / 180) * 90;
this.scene.rotation.y = (Math.PI / 180) * -58;
this.scene.scale.set(1.18, 1.18, 1.18);
// 创建三维坐标系
var axesHelper = new THREE.AxesHelper(100);
this.scene.add(axesHelper);
},
// 初始化光源
initLight() {
// 遍历添加光源
this.lightlist.forEach((item) => {
var light = new THREE[item.type](item.color, item.intensity);
light.position.set(item.posiy[0], item.posiy[1], item.posiy[2]); //点光源位置
if (item.type === "DirectionalLight") {
}
this.scene.add(light);
});
},
// 初始化相机
initCamera() {
this.camera = new THREE.PerspectiveCamera(
60,
this.$refs.geomap.offsetWidth / this.$refs.geomap.offsetHeight,
100,
1 << 30
);
},
// 渲染器对象
renderer() {
// 这里必须执行!!重新设置 three 的 gl 上下文状态。
this.render.state.reset();
var { near, far, fov, up, lookAt, position } =
this.customCoords.getCameraParams();
// 2D 地图下使用的正交相机
// 这里的顺序不能颠倒,否则可能会出现绘制卡顿的效果。
this.camera.near = near;
this.camera.far = far;
this.camera.fov = fov;
this.camera.position.set(...position);
this.camera.up.set(...up);
this.camera.lookAt(...lookAt);
this.camera.updateProjectionMatrix();
// 2D 地图使用的正交相机参数赋值
// this.camera.top = top;
// this.camera.bottom = bottom;
// this.camera.left = left;
// this.camera.right = right;
// this.camera.position.set(...position);
// this.camera.updateProjectionMatrix();
this.render.render(this.scene, this.camera);
},
// 动画
animate() {
// 渲染时刷新地图
this.map.render();
// 添加了一个旋转地图的动画
if (this.aminonte) {
var totation = this.map.getRotation();
// -360 - 360 范围
// 在-180的时候重置为180 (aminonte是停止一下动画的
if (totation > -180) {
this.map.setRotation((totation - 0.2) % 360, true);
} else if (totation <= -180) {
this.aminonte = false;
this.map.setRotation(180, true);
this.aminonte = true;
}
}
// 自动刷新
requestAnimationFrame(this.animate);
},
// 设置动画
tweenUpdate() {
requestAnimationFrame(this.tweenUpdate);
this.$tweener.update();
},
// 运动动画
tweenobj(object, y) {
this.$tween.fade(
object.position,
{
x: object.position.x,
y: object.position.y + y,
z: object.position.z,
},
1000,
0,
this.$tweener.Easing.Cubic.InOut
);
},
},
};
</script>
<style lang="less" scoped>
// 高德地图加载器
.geomap {
width: 100%;
height: 100%;
color: transparent;
}
</style>
这里也是使用tween.js进行一些动画,只按照这篇文章的话可能缺少一些依赖
3.使用方法
使用的方法和我的另一篇文章一样,链接放下面了
vue中使用three.js加载各种模型文件(obj,mtl,fbx..)(封装
你可能缺少的依赖
//three依赖
npm i three 或者 yarn add three
//tween.js依赖
npm i @tweenjs/tween.js 或者 yarn add @tweenjs/tween.js
//obj,mtl 文件加载依赖
npm i three-obj-mtl-loader 或者 yarn add three-obj-mtl-loader
//高德地图
npm i @amap/amap-jsapi-loader 或者 yarn add @amap/amap-jsapi-loader
就是这样,下班!!!