从零开始Vue项目中使用MapboxGL开发三维地图教程(七)创建一个自动旋转的地球、添加一个3D模型、实现在两个地图之间滑动和同步来比较两个地图

news2024/11/18 14:53:38

目录

      • 1、创建一个自动旋转的地球地图
      • 2、添加一个3D模型
      • 3、一个页面创建两个底图之间滑动

1、创建一个自动旋转的地球地图

实现功能:地球仪和camera动画结合在一起,创建旋转行星效果。

实现思路:通过在动画结束时调用easeTo,旋转动画将无限期地继续。旋转在用户交互时暂停,并且在高缩放级别时减慢到停止。

首先在dom中添加一个button:

<button id="btn-spin">Pause rotation</button>

实现代码:

map.on('style.load', () => {
					map.setFog({}); // Set the default atmosphere style
				});

				// The following values can be changed to control rotation speed:

				// At low zooms, complete a revolution every two minutes.
				const secondsPerRevolution = 120;
				// Above zoom level 5, do not rotate.
				const maxSpinZoom = 5;
				// Rotate at intermediate speeds between zoom levels 3 and 5.
				const slowSpinZoom = 3;

				let userInteracting = false;
				let spinEnabled = true;

				function spinGlobe() {
					const zoom = map.getZoom();
					if (spinEnabled && !userInteracting && zoom < maxSpinZoom) {
						let distancePerSecond = 360 / secondsPerRevolution;
						if (zoom >
							slowSpinZoom) {
							// Slow spinning at higher zooms
							const zoomDif =
								(maxSpinZoom - zoom) / (maxSpinZoom - slowSpinZoom);
							distancePerSecond *= zoomDif;
						}
						const center = map.getCenter();
						center.lng -= distancePerSecond;
						// Smoothly animate the map over one second.
						// When this animation is complete, it calls a 'moveend' event.
						map.easeTo({
							center,
							duration: 1000,
							easing: (n) => n
						});
					}
				}

				// Pause spinning on interaction
				map.on('mousedown', () => {
					userInteracting = true;
				});

				// Restart spinning the globe when interaction is complete
				map.on('mouseup', () => {
					userInteracting = false;
					spinGlobe();
				});

				// These events account for cases where the mouse has moved
				// off the map, so 'mouseup' will not be fired.
				map.on('dragend', () => {
					userInteracting = false;
					spinGlobe();
				});
				map.on('pitchend', () => {
					userInteracting = false;
					spinGlobe();
				});
				map.on('rotateend', () => {
					userInteracting = false;
					spinGlobe();
				});

				// When animation is complete, start spinning if there is no ongoing interaction
				map.on('moveend', () => {
					spinGlobe();
				});

				document.getElementById('btn-spin').addEventListener('click', (e) => {
					spinEnabled = !spinEnabled;
					if (spinEnabled) {
						spinGlobe();
						e.target.innerHTML = 'Pause rotation';
					} else {
						map.stop(); // Immediately end ongoing animation
						e.target.innerHTML = 'Start rotation';
					}
				});

				spinGlobe();

效果展示:
在这里插入图片描述

2、添加一个3D模型

使用three.js,首先three.js安装到项目中:

# three.js
npm install --save three

在项目中引入:

	import * as THREE from 'three';
	import {
		GLTFLoader
	} from 'three/examples/jsm/loaders/GLTFLoader.js';

使用带有three.js的自定义样式层将三维模型添加到地图中:

