vue中使用高德地图自定义掩膜背景结合threejs
技术架构
vue3+高德地图2.0+threejs
代码步骤
这里我们就用合肥市为主要的地区,将其他地区扣除,首先使用高德的webapi的DistrictSearch功能,使用该功能之前记得检查一下初始化的时候是否添加到plugins中,然后搜索合肥市的行政数据。
district.search(targetArea.name, (status, result) => {if (status === "complete") {//设置中心点map.setCenter([result.districtList[0].center.lng, result.districtList[0].center.lat], true);//整个世界let outer = [new AMap.LngLat(-360, 90, true), new AMap.LngLat(-360, -90, true), new AMap.LngLat(360, -90, true), new AMap.LngLat(360, 90, true)];//合肥市边界信息let holes = result.districtList[0].boundaries;let pathArray = [outer];// 绘制行政区划pathArray.push.apply(pathArray, holes);// 在合肥市内描边let polygon1 = new AMap.Polygon({path: [outer],strokeColor: "#00eeff",strokeWeight: 5,fillOpacity: 0,});//添加至地图polygon.setPath(pathArray);map.add(polygon);}});
这里就已经有了整个城市的轮廓。

我们的需求是自定义背景,首先我们需要获取到除了合肥市以外的地区,这里我们使用threejs,版本是0.157.0,大家这里可以安装和我一样的版本保证不会出错,版本太高会有问题,控制台 npm i three@0.157.0,在代码中import * as THREE from "three"导入,这里我们单独将threejs业务代码分出去。
------继续上面的代码----------//先获取地图画布的大小const innerHeight = mapRef.value.clientHeight;const innerWidth = mapRef.value.clientWidth;let options = {pathArray,center: [result.districtList[0].center.lng, result.districtList[0].center.lat],size: {innerWidth,innerHeight,},};//这里传入数据,单独写一个js文件来处理threejs业务 ,instace是AMapcreateThreeLayer(instance, map, options);
收集到我们需要的数据之后单独建一个js文件,先安装一个插件叫turf,这个插件非常善于处理地图上的数学、多边型,先 npm i @turf/turf,再导入import * as turf from "@turf/turf,下面开始写逻辑。
import * as THREE from "three";import * as turf from "@turf/turf";let glLayer;let camera, renderer, scene, raycaster;let customCoords = null;/*** @description 创建ThreeLayer*/export function createThreeLayer(instance, map, options) {const { polygon, center, size } = options;customCoords = map.customCoords;// 地图中心转换为墨卡托const centerCoord = customCoords.lngLatToCoord(center);// polygon是传入的多边形坐标,是一个非遮罩区域,outer外边框是整个地图的边界const outer = polygon[0];const inner = polygon[1];// inner的bboxconst turfPoints = inner.map((item) => [item.lng, item.lat]);const innerBbox = turf.bbox(turf.polygon([turfPoints]));// 最小正方形const squared = turf.square(innerBbox);// 转为4个点const squaredPoints = [[squared[0], squared[1]],[squared[0], squared[3]],[squared[2], squared[3]],[squared[2], squared[1]],];// 多边形坐标转换为世界中的坐标const innerCoords = inner.map((item) => {return {...item,coord: customCoords.lngLatToCoord([item.lng, item.lat]),};});const outerCoords = outer.map((item) => {return {...item,coord: customCoords.lngLatToCoord([item.lng, item.lat]),};});//世界边界点const squaredPointsCoords = squaredPoints.map((item) => customCoords.lngLatToCoord(item));//——--------------------——------------继续写代码的位置-------------------------}
这里将我们所有使用的点转换好了之后就可以创建自定义图层了,接下来开始绘制,这里我们准备两张图片,一张贴图,一张法线贴图(让图片凹凸部分感光,让画面更有质感),所有步骤的解释都在注释里面。
// 背景贴图const bgTexture = new THREE.TextureLoader().load("static/three/bg.png");// 法线背景贴图const normalTexture = new THREE.TextureLoader().load("static/three/bg_normal.png");if (!glLayer) {glLayer = new instance.GLCustomLayer({zIndex: 10,init: (gl) => {camera = new THREE.PerspectiveCamera(45, size.innerWidth / size.innerHeight, 100, 1 << 30);renderer = new THREE.WebGLRenderer({context: gl, // 地图的 gl 上下文});renderer.autoClear = false;scene = new THREE.Scene();// 环境光照和平行光let aLight = new THREE.AmbientLight(0xffffff, 2);let dLight = new THREE.DirectionalLight(0xffffff);dLight.intensity = 6;dLight.position.set(centerCoord[0], -100000, 50000);dLight.target.position.set(centerCoord[0], centerCoord[1], 0);dLight.target.updateMatrixWorld();scene.add(dLight);scene.add(aLight);// 辅助// const helper = new THREE.DirectionalLightHelper(dLight, 1);// scene.add(helper);// 辅助坐标轴// const axesHelper = new THREE.AxesHelper(100000);// scene.add(axesHelper);// 创建遮罩区域,遮罩区域 = outer - innerconst maskShape = new THREE.Shape();// 创建outermaskShape.moveTo(outerCoords[0].coord[0], outerCoords[0].coord[1]);outerCoords.forEach((item) => {maskShape.lineTo(item.coord[0], item.coord[1]);});// 创建innermaskShape.holes.push(new THREE.Path());maskShape.holes[0].moveTo(innerCoords[0].coord[0], innerCoords[0].coord[1]);innerCoords.forEach((item) => {maskShape.holes[0].lineTo(item.coord[0], item.coord[1]);});// 信息添加给多边形const maskGeometry = new THREE.ShapeGeometry(maskShape);// 调整纹理坐标 这里是调整贴图偏移和大小bgTexture.wrapS = THREE.RepeatWrapping;bgTexture.wrapT = THREE.RepeatWrapping;bgTexture.repeat.set(120, 120);bgTexture.offset.set(0.877, 0.275);//这里是调整法线贴图的normalTexture.wrapS = THREE.RepeatWrapping;normalTexture.wrapT = THREE.RepeatWrapping;normalTexture.repeat.set(120, 120);normalTexture.offset.set(0.877, 0.275);// 调整 UVmaskGeometry.computeBoundingBox();const bbox = maskGeometry.boundingBox;let size1 = new THREE.Vector2();bbox.getSize(size1);const uvAttribute = maskGeometry.attributes.uv;for (let i = 0; i < uvAttribute.count; i++) {const uv = new THREE.Vector2().fromBufferAttribute(uvAttribute, i);uv.x = (uv.x - bbox.min.x) / size1.x; // uv坐标映射uv.y = (uv.y - bbox.min.y) / size1.y;uvAttribute.setXY(i, uv.x, uv.y);}uvAttribute.needsUpdate = true;const maskMaterial = new THREE.MeshStandardMaterial({map: bgTexture,side: THREE.DoubleSide,transparent: true,normalMap: normalTexture,roughness: 0.5,metalness: 0.5,});const maskMesh = new THREE.Mesh(maskGeometry, maskMaterial);scene.add(maskMesh);},render: () => {let { near, far, fov, up, lookAt, position } = customCoords.getCameraParams();camera.near = near;camera.far = far;camera.fov = fov;camera.position.set(...position);camera.up.set(...up);camera.lookAt(...lookAt);camera.updateProjectionMatrix();renderer.render(scene, camera);renderer.resetState();},});map.add(glLayer);const animate = () => {map.render();requestAnimationFrame(animate);};animate();function onWindowResize() {camera.aspect = size.innerWidth / size.innerHeight;camera.updateProjectionMatrix();renderer.setSize(size.innerWidth, size.innerHeight);}window.addEventListener("resize", onWindowResize);}
下面放出效果图。

因为加上了法线贴图所以他会像这样。


加入高德地图各种特效之后是这样的效果。

素材放在下面了,需要的朋友可以自取哦~



高德开放平台第二期实战案例,三等奖作品
作者:左文韬
仅代表作者个人观点
相关文章:
vue中使用高德地图自定义掩膜背景结合threejs
技术架构 vue3高德地图2.0threejs 代码步骤 这里我们就用合肥市为主要的地区,将其他地区扣除,首先使用高德的webapi的DistrictSearch功能,使用该功能之前记得检查一下初始化的时候是否添加到plugins中,然后搜索合肥市的行政数据…...
tomcat如何配置保存7天滚动日志
在 Tomcat 中,logging.properties 文件是用于配置 Java 日志框架(java.util.logging)的。若要实现 catalina.out 日志保存 7 天,且每天的日志文件名带有时间戳,可以按以下步骤进行配置: 1. 备份原配置 在修…...
ffmpeg -pix_fmts
1. ffmpeg -pix_fmts -loglevel quiet 显示ffmpeg支持的像素格式 2. 输出 选取部分输出结果 Pixel formats: I.... Supported Input format for conversion .O... Supported Output format for conversion ..H.. Hardware accelerated format ...P. Paletted format ..…...
Python----PyQt开发(PyQt高级:图像显示,定时器,进度条)
一、图像显示 1.1、增加图标 1.直接创建setWindowIcon(QIcon(灯泡.jpg)) import sys from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton from PyQt5.QtGui import QIconclass MainWindow(QMainWindow):def __init__(self):super(MainWindow, self).__init_…...
Tomcat添加到Windows系统服务中,服务名称带空格
要将Tomcat添加到Windows系统服务中,可以通过Tomcat安装目录中“\bin\service.bat”来完成,如果目录中没有service.bat,则需要使用其它方法。 打到CMD命令行窗口,通过cd命令跳转到Tomcat安装目录的“\bin\”目录,然后执…...
2025.2.10 每日学习记录3:技术报告只差相关工作+补实验
0.近期主任务线 1.完成小论文准备 目标是3月份完成实验点1的全部实验和论文。 2.准备教资笔试 打算留个十多天左右,一次性备考笔试的三个科目 1.实习申请技术准备:微调、Agent、RAG 据央视财经,数据显示,截至2024年12月…...
普通用户授权docker使用权限
1、检查docker用户组 sudo cat /etc/group |grep docker 若显示:docker:x:999: # 表示存在否则创建docker用户组: sudo groupadd docker2、查看 /var/run/docker.sock 的属性 ll /var/run/docker.sock 显示: srw-rw---- 1 root root 0 1月…...
微生物学术语和定义 | 微生物学词汇表
微生物学作为一门研究微生物及其与环境、宿主和其他生物相互作用的科学,涵盖了广泛的学科领域和专业术语。然而,由于微生物学的快速发展和跨学科融合,许多术语的定义和使用在不同领域中可能存在差异甚至混淆。 随着新冠疫情的全球蔓延&am…...
Java集合List详解(带脑图)
允许重复元素,有序。常见的实现类有 ArrayList、LinkedList、Vector。 ArrayList ArrayList 是在 Java 编程中常用的集合类之一,它提供了便捷的数组操作,并在动态性、灵活性和性能方面取得了平衡。如果需要频繁在中间插入和删除元素…...
后盾人JS -- 异步编程,宏任务与微任务
异步加载图片体验JS任务操作 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title&g…...
Go语言的内存分配原理
Go语言的内存分配原理 Go语言的内存管理分为两个主要区域:栈(Stack) 和 堆(Heap)。理解这两个区域的工作原理,可以帮助你写出更高效的代码,并避免一些常见的性能问题。 1. 栈(Stac…...
分层解耦-ioc引入
内聚: 软件中各个功能模块内部的功能联系。 耦合: 衡量软件中各个层/模块之间的依赖、关联的程度。 软件设计原则: 高内聚低耦合。...
【知识科普】CPU,GPN,NPU知识普及
CPU,GPU,NPU CPU、GPU、NPU 详解1. CPU(中央处理器)2. GPU(图形处理器)3. NPU(神经网络处理器) **三者的核心区别****协同工作示例****总结** CPU、GPU、NPU 详解 1. CPU(中央处理器࿰…...
【管理与实物】1.1.1 建筑物分类与构成
1.1.1 建筑物分类与构成 建筑物的分类建筑物的构成 一、课前学习建议 民用建筑的分类:根据《民用建筑设计统一标准》GB50352-2019 划分可划分为单层或多层民用建筑、高层民用建筑、超高层民用建筑;根据《建筑设计防火规范》GB50016-2014(2…...
CentOS虚机在线扩容系统盘数据盘
最近在制作Openstack下的镜像,用户需要CentOS6以及CentOS7的虚机镜像,遇到了些关于系统盘以及数据盘在线扩容的问题,故此整理一下。 传统我们想对磁盘在线热扩容,必然会想到LVM逻辑卷。如果没有LVM逻辑卷的情况下,…...
使用Kickstart配置文件封装操作系统实现Linux的自动化安装
使用Kickstart配置文件封装操作系统实现Linux的自动化安装 创建ks.cfg配置文件 可以使用已经安装完成的Linux操作系统中的/root目录下的anaconda.cfg配置文件 注意,配置文件会因为kickstart的版本兼容性的问题导致无法安装报错需要在实际使用过程中删除某些参数 …...
如何利用DeepSeek开源模型打造OA系统专属AI助手
利用DeepSeek开源模型打造OA系统专属AI助手,可以显著提升办公效率,增强信息检索和管理能力。 注册与登录DeepSeek平台 访问DeepSeek官网 访问DeepSeek的官方网站DeepSeek。使用电子邮件或手机号码注册账号并登录。 获取API Key 登录DeepSeek平台&am…...
【20250211】栈与队列:1047.删除字符串中的所有相邻重复项
#方法一:使用栈 # class Solution: # def removeDuplicates(self, s): # res [] # for char in s: # #真和消消乐一样,栈外来一个数据,如果和栈顶数据相同,则不仅不入栈,还把栈顶数据…...
使用Hexo部署NexT主体网站
一.使用git提交文件 参考: 从零开始搭建个人博客(超详细) - 知乎 致谢! 第一种:本地没有 git 仓库 直接将远程仓库 clone 到本地;将文件添加并 commit 到本地仓库;将本地仓库的内容push到远程仓…...
uni getLocation 公众号h5获取定位坐标没有返回
先看代码 //获取经纬度getLocation() {console.log("111")uni.getLocation({type: wgs84,success: function (res) {console.log(当前位置的经度: res.longitude);console.log(当前位置的纬度: res.latitude);},fail: function(err) {conso…...
C语言基本概念————讨论sqrt()和pow()函数与整数的关系
本文来源:C语言基本概念——讨论sqrt()和pow()函数与整数的关系. C语言基本概念——sqrt和pow函数与整数的关系 1. 使用sqrt()是否可以得到完全平方数的精确的整数平方根1.1 完全平方数的计算结果是否精确?1.2 为什么不会出现误差(如 1.99999…...
【时时三省】(C语言基础)什么是算法
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 一个程序主要包括以下两方面的信息: (1)对数据的描述。在程序中,要指定用到哪些数据,以及这些数据的类型和数据组织形式。这就是数…...
Spring Boot 中加载多个 YAML 配置文件
在 Spring Boot 中加载多个 YAML 配置文件是一个常见的需求,通常用于将配置信息分离到多个文件中以便于管理和维护。Spring Boot 提供了灵活的方式来加载多个 YAML 配置文件。 以下是一些方法和步骤,用于在 Spring Boot 应用中加载多个 YAML 配置文件&a…...
IPoIB模块初始化过程详解
在现代网络环境中,InfiniBand over IP (IPoIB) 作为一种高性能的网络技术,被广泛应用于数据中心和高性能计算领域。为了确保其稳定性和高效性,Linux内核中的IPoIB模块在加载时需要进行一系列复杂的初始化操作。本文将基于一系列技术对话内容,详细介绍IPoIB模块的初始化流程…...
C语言——排序(冒泡,选择,插入)
基本概念 排序是对数据进行处理的常见操作,即将数据按某字段规律排列。字段是数据节点的一个属性,比如学生信息中的学号、分数等,可针对这些字段进行排序。同时,排序算法有稳定性之分,若两个待排序字段一致的数据在排序…...
如何本地部署DeepSeek
第一步:安装ollama https://ollama.com/download 打开官网,选择对应版本 第二步:选择合适的模型 https://ollama.com/ 模型名称中的 1.5B、7B、8B 等数字代表模型的参数量(Parameters),其中 B 是英文 B…...
Docker 部署 MySQL-5.7 单机版
一、镜像获取 # docker hub 镜像 docker pull farerboy/mysql:5.7 # 国内阿里镜像 docker pull registry.cn-hangzhou.aliyuncs.com/farerboy/mysql:5.7 以上两个镜像二选一即可 二、运行容器 docker run -dti --name mysql \n --privileged \n --cgroupns private \n --e…...
正则表达式--元字符-限定符(4)
正则的限定元字符 表示前边一个符号代表的内容出现多少次 1.* ------ 表示0~正无穷次 2. ------ 表示 1~正无穷次 3. ? ------ 表示 0~1次 4. {n} ------ 表示 限定 n 次, 不能多也不能少 5. {n,} ------ 表示 最少 n 次 6. {n,m} ------ 表示 最少 n 次, 最多 m 次 <!DO…...
【CMAEL多智能体框架】第一节 环境搭建及简单应用(构建一个鲜花选购智能体)
第一节 环境搭建 文章目录 第一节 环境搭建前言一、安装二、获取API1. 使用熟悉的API代理平台2.设置不使用明文存放API 三 、具体应用进阶任务 总结 前言 CAMEL Multi-Agent是一个开源的、灵活的框架,它提供了一套完整的工具和库,用于构建和模拟多智能体…...
网络工程师 (31)VLAN
前言 VLAN(Virtual Local Area Network)即虚拟局域网,是一种将物理局域网划分成多个逻辑上独立的虚拟网络的技术。 一、定义与特点 定义:VLAN是对连接到的第二层交换机端口的网络用户的逻辑分段,不受网络用户的物理位置…...
