Threejs 实现3D 地图(02)创建3d 地图

devtools/2024/10/19 10:39:20/

 

"d3": "^7.9.0",
"three": "^0.169.0",
"vue": "^3.5.10"

地图数据来源: DataV.GeoAtlas地理小工具系列 

<script setup>
import {onMounted, ref} from 'vue'
import * as THREE from 'three'
import * as d3 from "d3";  //莫开托坐标 矫正地图坐标
import map from './constant/map.json'
// 引入轨道控制器扩展库OrbitControls.js
import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
// 拿到页面的宽高
const width = window.innerWidth, height = window.innerHeight;// d3投影转换函数 (109, 34.5  中心点位置)
const handleProject = d3.geoMercator().center([109, 34.5]).scale(1000).translate([0, 0])
// 存储地图容器
const mapContainer = new THREE.Object3D()// 创建场景
const scene = new THREE.Scene();
// 将背景颜色设置为白色
scene.background = new THREE.Color("#000000");// 创建相机
const camera = new THREE.PerspectiveCamera(70, width / height, 0.01, 10000);
// 设置相机位置
camera.position.z = 1000;// // 辅助线 AxesHelper
const axesHelper = new THREE.AxesHelper(500);
scene.add(axesHelper);// 初始化渲染器
const renderer = new THREE.WebGLRenderer({antialias: true});
renderer.setSize(width, height);// 设置相机控件轨道控制器OrbitControls
const controls = new OrbitControls(camera, renderer.domElement);
//阻尼 更真实
controls.enableDamping = true// 地图数据处理
const initGeom = () => {// 将地图数据显示在屏幕上// 如果是服务器返回的数据,需要先将数据转为geojson格式 这里默认用的本地数据handleData(map)
}const handleData = (jsonData) => {const featureList = jsonData.features;featureList.forEach((feature) => {// 创建省的容器const province = new THREE.Object3D;// 省份名称province.properties = feature.properties.nameprovince.name = feature.properties.name // 省份名称mapContainer.name = feature.properties.name // 省份名称// 省份坐标信息const coordinates = feature.geometry.coordinatesif (feature.geometry.type === 'MultiPolygon') {coordinates.forEach((cord) => {// coordinate 就是边界素组坐标系cord.forEach((coordinate) => {// 三维多边形const extrudeMesh = creatDepthPolygon(coordinate)// 给extrudeMesh对象加一个自定义的属性(properties)用来存放省份名称extrudeMesh.properties = feature.properties.name// 绘制省份边缘线条const line = createLine(coordinate);// 将面加入3d 中province.add(extrudeMesh)// 将线加入3d 中province.add(line)})})}if (feature.geometry.type === 'Polygon') {coordinates.forEach((coordinate) => {// 三维多边形const extrudeMesh = creatDepthPolygon(coordinate)extrudeMesh.properties = feature.properties.name// 线条const line = createLine(coordinate);province.add(extrudeMesh)province.add(line)})}// 将每个省份的容器加入到地图容器中mapContainer.add(province)})// 将地图容器加入到场景中scene.add(mapContainer)
}// 创建三维多边形(也就是每个省份的地图)
const creatDepthPolygon = (coordinate) => {const shape = new THREE.Shape();// 每一个item都是省份边界坐标 需要把 json 的坐标系 转化为d3的坐标系  例如:[117.429915,40.576141]coordinate.forEach((item, index) => {const [x_XYZ, y_XYZ] = handleProject(item)if (index === 0) {// moveTo 的主要作用是定义形状的起点位置shape.moveTo(x_XYZ, -y_XYZ)} else {// 依次按照坐标 形成一个多边形shape.lineTo(x_XYZ, -y_XYZ)}})const extrudeSettings = {steps: 2,depth: 16,bevelEnabled: true,bevelThickness: 1,bevelSize: 1,bevelOffset: 0,bevelSegments: 1};// ExtrudeGeometry  创建一个多边形const geometry = new THREE.ExtrudeGeometry(shape, extrudeSettings)  //挤压缓冲几何体// 设置每个身份的背景颜色const material = new THREE.MeshBasicMaterial({// color: new THREE.Color(Math.random() * 0xffffff), // 每个省随机赋色color: '#d13a34',transparent: true,opacity: 0.6})return new THREE.Mesh(geometry, material)
}// 创建省份边界线条
const createLine = (coordinate) => {const material = new THREE.LineBasicMaterial({color: '#ffffff'});const points = []coordinate.forEach((item, index) => {// 每一个item都是省份边界坐标 需要把 json 的坐标系 转化为d3的坐标系  例如:[117.429915,40.576141]const [x_XYZ, y_XYZ] = handleProject(item)points.push(new THREE.Vector3(x_XYZ, -y_XYZ, 25))})const geometry = new THREE.BufferGeometry().setFromPoints(points);return new THREE.Line(geometry, material);
}// 渲染页面
const render = () => {// 将场景(scene)和摄像机(camera 加入进来)renderer.render(scene, camera)// 渲染下一帧的时候会调用render函数requestAnimationFrame(render)controls.update()
}const initLight = () => {// 基本光源const ambLight = new THREE.AmbientLight('#ffffff', 0.3)/*** 设置聚光灯相关的的属性*/const spotLight = new THREE.SpotLight(0xFFFFFF); // 聚光灯spotLight.position.set(40, 200, 10);spotLight.castShadow = true; // 只有该属性为true时,该点光源允许产生阴影,并且下列属性可用scene.add(ambLight, spotLight); // 向场景中添加光源
}onMounted(() => {// 添加物体到场景initGeom()// 渲染render()// 设置环境光initLight()// 将渲染加入到页面上document.body.appendChild(renderer.domElement);
})
</script><template><div id="info"></div>
</template><style scoped></style>


http://www.ppmy.cn/devtools/126980.html

相关文章

业务诊断简介

通过业务诊断功能&#xff0c;维护人员可以根据需要通过命令行创建一个诊断对象。当符合诊断对象的属性特征的用户上线时&#xff0c;设备根据诊断对象为其自动创建诊断实例&#xff0c;并对该实例在接入过程中的状态变化、协议处理结果等信息进行诊断并输出。 诊断对象是具有…

【JavaEE初阶】深入透析文件-IO关于文件内容的操作(四种文件流)

前言 &#x1f31f;&#x1f31f;本期讲解关于CAS的补充和JUC中有用的类&#xff0c;这里涉及到高频面试题哦~~~ &#x1f308;上期博客在这里&#xff1a;【JavaEE初阶】文件-IO之实现文件系统的操作如何进行实现-CSDN博客 &#x1f308;感兴趣的小伙伴看一看小编主页&…

【最新华为OD机试E卷-支持在线评测】水仙花数(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…

vue + 百度地图GL版判断一个点位是否在地图可视区内

利用BMapGLLib中isPointInRect 因为没有找到官方文档因此直接下载了该工具的源码&#xff0c;复制以下部分到自己的项目中&#xff0c;避免再次引用完整的BMapGLLib脚本 关键方法 isPointInRect(point, bounds) {if (!(point.toString() "Point" || point.toString(…

三菱FX PLC设计一个电子钟程序实例

在这里介绍三菱FX系列PLC的计数器C的功能、结构&#xff0c;计数过程及工作原理。 功能&#xff1a; 对内部元件X、Y、M、S、T、C的信号进行计数。 结构&#xff1a; 线圈、触点、设定值寄存器、当前值寄存器。 地址编号&#xff1a; 字母C&#xff0b;&#xff08;…

郑州大学第一附属医院许建中教授专家团队会诊室揭牌仪式在郑州长江中医院成功举行

近日&#xff0c;郑州大学第一附属医院许建中教授专家团队会诊室揭牌仪式暨骨关节病非手术治疗技术推广计划启动仪式在郑州举行。郑州大学第一附属医院许建中教授及其专家团队&#xff0c;郑州长江中医院专家团出席了本次活动。 关节病&#xff0c;尤其是膝关节、肩关节等关节的…

Qt_软件添加版本信息

文章内容: 给生成的软件添加软件的版权等信息 #include <windows.h> //中文的话增加下面这一行 #pragma code_page(65001)VS_VERSION_INFO VERSIONINFO

JavaScript网页设计案例:构建动态交互的在线图书管理系统

JavaScript网页设计案例&#xff1a;构建动态交互的在线图书管理系统 在当今的数字化时代&#xff0c;网页设计不仅仅是关于美观和布局&#xff0c;更重要的是用户体验和互动性。JavaScript&#xff0c;作为一种强大的编程语言&#xff0c;在网页开发中扮演着至关重要的角色&a…