// parameters to ensure the model is georeferenced correctly on the map
				const modelOrigin = [104.9819, 37.39847];
				const modelAltitude = 0;
				const modelRotate = [Math.PI / 2, 0, 0];

				const modelAsMercatorCoordinate = this.$mapboxgl.MercatorCoordinate.fromLngLat(
					modelOrigin,
					modelAltitude
				);

				// transformation parameters to position, rotate and scale the 3D model onto the map
				const modelTransform = {
					translateX: modelAsMercatorCoordinate.x,
					translateY: modelAsMercatorCoordinate.y,
					translateZ: modelAsMercatorCoordinate.z,
					rotateX: modelRotate[0],
					rotateY: modelRotate[1],
					rotateZ: modelRotate[2],
					/* Since the 3D model is in real world meters, a scale transform needs to be
					 * applied since the CustomLayerInterface expects units in MercatorCoordinates.
					 */
					scale: modelAsMercatorCoordinate.meterInMercatorCoordinateUnits()
				};

				// const THREE = window.THREE;

				// configuration of the custom layer for a 3D model per the CustomLayerInterface
				const customLayer = {
					id: '3d-model',
					type: 'custom',
					renderingMode: '3d',
					onAdd: function (map, gl) {
						this.camera = new THREE.Camera();
						this.scene = new THREE.Scene();

						// create two three.js lights to illuminate the model
						const directionalLight = new THREE.DirectionalLight(0xffffff);
						directionalLight.position.set(0, -70, 100).normalize();
						this.scene.add(directionalLight);

						const directionalLight2 = new THREE.DirectionalLight(0xffffff);
						directionalLight2.position.set(0, 70, 100).normalize();
						this.scene.add(directionalLight2);

						// use the three.js GLTF loader to add the 3D model to the three.js scene
						const loader = new GLTFLoader();
						loader.load(
							'https://docs.mapbox.com/mapbox-gl-js/assets/34M_17/34M_17.gltf',
							(gltf) => {
								this.scene.add(gltf.scene);
							}
						);
						this.map = map;

						// use the Mapbox GL JS map canvas for three.js
						this.renderer = new THREE.WebGLRenderer({
							canvas: map.getCanvas(),
							context: gl,
							antialias: true
						});

						this.renderer.autoClear = false;
					},
					render: function (gl, matrix) {
						const rotationX = new THREE.Matrix4().makeRotationAxis(
							new THREE.Vector3(1, 0, 0),
							modelTransform.rotateX
						);
						const rotationY = new THREE.Matrix4().makeRotationAxis(
							new THREE.Vector3(0, 1, 0),
							modelTransform.rotateY
						);
						const rotationZ = new THREE.Matrix4().makeRotationAxis(
							new THREE.Vector3(0, 0, 1),
							modelTransform.rotateZ
						);

						const m = new THREE.Matrix4().fromArray(matrix);
						const l = new THREE.Matrix4()
							.makeTranslation(
								modelTransform.translateX,
								modelTransform.translateY,
								modelTransform.translateZ
							)
							.scale(
								new THREE.Vector3(
									modelTransform.scale,
									-modelTransform.scale,
									modelTransform.scale
								)
							)
							.multiply(rotationX)
							.multiply(rotationY)
							.multiply(rotationZ);

						this.camera.projectionMatrix = m.multiply(l);
						// this.renderer.resetState();
						this.renderer.render(this.scene, this.camera);
						this.map.triggerRepaint();
					}
				};

				map.on('style.load', () => {
					map.addLayer(customLayer, 'waterway-label');
				});

上效果:
在这里插入图片描述

3、一个页面创建两个底图之间滑动

以通过左右滑动来比较两个地图

使用mapbox插件 mapbox-gl-compare
安装

npm i mapbox-gl-compare -D
npm i mapbox-gl-sync-move -D

导入

import mapboxgl from ‘mapbox-gl’
import Compare from ‘mapbox-gl-compare’

创建两个div:

<div id="comparison-container">
    <div id="before" class="map"></div>
    <div id="after" class="map"></div>
</div>

核心代码:

	mapboxgl.accessToken = 'xxxxxxx';
    const beforeMap = new mapboxgl.Map({
        container: 'before',
        // Choose from Mapbox's core styles, or make your own style with Mapbox Studio
        style: 'mapbox://styles/mapbox/streets-v12',
        center: [0, 0],
        zoom: 0
    });

    const afterMap = new mapboxgl.Map({
        container: 'after',
        style: 'mapbox://styles/mapbox/satellite-streets-v12',
        center: [0, 0],
        zoom: 0
    });

    // A selector or reference to HTML element
    const container = '#comparison-container';

    const map = new mapboxgl.Compare(beforeMap, afterMap, container, {
        // Set this to enable comparing two maps by mouse movement:
        // mousemove: true
    });

