Babylonjs学习笔记(十一)——加载geoJson文件

server/2024/9/24 14:21:50/
一、定义基本场景类
  • 定义场景
  • 定义相机
import { ArcRotateCamera, Color4, CubeTexture, Engine, GlowLayer, KeyboardEventTypes, Scene, Vector3 } from '@babylonjs/core';import { AdvancedDynamicTexture } from '@babylonjs/gui';class SceneManager {public engine: Engine;public scene: Scene;public camera: ArcRotateCamera;public advanceTexture: AdvancedDynamicTexture;public glowLayer: GlowLayer;constructor(canvas: HTMLCanvasElement) {this.engine = new Engine(canvas);const { scene, camera } = this.BuildScene();this.scene = scene;this.camera = camera;this.advanceTexture = AdvancedDynamicTexture.CreateFullscreenUI('ui');this.glowLayer = this.SetGlowLayer();this.setEnv();this.Resize();this.RenderLoop();}BuildScene(): { scene: Scene; camera: ArcRotateCamera } {const scene = new Scene(this.engine);scene.clearColor = new Color4(0, 0, 0, 0);const camera = new ArcRotateCamera('camera', 1.57, 1.57, 5.5, Vector3.Zero());camera.attachControl(this.engine.getRenderingCanvas(), true);camera.minZ = 0;camera.wheelPrecision = 20;camera.fov = 0.7;camera.lowerAlphaLimit = null;camera.upperAlphaLimit = null;camera.lowerBetaLimit = null;camera.upperBetaLimit = null;camera.inputs.removeByType('ArcRotateCameraMouseWheelInput');return {camera,scene};}SetGlowLayer(): GlowLayer {const glowLayer = new GlowLayer('gl');glowLayer.isEnabled = true;glowLayer.intensity = 0.3;return glowLayer;}RenderLoop() {this.engine.runRenderLoop(() => {this.scene.render();});}Resize() {if (window) {window.addEventListener('resize', () => {this.engine.resize();});}}// 切换调试面板public async RegisterInspectorOnInput(scene: Scene) {const isEnv = import.meta.env.MODE === 'development';if (isEnv) {await Promise.all([import('@babylonjs/core/Debug/debugLayer'), import('@babylonjs/inspector')]);scene.debugLayer.show({ embedMode: true });}const toggleInspector = () => {if (scene.debugLayer.isVisible()) scene.debugLayer.hide();else scene.debugLayer.show();};scene.onKeyboardObservable.add((kbInfo) => {if (kbInfo.type === KeyboardEventTypes.KEYDOWN && kbInfo.event.key === 'i') {toggleInspector();}});}setEnv() {const skybox = CubeTexture.CreateFromPrefilteredData('env/Earth_Skybox.env', this.scene);this.scene.createDefaultSkybox(skybox, false, 30, 0.98);const hdr = CubeTexture.CreateFromPrefilteredData('env/Earth_Env.env', this.scene);this.scene.environmentTexture = hdr;this.scene.autoClear = false; // Color bufferthis.scene.autoClearDepthAndStencil = false; // Depth and stencil, obviously}Dispose() {this.scene.dispose();this.engine.dispose();}
}export { SceneManager };
二、定义子类继承父类
  • 继承父类
  • 加载json文件
  • 利用墨卡托投影算法创建地图轮廓

import * as d3 from 'd3';

import earcut from 'earcut';

1.加载json文件

  LoadJson() {return new Promise<JSONType>((resolve) => {Tools.LoadFile('json/china.json', (response) => {try {const json = JSON.parse(response as string) as JSONType;resolve(json);} catch (error) {console.error(`地图json加载失败:${error}`);}});});}

 

2.生成边线和轮廓

2.1定义地图中心和投影算法

const center: [number, number] = [108.55, 34.32];
export function projection(args: [number, number]) {const result = d3.geoMercator().center(center).scale(5).translate([0, 0])(args) as [number, number];return result;
}

 2.2 封装创建多边形算法

