软件研究之Mars3d
1.前言
准备用Cesium进行三维开发。
问题
(1) 掩膜无法覆盖全
我使用阿里云的行政区县数据生成掩膜,增加了一个 mask 属性
1 | // 加载行政区划 |
结果显示错误,也就是在掩膜之外,还有一个角没有被淹没覆盖。
【解决方法】
经过一个星期的等待,结果官方的人给了回复,说是要在设置样式的时候,要增加一个贴地属性 clampToGround 。
1 | // 加载行政区划 |
1.Mars3D之关于贴地问题 style加个clampToGround:true属性
2.坐标系
Mars3D默认的坐标系是4326坐标系,就算是使用的高德的暗色底图,也是进行了转换,转成了4326坐标系,所以鼠标在地图上滑动,底下显示的也是4326的经纬度。比如 合景叠彩园 这个地址,坐标如下:
- 天地图浙江:[120.024,30.276]
- Mars3D:[120.023983,30.276061]
- 高德坐标拾取器:[120.028748,30.273686]
- 百度坐标拾取器:[120.035217,30.279733]
1 | "basemaps": [ |
1.阿里云地图选择器 这里使用的是高德的地图,坐标系就是GCJ02
2.百度坐标拾取器 百度坐标
3.拾取坐标系统(高德、百度、谷歌、腾讯)
4. hujiulong /gcoord 坐标转换工具,可以转换 WGS84、GCJ02、BD09等坐标系,暂时不支持4490坐标系
5.百度地图,高德地图和wgs84坐标系转换、度分秒十进制坐标格式互转 在线坐标转换
6.天地图浙江 可以鼠标滑动确定大致的经纬度
7. hujiulong / gcoord 这是在代码仓库中的一个。
3.不同级别显示不同的样式
需求就是不同的显示级别,但是我找来找去,在 GeoJsonLayer 找到关于不同级别配置不同样式的例子,唯一的 symbol 属性配置函数,但是每次视图发生变化的时候,并不会重新调用这个函数。
后来想到的一种解题思路,就是 监听地图相机的高度,然后转换为层级,当达到了相应的高度的时候,对图层进行删除,重新添加新的样式的图层。
1.GeoJsonLayer
2.Cesium 事件详解(鼠标事件、相机事件、键盘事件、场景触发事件) 屏幕空间事件处理程序、屏幕空间相机控制器、场景触发事件、Cesium API 中的场景触发事件
4.GeoJsonLayer图片类型特别的卡
渲染这个GeoJsonLayer图层的时候,特别的慢。我主要就是加载图层,然后有一个控制开关,就是过滤属性,哪些要素不用显示,哪些要显示。我的做法是遍历数据,筛选需要的feature,然后把原先的图层用 map.removeLayer 删掉,然后用新的数据构建新的图层。代码截图如下:
1 | // 清空已有图层 |
样式如果这么写的话,每次属性切换的时候,就特别的卡。没有报错,只是浏览器会显示警告。每次切换属性的时候,这个警告数量跳的很慢,警告跳完了之后,图层才会加载完成。在官方示例 GeoJson矢量图层 这个示例中的体育设施点,也会存在这个问题,就是每次点击体育设施点,都会有停顿的显示。这里之所以显示的快,是因为体育设施点只有91个,还算能接受。如果体育设施点超过400个,我自己的项目中就超过了400个,那么每一次清空图层之后重新创建的时间就特别的长。
【尝试】
(1) 反馈到官方群里,给我建了一个issue GeoServer矢量服务查询(OGC WFS)示例代码里面的点,有这个image属性,是为什么? 。
(2) 后来我单独的开了一个issue,GeoJsonLayer设置image样式时特别的卡 这是我的问题的具体描述,为了保证官方能第一时间准确的定位问题,我花了很多的时间处理这个东西。
(3) 我还尝试使用示例
【解决方案】
官方给我的解决方案:“通过使用show来显示和隐藏处理。如果属性比较多,就要,就要创建多个图层,或者发布为矢量服务,如wfs服务。” 没有其他的办法了,这个回答显然让我非常的不满意。
5.GeoJsonLayer没有image属性
在写geojson用图片渲染的时候,发现GeoJsonLayer 代码里面的 type 如果是 pointEntity ,没有这个image属性,但是示例中却出现了。官方回复我,说是PointEntity有一个属性叫 billboard ,可以设置图片的样式。
经过我的查找,这个 GeoJsonLayer 图层的 symbol 属性 styleOptions,对应的是每种不同类型数据都有不同的样式,具体见各GraphicType矢量数据的style参数。但是恰好这个PointEntity的style中没有这个image参数。这个billboard就是额外的属性了,这是文档的错误还是说可以直接这么使用呢?
6.Cesium is not defined
打包之后,运行的时候,出现了这个问题,但是开发的时候没有问题。
【解决方法】
后来在检查代码的时候,我发现了在我的一个文件中有 @ts-nocheck 这个标签,这个文件里面引用了Cesium变量,但是没有定义。开发的时候没有报错,但是打包之后就出现了错误。
1 | // @ts-nocheck |
7.原生Cesium无法加载模型
我在Mars3d中使用Cesium方式加载模型,我使用的是 import * as Cesium from “mars3d-cesium” 方式定义的Cesium,但是总是出不来。后来问了群里的人,说要使用 const Cesium = mars3d.Cesium 代替 import * as Cesium from “mars3d-cesium” 才可以。
1 | // 这句话很重要,不能用 import * as Cesium from "mars3d-cesium",否则模型出不来 |
8.mars3d和mars3d-cesium独立打包
在我使用 Mars3d提供的最简模版,进行打包的时候,虽然mars3d-cesium被独立出来了,但是代码还是被打包进了index.js文件中,导致了index.js又十多M的大小。
版本是v3.5.0,时间是2023年04月03日。后来官方的给我开了一个issue,进行问题的解决。
1 | "mars3d": "~3.5.0", |
【解决方案】
官方给了一个方案,就是代码层面没有什么可以优化的了。我自己研究了下,重新配置了vite的打包选项
1 | build: { |
打包后的信息如下:
9.鼠标点击高亮
1.Mars3D高亮效果怎么实现 这篇文章写了如何进行配置
10.vitePluginMars3d is not a function
这个问题出现在使用 vitePluginMars3d 这个插件之后出现的问题。
1 | import { vitePluginMars3d } from "vite-plugin-mars3d" |
这个在早期的版本中奏效,但是最新版本的 vite-plugin-mars3d 插件导出的函数有所变化。
1 | import { mars3dPlugin } from 'vite-plugin-mars3d'; |
11.加载的Geojson总是先显示然后消失
就是我用了一个GeojsonLayer图层,去加载了一系列的点,这些点图标总是先加载一遍,然后消失,等我拖动地图的时候,没一会这些点图标就显示出来了。
【尝试方案】
这个解决方案,就是这些个点的高度不够,需要设置一个高度。
【解决方案】
这个问题主要是出在这个 clampToGround: true, // 是否贴地 属性上,计算贴地之后,会导致图标出现问题。有人说:“你这是因为地形加载慢吧,先没地形,加载了贴地图标,然后地形才加载出来,一瞬间把图标淹没了,再然后图标重新贴地就又出来了。” 可是我没有加载地形啊。
1.clampToGround
12.mars3d-heatmap插件
我安装了mars3d-heatmap 插件,为什么直接引入 import ‘mars3d-heatmap’,会报错:Could not resolve “@mars3d/heatmap.js” … ‘undefined’ ? factory(exports, (window.mars3d || require(‘mars3d’)), (window.h337 || require(‘@mars3d/heatmap.js’))) :
版本也是对的
后来不知道怎么搞的,又好了,但是提示的内容又不正确了,提示我 heatmap.js 没有引入,但是我已经安装引入了。
1 | import * as Cesium from 'mars3d-cesium'; |
插件的引入顺序
【解决方案】
解决方案,也不是解决方案,只是我重新用了官方的示例模版,重新安装配置 heatmap,结果很顺利的继承了。而且我在mac电脑上,同样的代码,也是没有引入的问题的,那么问题到底出在哪里呢?
经过好几天的搁置,我最后分析了这个 mars3d-heatmap.js 这个插件的第一行,这里其实显示的就是需要一个 window.h337 全局变量,或者是 @mars3d/heatmap.js 这个插件,对应两种方式引入 heatmap.js 这个插件。
1 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, (window.mars3d || require('mars3d')), (window.h337 || require('@mars3d/heatmap.js'))) : |
所以最后我将 插件进行了替换,换成 @mars3d/heatmap.js 就可以了。
1 | pnpm add heatmap |
正确的使用方式
1 | // 导入mars3d插件(按需使用,需要先npm install mars3d-heatmap @mars3d/heatmap.js) |
1.获取 Mars3D SDK类库 这个离线获取,还是有点麻烦的。
2.heatmap.js
3.个人笔记|vue+cesium用heatmap.js插件展示热力图0
4.mars3d-heatmap 这里面也提到了@mars3d/heatmap.js, npm install mars3d-heatmap @mars3d/heatmap.js –save 但是我当时为什么没有看见呢?
13.mars3d-echarts插件
在我引入 mars3d-echarts插件的时候,又出现了问题:can’t access property “type”, seriesModel.coordinateSystem is undefined 。这个问题不知道怎么解决的,就解决了。后来又出现了新的问题,那就是在我按照官方的 例子 进行绘制的时候,基础模版和官方的例子都没有问题,有问题的是我自己的一模一样的代码里面,竟然所有的图标都是方块,而不是图形。
【解决方案】
问题就是少了图片的前缀。需要写上 “image://“ 这样的路径,而不是 “image:”。
1 | /** |
14.移动popup
创建一个可以随着鼠标移动的弹出框,主要就是监听鼠标点击,弹起以及鼠标移动事件
1 | /** |
这里其实涉及到了不同的坐标系之间的转换,屏幕坐标、笛卡尔坐标和经纬度坐标
1 | // 屏幕坐标 转换为 笛卡尔空间直角坐标 |
1.Mars3D中坐标系及坐标变换 这里的各种坐标转换的API说明,可以用的到。平台为我们提供了如下几种很有用的 计算机图形学中的变换工具类(如平移旋转缩放)Cesium.Cartesian3 :相当于Point3D。Cesium.Matrix3 :3x3矩阵,用于描述旋转变换。Cesium.Matrix4 :4x4矩阵,用于描述旋转加平移变换。Cesium.Quaternion :四元数,用于描述围绕某个向量旋转一定角度的变换。Cesium.Transforms :包含将位置转换为各种参考系的功能。
2.cesium实现矩形、多边形的手动绘制、拉伸和移动效果 这个稍微有些复杂,还是需要仔细的去研读这个里面的代码。
3.Cesium 中如何垂直抬升、水平移动、旋转模型 这里用了一个矩阵变换进行了处理,其实就是静态的。
4.Mars3D之三维空间视角
5.Mars3d开发——坐标系以及事件机制 这里也有各种坐标的转换方法,还有些事件的方法。
15.放大缩小
1 | import * as mars3d from 'mars3d'; |
1.自定义镜头缩放 原理很简单,通过 Cesium 提供的 viewer.camera.zoomIn() 和 viewer.camera.zoomOut API 即可。
2.cesium地图放大缩小 这是cesium的代码。
3.flyToPoint
16. ERR_REQUIRE_ESM require() of ES Module not supported
我在 jeecgboot3.6.3 中使用 vite-plugin-mars3d 插件,结果就报了这个错误,启动不了程序。不知道问题出在了哪里,但是根据模版中的版本,其实 vite:5.1.3 和 vite-plugin-mars3d 是可以共存的。
出现此错误的原因是模块已外部化。对于支持CJS的模块,我们最好将其外部化。对于只支持 ESM 的模块(例如 lowdb、execa、node-fetch 等),我们不应该将其外部化。
【尝试方案】
(1)我尝试去升级 vite 版本到最新版,还是不行。
(2)尝试修改 package.json,增加 “type”: “module”, 结果出现了其他的错误:”convertLegacyToken” is not a function,解决了这个问题,之后又出现了新的错误:vueSetupExtend is not a function,而这个问题的解决就是将 “type”:”module” 去掉。
(3)我尝试重新修改 vite-plugin-mars3d.umd.cjs 中的 require 引入方式,将require改为import引入,结果出现了:d.viteExternalsPlugin is not a function
(4)尝试修改引入 mars3d 插件,结果还是出错,解决方法就是增加 “type”: “module”
1 | import { mars3dPlugin } from 'vite-plugin-mars3d/dist/index'; |
(5)我查看了 vite-plugin-mars3d 的 3.0.0 版本和 4.0.0 版本的 index.d.ts 的不同
(6)安装了 ts-node,然后修改了 ts.config.js,”module”: “CommonJS”,后来我还增加了 “ts-node”: { “esm”: true }
(7)安装了 vite-plugin-require-transform 插件,然后引入了这个插件
1 | import { defineConfig } from 'vite' |
(8)adding “type”: “module” to the nearest package.json; renaming vite.config.js/vite.config.ts to vite.config.mjs/vite.config.mts
(9)尝试加载 import { mars3dPlugin } from ‘../../../node_modules/vite-plugin-mars3d/dist/vite-plugin-mars3d.umd.mjs’;
【解决方案】
(1)有一个小伙子的解决方案就是将 vite-plugin-mars3d 版本降到 3.0.0,这个可以解决问题。
(2)第二个解决方法就是使用 cdn 的方式引入 mars3d,也是可以的。
【1】.Error [ERR_REQUIRE_ESM]: require() of ES Module not supported [duplicate] I figured it out. I just had to downgrade node-fetch to 2.6.6, as the higher versions only use ESM, which caused a lot of errors.
【2】.火星科技 / mars3d-vue-template “vite”: “^5.1.3”,”vite-plugin-mars3d”: “^4.0.0”
【3】.TypeError: “convertLegacyToken” is not a function
【4】.How to use convertLegacyToken with less-loader in vite
【5】.jeecg-vue3 UI框架升级到antd4.x 因antd4.x放弃了less,但是jeecg-vue3中还要大量less变量,所以要兼容两者。
【6】.vite V3.0.0 vite.config.ts 引入插件报错(***** is not a function) 这里就是删除 type:module。
【7】.vite5使用vite-plugin-vue-setup-extend-plus报错TypeError: vueSetupExtend is not a function
【8】.vite V3.0.0 vite.config.ts 引入插件vite-plugin-vue-setup-extend-plus报错(vueSetupExtend不是一个函数)
【9】.Error [ERR_REQUIRE_ESM]: require() of ES Module Electron doesn’t support ESM, so the build standard for the main process and preload scripts is still CJS. This error occurs because the module is externalized. For modules that support CJS, we’d better externalize it. For modules that only support ESM (e.g. lowdb, execa, node-fetch, etc.), we should not externalize it. We should let electron-vite bundle it into a CJS standard module to support Electron.
【10】.[plugin externalize-deps] Failed to resolve entry for package “@crxjs/vite-plugin”](https://github.com/crxjs/chrome-extension-tools/issues/660)
【11】.如何在 Vite 中使用 UMD 的包
【12】. 解决Vite中不能使用require的问题
【13】.Error [ERR_REQUIRE_ESM]: require() of ES Module
【14】.vite-plugin-externals
【15】.This package is ESM only adding “type”: “module” to the nearest package.json; renaming vite.config.js/vite.config.ts to vite.config.mjs/vite.config.mts