效果如下:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/660632.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软考A计划-网络工程师-IP,TCP,UDP,ICMP报头

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

YOLOv5/v7 添加注意力机制,30多种模块分析⑤,SOCA模块 ,SimAM模块

目录 一、注意力机制介绍1、什么是注意力机制&#xff1f;2、注意力机制的分类3、注意力机制的核心 二、SOCA模块1、SOCA模块的原理2、实验结果3、应用示例 三、SimAM模块1、SimAM模块的原理2、实验结果3、应用示例 大家好&#xff0c;我是哪吒。 &#x1f3c6;本文收录于&…

Vue 面试题

一、对于MVVM的理解&#xff1f; MVVM 是 Model-View-ViewModel 的缩写。 1、Model 代表数据模型&#xff0c;也可以在Model中定义数据修改和操作的业务逻辑。 2、View 代表UI 组件&#xff0c;它负责将数据模型转化成UI 展现出来。 3、ViewModel 监听模型数据的改变和控制…

【分布式系统】分布式唯一ID生成方案总结

目录 UUID实现 数据库生成IDsegment号段模式美团Leaf-segment号段模式Redis生成ID实现 zookeeper生成ID实现 snowflake雪花算法实现 Leaf-snowflake雪花算法百度UidGenerator滴滴TinyID双号段缓存多DB支持tinyid-client 参考 UUID 基本方法之一。 UUID(Universally Unique Id…

Java阿里巴巴代码规范

目录 1 编程规约1.1 方法参数类型必须一致&#xff0c;不要出现自动装箱拆箱操作1.1.1 反例1.1.2 正例 1.2 SimpleDateFormat是线程不安全的1.2.1 反例1.2.2 正例 1.3 使用equals方法应该注意空指针1.3.1 反例1.3.2 正例 2 异常日志2.1 事务场景中如果异常被被捕获要注意回滚2.…

2023 年最适用于工业物联网领域的三款开源 MQTT Broker

MQTT 最初作为一种轻量级的发布/订阅消息传递协议而设计&#xff0c;如今已经成为工业物联网&#xff08;IIoT&#xff09;和工业 4.0 发展的重要基础。它的意义在于实现了各类工业设备与云端的无缝连接&#xff0c;促进了运营技术&#xff08;OT&#xff09;和信息技术&#x…

MySQL----事物与存储引擎

文章目录 一、事务介绍1.1 MySQL 事务的概念1.2 事务的ACID特点原子性一致性隔离性持久性 1.3 事务之间的相互影响1.4 设置隔离级别1.5事务控制语句1.6使用 set 设置控制事务 二、存储引擎介绍2.1查看系统支持的存储引擎2.2 修改存储引擎2.3InnoDB行锁与索引的关系 一、事务介绍…

Windows VMware安装RockyLinux9

前言&#xff0c;今天用虚拟机安装rockyLinux时碰到了一些坑&#xff0c;要么时无法联网&#xff0c;要么是无法使用ssh链 接&#xff0c;在这里记录下 准备工作 1. VMware Workstation 17 Pro 2. RockyLinux9.2阿里镜像站&#xff0c;这里无选择了最小版本Rocky-9-latest-x86…

我的内网渗透-Empire模块的使用(宏病毒主要)

目录 stager模块&#xff08;payload&#xff09; 宏病毒 理解 在word中的设置 宏病毒代码 运行 保存 监听模块 提权模块 持久化模块 stager模块&#xff08;payload&#xff09; 常用的windows类型windows/launcher_bat #生成bat类型&#xff0c;还是可以用的。但…

GPT学习笔记-Enterprise Knowledge Retrieval(企业知识检索)--私有知识库的集成

openai-cookbook/apps/enterprise-knowledge-retrieval at main openai/openai-cookbook GitHub 终于看到对于我解决现有问题的例子代码&#xff0c;对于企业私有知识库的集成。 我对"Retrieval"重新理解了一下&#xff0c;源自动词"retrieve"&#xf…

【Matlab】LM迭代估计法

简介 在最近的传感器校准算法学习中&#xff0c;有一些非线性的代价函数求解使用最小二乘法很难求解&#xff0c;使用LM算法求解会简单许多&#xff0c;因此学习了一下LM算法的基础记录一下。 LM 优化迭代算法时一种非线性优化算法&#xff0c;可以看作是梯度下降与高斯牛顿法…

【linux kernel】linux media子系统分析之media控制器设备

文章目录 一、抽象媒体设备模型二、媒体设备三、Entity四、Interfaces五、Pad六、Link七、Media图遍历八、使用计数和电源处理九、link设置十、Pipeline和Media流十一、链接验证十二、媒体控制器设备的分配器API 本文基于linux内核 4.19.4&#xff0c;抽象媒体设备模型框架的相…

day11_类中成员之方法

成员变量是用来存储对象的数据信息的&#xff0c;那么如何表示对象的行为功能呢&#xff1f;就要通过方法来实现 方法 概念&#xff1a; 方法也叫函数&#xff0c;是一个独立功能的定义&#xff0c;是一个类中最基本的功能单元。把一个功能封装为方法的目的是&#xff0c;可…

信息安全原理与技术期末复习(如学)

文章目录 一、前言&#xff08;开卷打印&#xff09;二、选择题三、简答题1、简述端口扫描技术原理&#xff08;P136&#xff09;2、分组密码工作方式&#xff08;P61&#xff09;3、木马攻击&#xff08;P176&#xff09;4、消息认证码&#xff08;P84&#xff09;5、非对称密…

华为OD机试真题B卷 JavaScript 实现【删除字符串中出现次数最少的字符】,附详细解题思路

一、题目描述 删除字符串中出现次数最少的字符&#xff0c;如果多个字符出现次数一样则都删除。 二、输入描述 一个字符串。 三、输出描述 删除字符串中出现次数最少的字符&#xff0c;如果多个字符出现次数一样则都删除&#xff0c;如果都被删除 则换为empty。 四、解题…

机器视觉初步5-1:图像平滑专题

在计算机视觉领域&#xff0c;图像平滑处理是一个重要的任务&#xff0c;用于降低噪声&#xff0c;提高图像质量。常见的图像平滑算法有均值滤波、中值滤波、高斯滤波等。本文将介绍这些算法的原理&#xff0c;并分别给出使用Python与Halcon实现的代码。&#xff08;当前版本&a…

libface 人脸检测

于老师的项目地址GitHub - ShiqiYu/libfacedetection: An open source library for face detection in images. The face detection speed can reach 1000FPS. 关于如何使用&#xff0c;于老师写得很清楚&#xff1a; 测试代码 CMakeList.txt 和 三个face开头的cpp文件都是于老…

有趣的数学 数学建模入门一 从几个简单的示例入手

一、“变量”的概念 一个代数表达式&#xff08;通常只有一个字母&#xff1a;x&#xff0c;y&#xff0c;z…&#xff0c;如果它取代了一个未知值&#xff08;物理、经济、时间等&#xff09;&#xff0c;则称为“变量”。 变量的作用是占据一个值所在的位置&#xff0c;如果该…

设计模式之工厂方法模式笔记

设计模式之工厂方法模式笔记 说明Factory Method(工厂方法)目录UML抽象工厂示例类图咖啡抽象类美式咖啡类拿铁咖啡类 咖啡工厂接口美式咖啡工厂类拿铁咖啡工厂类 咖啡店类测试类 说明 记录下学习设计模式-工厂方法模式的写法。 Factory Method(工厂方法) 意图:定义一个用于创…

深度学习图像分类、目标检测、图像分割源码小项目

​demo仓库和视频演示&#xff1a; 银色子弹zg的个人空间-银色子弹zg个人主页-哔哩哔哩视频 卷积网路CNN分类的模型一般使用包括alexnet、DenseNet、DLA、GoogleNet、Mobilenet、ResNet、ResNeXt、ShuffleNet、VGG、EfficientNet和Swin transformer等10多种模型 目标检测包括…