// 创建多边形
export function CreatePolygon(path: Vector3[], scene: Scene) {return MeshBuilder.ExtrudePolygon('polygon',{shape: path,sideOrientation: Mesh.FRONTSIDE,depth: 0.5,// 这里设置会覆盖材质的颜色faceColors: [new Color4(1, 0, 0, 1), new Color4(0, 1, 0, 0.1), new Color4(1, 1, 1, 1)],faceUV: [new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1), new Vector4(0, 0, 1, 1)]},scene,earcut);
}// 创建边界线
export function CreateBoundaryLine(path: Vector3[]) {const line = MeshBuilder.CreateLines('line', { points: path.concat(path[0]), updatable: true });line.color = Color3.Random();return line;
}

2.3 通过json数据创建多边形

CreateMapFromGeoJSON(geoJsonData: JSONType) {return new Promise<Boolean>((resolve) => {const { features } = geoJsonData;const _createPolygonsFromCoordinates = (coordinate: number[][][] | number[][], meshList: Mesh[], lineList: Mesh[]) => {coordinate.forEach(() => {//获取轮廓const path = coordinate[0].map((coord: any) => {const [x, y] = projection([coord[0], coord[1]]) as [number, number];// 投影在xz平面return new Vector3(x, 0, -y);});const polygon = CreatePolygon(path, this.scene);meshList.push(polygon);const line = CreateBoundaryLine(path);lineList.push(line);});};features.forEach((feature, groundIndex) => {const { center, name, centroid } = feature.properties;const { coordinates, type } = feature.geometry;const meshList: Mesh[] = [];const lineList: Mesh[] = [];if (type === 'Polygon') _createPolygonsFromCoordinates(coordinates, meshList, lineList);if (type === 'MultiPolygon') coordinates.forEach((item) => _createPolygonsFromCoordinates(item, meshList, lineList));if (meshList.length > 0) {const mergedMesh = Mesh.MergeMeshes(meshList, true, true, undefined, false, true);if (mergedMesh) {mergedMesh.name = name + groundIndex;this.regionList.push({name,center,centroid,mesh: mergedMesh});}}});resolve(true);});}

2.4 创建省份标签

//创建区域标签
export function CreateRegionLabel(regionList: TypeRegionList[], advanceTexture: AdvancedDynamicTexture) {const _drawText = (name: string, mesh: Mesh) => {const text = new TextBlock();text.text = name;text.fontSize = 12;text.color = 'white';advanceTexture.addControl(text);text.linkWithMesh(mesh);};const _drawImage = (mesh: Mesh) => {const image = new Image('point', 'textures/point.png');image.width = '70px';image.height = '70px';advanceTexture.addControl(image);image.linkWithMesh(mesh);// image.linkOffsetX = -15;// image.linkOffsetY = 0;};regionList.forEach((item) => {const { mesh, name } = item;_drawText(name, mesh);_drawImage(mesh);});
}

2.5 创建飞线


export function CreateFlyline(regionList: TypeRegionList[], scene: Scene) {const flylineCenter = [116.41995, 40.18994] as [number, number];const [x, y] = projection(flylineCenter);const origin = new Vector3(x, 0, -y);// 创建textureconst createLineTexture = (): Texture => {const textureColors = new Uint8Array([255, 255, 255, 0, 0, 255]);const texture = new RawTexture(textureColors,textureColors.length / 3,1,Engine.TEXTUREFORMAT_RGB,scene,false,true,Engine.TEXTURE_NEAREST_NEAREST);texture.wrapU = RawTexture.WRAP_ADDRESSMODE;texture.name = 'blue-white-texture';texture.uScale = 5;return texture;};const texture = createLineTexture();const createLinesInstance = (points: Vector3[]): GreasedLineBaseMesh => {const line = CreateGreasedLine('line',{points,updatable: true},{width: 0.008,colorMode: GreasedLineMeshColorMode.COLOR_MODE_MULTIPLY},scene);return line;};regionList.forEach((city) => {const { centroid } = city;if (centroid) {const [x, y] = projection(centroid);const targetVec = new Vector3(x, 0, -y);CreateWave(new Vector3(targetVec.x, targetVec.y + 0.01, targetVec.z), scene);const middle = origin.add(targetVec).scale(0.5);let control = new Vector3(middle.x, 1, middle.z);// 创建贝塞尔曲线const curve = Curve3.CreateQuadraticBezier(origin, control, targetVec, 64);// 将贝塞尔曲线的点赋予lineconst line = createLinesInstance(curve.getPoints());(line.material as StandardMaterial).emissiveTexture = texture;texture.uScale = 5;scene.onBeforeRenderObservable.add(() => {texture.uOffset += -0.0005 * scene.getAnimationRatio();});}});
}

2.6 创建缩放动画

export function CreateWave(position: Vector3, scene: Scene) {const plane = MeshBuilder.CreatePlane('wave', { size: 0.15 });const mat = new StandardMaterial('mat');const texture = new Texture('textures/wave.png');mat.emissiveColor = Color3.White();mat.diffuseTexture = texture;mat.useAlphaFromDiffuseTexture = true;texture.hasAlpha = true;plane.material = mat;plane.position = position;plane.rotation.x = Math.PI / 2;let radio = 1.0; // 初始化缩放比例let size = 1; // 初始大小scene.onBeforeRenderObservable.add(() => {radio += 0.01; // 控制缩放速度const scling = size * radio;const initVector = new Vector3(scling, scling, scling);plane.scaling = initVector;if (radio <= 1.5) {plane.material!.alpha = (radio - 1) * 2; // 透明度从0到1} else if (radio > 1.5 && radio <= 2) {plane.material!.alpha = 1 - (radio - 1.5) * 2; // 透明度从1到0} else {radio = 1.0; // 重置缩放比例}});
}

2.7 创建action

export function AddEvent(regionList: TypeRegionList[]) {regionList.forEach((item) => {const { mesh, name } = item;mesh.actionManager = new ActionManager();// 改变样式actionmesh.actionManager.registerAction(new SetValueAction(ActionManager.OnPointerOverTrigger, mesh.material, 'diffuseColor', Color3.Blue()));mesh.actionManager.registerAction(new SetValueAction(ActionManager.OnPointerOutTrigger, mesh.material, 'diffuseColor', (mesh.material as StandardMaterial)!.diffuseColor));mesh.actionManager.registerAction(new InterpolateValueAction(ActionManager.OnPointerOverTrigger, mesh, 'scaling', new Vector3(1, -1.2, 1), 300));mesh.actionManager.registerAction(new InterpolateValueAction(ActionManager.OnPointerOutTrigger, mesh, 'scaling', new Vector3(1, 1, 1), 300));// 点击事件actionmesh.actionManager.registerAction(new ExecuteCodeAction({trigger: ActionManager.OnLeftPickTrigger,// 参数传递parameter: function (actionEvent: any) {return actionEvent.sourceEvent.key === 'R';}},(evt) => {console.log(evt, name);// 派发事件emitter.emit(EVENT_NAME.SET_PROVINCE_DATA, name as TProvinceKeys);}));});
}

3. 构造函数中调用

constructor(params: { canvas: HTMLCanvasElement; topList: String[] }) {const { canvas, topList } = params;super(canvas);// new HemisphericLight('ligt', Vector3.Up());this.LoadJson().then((geoJson: JSONType) => {this.CreateMapFromGeoJSON(geoJson).then(() => {// 创建区域标签CreateRegionLabel(this.regionList, this.advanceTexture);// 创建飞线CreateFlyline(this.regionList, this.scene);// 添加交互事件AddEvent(this.regionList);// 轮播this.SetupLoopInteraction();});});}

4 效果展示


http://www.ppmy.cn/server/62229.html

相关文章

昇思25天学习打卡营第二十四天|基于MindSpore通过GPT实现情感分类

基于MindSpore通过GPT实现情感分类 导入数据集 import osimport mindspore from mindnlp._legacy.engine import Evaluator, Trainer from mindnlp._legacy.engine.callbacks import BestModelCallback, CheckpointCallback from mindnlp._legacy.metrics import Accuracy fr…

如何使用这个XMLHttpRequest?

ajax含义:async javascript and XML;是异步的JS和XML&#xff1b;是实现页面局部刷新的技术(是一门独立的技术)。 为什么在js内能够使用呢&#xff1f;是因为ajax在浏览器内内置了一个核心对象&#xff0c;--》XMLHttpRequest&#xff08;低版本的IE浏览器没有&#xff09; 步…

应急响应总结

应急响应 日志 windows IIS 6.0 及更早版本&#xff1a; C:\WINDOWS\system32\LogFiles\W3SVC[SiteID]\ IIS 7.0 及更高版本&#xff1a; C:\inetpub\logs\LogFiles\W3SVC[SiteID]\ Apache HTTP Server C:\Program Files (x86)\Apache Group\Apache2\logs\ 或者 C:\Prog…

【面试题】Golang 之Channel底层原理 (第三篇)

目录 1.常见channel三大坑&#xff1a;死锁、内存泄漏、panic 1.死锁 1.只有生产者&#xff0c;没有消费者&#xff0c;或者反过来 2 生产者和消费者出现在同一个 goroutine 中 3 buffered channel 已满&#xff0c;且在同一个goroutine中 2.内存泄露 1 如何实现 gorout…

DP讨论——适配器模式

学而时习之&#xff0c;温故而知新。 敌人出招&#xff08;使用场景&#xff09; 说是自己的程序对接第三方的库&#xff0c;但是自己的代码的接口设计完毕了&#xff0c;如何对接上&#xff1f; 你出招 适配器模式就是为此而生的——我觉得应该是该解决方法被命名为了适配…

房屋出租管理系统小程序需求分析及功能介绍

房屋租赁管理系统适用于写字楼、办公楼、厂区、园区、商城、公寓等商办商业不动产的租赁管理及租赁营销&#xff1b;提供资产管理&#xff0c;合同管理&#xff0c;租赁管理&#xff0c; 物业管理&#xff0c;门禁管理等一体化的运营管理平台&#xff0c;提高项目方管理运营效率…

从 Icelake 到 Iceberg Rust

本文作者丁皓是Databend 研发工程师&#xff0c;也是 ASF Member&#xff0c; Apache OpenDAL PMC Chair &#xff0c;主要研究领域包括存储、自动化与开源。 太长不看 Icelake 已经停止更新&#xff0c;请改用 iceberg-rust。 Iceberg-rust 是一个由社区驱动的项目&#xff0…

[ruby on rails]部署时候产生ActiveRecord::PreparedStatementCacheExpired错误的原因及解决方法

一、问题&#xff1a; 有时在 Postgres 上部署 Rails 应用程序时&#xff0c;可能会看到 ActiveRecord::PreparedStatementCacheExpired 错误。仅当在部署中运行迁移时才会发生这种情况。发生这种情况是因为 Rails 利用 Postgres 的缓存准备语句(PreparedStatementCache)功能来…