base.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. /* 引入Cesium */
  2. // import * as Cesium from 'Cesium';
  3. //状态栏
  4. import StatusBar from "./StatusBar.js";
  5. import '../Assets/styles/base.css';
  6. /**
  7. * 场景视图
  8. */
  9. class jtMap3d {
  10. /**
  11. *
  12. * 初始化三维大球
  13. * @author joy
  14. * @param {Object} options 具有以下属性:
  15. * @param {String} options.container 包含球体小部件的 DOM 元素ID
  16. * @param {String} [options.imageryProviderType] 默认底图(世界影像)影像类型
  17. * @param {String} [options.imageryProviderUrl] 默认底图(世界影像)影像路径
  18. *
  19. * @example
  20. *
  21. * 例1:
  22. * const jtMap3d = new jtMap3d({container: "jtMap3dContainer"});
  23. *
  24. * 例2:
  25. * const jtMap3d = new jtMap3d({
  26. * container: "jtMap3dContainer",
  27. * imageryProviderType: "SingleTileImageryProvider",
  28. * imageryProviderUrl: "img/earth_3.jpg",
  29. * });
  30. *
  31. */
  32. constructor(options) {
  33. if (!Cesium.defined(options) || !Cesium.defined(options.container)) {
  34. throw new Cesium.DeveloperError("options.container is required.");
  35. }
  36. /* 设置token 这很重要 否则将导致地图无法加载 */
  37. Cesium.Ion.defaultAccessToken =
  38. 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiIxNzM5YjQ3MC03YmMxLTRmMjAtOTk4Yi0yNDMyMDZlOTQzYTYiLCJpZCI6NTU5MjAsImlhdCI6MTYyNDI0NTM5NX0.diydVWFzw5C5rQlHaFYkdDJoSorcdex81KpWcntyICo';
  39. /* 初始化地图控件 */
  40. this._viewer = this._initMap(options);
  41. /* 初始化变量 地图基础图层集合*/
  42. this._imageryLayers = this._viewer.imageryLayers;
  43. /* 初始化变量 地图原语集合 */
  44. this._primitives = this._viewer.scene.primitives;
  45. /* 初始化变量 地图绘制实体集合 */
  46. this._entities = this._viewer.entities;
  47. /* 初始化变量 数据源集合 */
  48. this._dataSources = this._viewer.dataSources; //数据源集合
  49. //默认天空盒子
  50. this._defaultSkyBox = this._viewer.scene.skyBox;
  51. this.statusBar = new StatusBar(this._viewer);
  52. console.log(Cesium.buildModuleUrl.getCesiumBaseUrl());
  53. }
  54. /**
  55. * 初始化球体查看小部件
  56. * @ignore 忽略注释,注释不生成Doc
  57. * @param {Object} options 具有以下属性:
  58. * @param {Element | String} options.container 包含球体小部件的 DOM 元素或 ID
  59. * @param {String} [options.imageryProviderType] 影像类型
  60. * @param {String} [options.imageryProviderUrl] 影像路径
  61. * @return {Viewer}
  62. */
  63. _initMap(options) {
  64. // //添加默认底图(世界影像)
  65. // var imageryProvider = new Cesium.SingleTileImageryProvider({
  66. // url: 'jt3dSDK/imgs/earth_3.jpg',
  67. // });
  68. // if (Cesium.defined(options.imageryProviderType)) {
  69. // if (Cesium.defined(options.imageryProviderUrl)) {
  70. // if (options.imageryProviderType == "SingleTileImageryProvider") {
  71. // imageryProvider = new Cesium.SingleTileImageryProvider({
  72. // url: options.imageryProviderUrl,
  73. // });
  74. // } else if (options.imageryProviderType == "OpenStreetMapImageryProvider") {
  75. // imageryProvider = new Cesium.OpenStreetMapImageryProvider({
  76. // url: options.imageryProviderUrl
  77. // });
  78. // } else if (options.imageryProviderType == "ArcGisMapServerImageryProvider") {
  79. // imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
  80. // url: options.imageryProviderUrl
  81. // });
  82. // }
  83. // } else {
  84. // throw new Cesium.DeveloperError("imageryProviderType and imageryProviderUrl are required.");
  85. // }
  86. // }
  87. //球体查看器
  88. let viewer = new Cesium.Viewer(options.container, {
  89. animation: true, //是否显示动画控件(左下角时间圆盘)
  90. timeline: true, //是否显示时间线控件(下方时间条),默认true
  91. shadows: false, //阴影,是否让太阳投射阴影
  92. shouldAnimate: true, //是否允许动画,是否允许场景中的动画自动播放
  93. baseLayerPicker: false, //地图切换控件(底图以及地形图)是否显示,默认显示true
  94. navigationHelpButton: false, //是否显示帮助信息控件,默认true
  95. homeButton: false, //主页按钮,默认true
  96. fullscreenButton: false, //全屏按钮,默认显示true
  97. sceneModePicker: false, //是否显示3D/2D选择器
  98. scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
  99. infoBox: false, //点击要素之后显示的信息,默认true
  100. clampToGround: true, //开启贴地
  101. geocoder: false, //地名查找,默认true
  102. // imageryProvider: imageryProvider,
  103. selectionIndicator: false, //选中元素显示,默认true选中元素显示,默认true
  104. contextOptions: {
  105. webgl: {
  106. alpha: true,
  107. depth: true,
  108. stencil: true,
  109. antialias: true,
  110. premultipliedAlpha: true,
  111. //通过canvas.toDataURL()实现截图需要将该项设置为true
  112. preserveDrawingBuffer: true,
  113. failIfMajorPerformanceCaveat: true
  114. }
  115. }
  116. });
  117. //隐藏版本信息
  118. viewer._cesiumWidget._creditContainer.style.display = "none";
  119. //是否显示地球
  120. viewer.scene.globe.show = true;
  121. //高程遮挡效果。地形不透明 地形检测,Cesium开启地形检测
  122. /* 此项设置为true可以查看哪些内容掉到地下了 正常情况下设置为false 否则会导致绘制的点只能看见一半 */
  123. viewer.scene.globe.depthTestAgainstTerrain = true;
  124. // 光照效果
  125. viewer.scene.globe.enableLighting = false;
  126. //启动主动渲染 这样地图加载完成后停止渲染 可节省CPU的开支(开启,以防部分动态效果失效)
  127. viewer.scene.requestRenderMode = false;
  128. //是否显示帧FPS
  129. viewer.scene.debugShowFramesPerSecond = true;
  130. //是否隐藏大气圈,如果显示大气圈,自定义天空盒子无效
  131. viewer.scene.skyAtmosphere.show = false;
  132. //是否显示星空(默认天空盒子)
  133. viewer.scene.skyBox.show = true;
  134. //是否显示太阳
  135. viewer.scene.sun.show = true;
  136. //是否显示有月亮
  137. viewer.scene.moon.show = false;
  138. //取消鼠标左键双击
  139. viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
  140. //右侧缺少一块(全屏按钮)
  141. // viewer.animation.container.style.visibility = 'hidden';
  142. // viewer.timeline.container.style.visibility = 'hidden';
  143. // 修改timeline时间 从儒略日改为北京时间
  144. viewer.animation.viewModel.dateFormatter = localeDateTimeFormatter;
  145. viewer.animation.viewModel.timeFormatter = localeTimeFormatter;
  146. viewer.timeline.makeLabel = localeDateTimeFormatter;
  147. //ignoredate 忽略日期
  148. function localeDateTimeFormatter(datetime, viewModel, ignoredate) {
  149. var julianDT = new Cesium.JulianDate();
  150. Cesium.JulianDate.addHours(datetime, 8, julianDT);
  151. var gregorianDT = Cesium.JulianDate.toGregorianDate(julianDT);
  152. var objDT;
  153. if (ignoredate) {
  154. objDT = '';
  155. } else {
  156. objDT = new Date(gregorianDT.year, gregorianDT.month - 1, gregorianDT.day);
  157. objDT = gregorianDT.year + '-' + objDT.toLocaleString('zh-cn', {
  158. month: 'short'
  159. }).split('月').join('-') + gregorianDT.day + ' ';
  160. if (viewModel || gregorianDT.hour + gregorianDT.minute === 0) {
  161. return objDT
  162. objDT += '';
  163. }
  164. }
  165. let hour, minute, second;
  166. if (gregorianDT.hour < 10) {
  167. hour = `0${gregorianDT.hour}`
  168. } else {
  169. hour = gregorianDT.hour
  170. }
  171. if (gregorianDT.minute < 10) {
  172. minute = `0${gregorianDT.minute}`
  173. } else {
  174. minute = gregorianDT.minute
  175. }
  176. if (gregorianDT.second < 10) {
  177. second = `0${gregorianDT.second}`
  178. } else {
  179. second = gregorianDT.second
  180. }
  181. // var millisecond = Math.round(gregorianDT.millisecond);
  182. // return objDT + hour + ":" + minute + ":" + second+ ":" + millisecond;
  183. return objDT + hour + ":" + minute + ":" + second;
  184. }
  185. function localeTimeFormatter(time, viewModel) {
  186. return localeDateTimeFormatter(time, viewModel, true)
  187. }
  188. return viewer;
  189. }
  190. /**
  191. * 初始化大球视窗范围
  192. * @ignore 忽略注释,注释不生成Doc
  193. * @param {Object} options 具有以下属性:
  194. * @param {Number} options.longitude 经度,以度为单位
  195. * @param {Number} options.latitude 纬度,以度为单位
  196. * @param {Number} [options.height=0.0] 椭球的高度,以米为单位
  197. * @param {Number} [options.heading=0.0] 指向,默认值0.0(北)
  198. * @param {Number} [options.pitch=-90] 视角,默认值-90(向下看)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
  199. * @param {Number} [options.roll=0.0] 翻滚
  200. */
  201. _setView(options) {
  202. if (!Cesium.defined(options.longitude) && !Cesium.defined(options.latitude)) {
  203. throw new Cesium.DeveloperError("longitude and latitude are required.");
  204. }
  205. Cesium.Check.typeOf.number("longitude", options.longitude);
  206. Cesium.Check.typeOf.number("latitude", options.latitude);
  207. this._viewer.camera.setView({ //设置视图 设置相机位置、方向和变换。
  208. //fromDegrees()将经纬度和高程转为世界坐标 摄像机在 WGS84(世界)坐标中的最终位置,或从自上而下视图可见的矩形。
  209. destination: Cesium.Cartesian3.fromDegrees(
  210. options.longitude,
  211. options.latitude,
  212. options.height
  213. ),
  214. orientation: {
  215. //此视角为观察者/相机 Math.toRadians() 将角度换成弧度。
  216. heading: Cesium.Math.toRadians(Cesium.defaultValue(options.heading, 0.0)),
  217. pitch: Cesium.Math.toRadians(Cesium.defaultValue(options.pitch, -90)),
  218. roll: options.roll,
  219. },
  220. });
  221. }
  222. /**
  223. * 获取中国范围坐标
  224. * @ignore 忽略注释,注释不生成Doc
  225. */
  226. _getChinaPostion() {
  227. return Cesium.Cartesian3.fromDegrees(116.435314, 40.960521, 10000000.0);
  228. }
  229. /**
  230. * 初始定位中国
  231. * @ignore 忽略注释,注释不生成Doc
  232. */
  233. _flytoChina() {
  234. this._viewer.camera.flyTo({
  235. destination: this._getChinaPostion(),
  236. duration: 8
  237. });
  238. }
  239. }
  240. /**
  241. * 通用对外公开函数
  242. */
  243. Object.assign(jtMap3d.prototype, /** @lends jtMap3d.prototype */ {
  244. /**
  245. * 初始化大球视窗范围,锁定为中国范围
  246. */
  247. setViewChina: function() {
  248. this._setView({
  249. longitude: 103.84, //经度
  250. latitude: 31.15, //维度
  251. height: 24000000, //高度
  252. heading: 0, // 偏航
  253. pitch: -90, // 俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
  254. roll: 0.0 // 翻滚
  255. });
  256. },
  257. /**
  258. * 初始化项目范围(即全图功能)
  259. * @param {Object} options 具有以下属性:
  260. * @param {Number} options.west=0.0 最西端的经度范围[-180.0,180.0]
  261. * @param {Number} options.south=0.0 最南端的纬度范围[-90.0,90.0]
  262. * @param {Number} options.east=0.0 最东端的经度范围[-180.0,180.0]
  263. * @param {Number} options.north=0.0 最北端的纬度范围[-90.0,90.0]
  264. * @param {Number} [options.isRemove=true] 定位完成后是否删除
  265. * @param {Number} [options.duration=3] 飞行时间
  266. * @param {Number} [options.heading=0]
  267. * @param {Number} [options.pitch=-90]
  268. * @param {Number} [options.range=0]
  269. */
  270. fullMap: function(options) {
  271. return new Promise((resolve, reject) => {
  272. let _self = this;
  273. this._entities.removeById("fullMapRectangle");
  274. // 初始化参数默认值
  275. options.isRemove = Cesium.defaultValue(options.isRemove, true);
  276. options.duration = Cesium.defaultValue(options.duration, 3);
  277. options.heading = Cesium.defaultValue(options.heading, 0);
  278. options.pitch = Cesium.defaultValue(options.pitch, -90);
  279. options.range = Cesium.defaultValue(options.range, 0.0);
  280. //left,bottom,right,top (西,南,东,北)
  281. var rectangle = Cesium.Rectangle.fromDegrees(options.west, options.south, options.east,
  282. options.north);
  283. //定义一个实体对象
  284. var fullMapEntity = this._entities.add({
  285. id: "fullMapRectangle",
  286. name: "fullMapRectangle",
  287. rectangle: {
  288. coordinates: rectangle,
  289. material: Cesium.Color.GREEN.withAlpha(0),
  290. height: 10.0,
  291. outline: false
  292. }
  293. });
  294. var flyPromise = this._viewer.flyTo(fullMapEntity, {
  295. duration: options.duration, //飞行时间
  296. offset: {
  297. heading: Cesium.Math.toRadians(options.heading),
  298. pitch: Cesium.Math.toRadians(options.pitch),
  299. range: options.range
  300. },
  301. });
  302. flyPromise.then(function(flyPromise) {
  303. if (flyPromise) {
  304. //飞行成功后,是否移除该实体
  305. if (options.isRemove) {
  306. fullMapEntity && (_self._entities.remove(fullMapEntity),
  307. fullMapEntity = null);
  308. }
  309. resolve(true);
  310. }
  311. })
  312. .catch(function(error) {
  313. console.log(error);
  314. });
  315. });
  316. },
  317. /**
  318. * 地图指北
  319. */
  320. setMapNorth() {
  321. let viewer = this._viewer;
  322. let pitch = Cesium.Math.toDegrees(viewer.camera.pitch).toFixed(0);
  323. // 中心点位置
  324. var center = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.clientWidth / 2, viewer.canvas.clientHeight / 2));
  325. var curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(center);
  326. let centerX = curPosition.longitude * 180 / Math.PI;
  327. let centerY = curPosition.latitude * 180 / Math.PI;
  328. //相机姿态信息
  329. let cameraPointX = viewer.camera.positionCartographic.longitude * 180 / Math.PI;
  330. let cameraPointY = viewer.camera.positionCartographic.latitude * 180 / Math.PI;
  331. let cameraPointZ = viewer.camera.positionCartographic.height.toFixed(0);
  332. // 计算两点之间距离
  333. var satrt = Cesium.Cartographic.fromDegrees(cameraPointX, cameraPointY, cameraPointZ);
  334. var end = Cesium.Cartographic.fromDegrees(centerX, centerY, 0);
  335. var geodesic = new Cesium.EllipsoidGeodesic();
  336. geodesic.setEndPoints(satrt, end);
  337. var distance = geodesic.surfaceDistance;
  338. let range = Math.sqrt(Math.pow(distance, 2) + Math.pow(cameraPointZ - 0, 2));
  339. // 创建旋转中心点
  340. if (this.centerEntity) {
  341. viewer.entities.remove(this.centerEntity);
  342. }
  343. this.centerEntity = viewer.entities.add({
  344. position: Cesium.Cartesian3.fromDegrees(centerX, centerY, 0),
  345. point: {
  346. color: Cesium.Color.RED,
  347. pixelSize: 1
  348. }
  349. });
  350. //更新场景相关旋转、角度距离参数
  351. let offset = new Cesium.HeadingPitchRange(Cesium.Math.toRadians(0), Cesium.Math.toRadians(pitch), range);
  352. viewer.zoomTo(this.centerEntity, offset);
  353. },
  354. /**
  355. * 地图自旋
  356. * @param {Array/Cartesian3} points 绕点位置[lng,lat,height]经度,以度为单位,纬度,以度为单位
  357. * @param {Object} options 具有以下属性:
  358. * @param {Number} [options.speed=30] 设定绕行一周花费时间
  359. * @param {Number} [options.pitch] 设定相机角度,默认相机当前看点的角度,如果大于0那么则是从地底往上看,所以要为负值。-90(向下看,俯仰)。俯仰,人如果在赤道上空,俯仰角为0可见地球。如果在北纬,俯仰角为负才能见地球
  360. * @param {Number} [options.height] 设定相机距离点的距离,默认相机当前视角高度
  361. */
  362. setMapSpinByPoint(points, options) {
  363. let _self = this;
  364. let viewer = this._viewer;
  365. if (!Cesium.defined(points)) {
  366. throw new Cesium.DeveloperError("points is required.");
  367. }
  368. options = options || {};
  369. options.speed = Cesium.defaultValue(options.speed, 30);
  370. //绕点位置
  371. var position = points;
  372. if (points instanceof Cesium.Cartesian3) {
  373. position = points;
  374. } else {
  375. position = Cesium.Cartesian3.fromDegrees(points[0], points[1], points[2] || 0);
  376. }
  377. // 为更直观地展示查询的位置,在点击处添加对应点
  378. var entity = viewer.entities.add(
  379. new Cesium.Entity({
  380. point: new Cesium.PointGraphics({
  381. color: new Cesium.Color(1, 1, 0),
  382. pixelSize: 6,
  383. outlineColor: new Cesium.Color(0, 1, 1)
  384. }),
  385. position: position
  386. })
  387. )
  388. // 给定飞行一周所需时间,比如30s, 那么每秒转动度数
  389. var angle = 360 / options.speed;
  390. // 相机的当前heading
  391. var initialHeading = viewer.camera.heading;
  392. // 相机的当前pitch,相机看点的角度,如果大于0那么则是从地底往上看,所以要为负值
  393. var pitch = viewer.camera.pitch
  394. if (options.pitch) {
  395. pitch = Cesium.Math.toRadians(options.pitch);
  396. }
  397. // 给定相机距离点多少距离飞行
  398. var distance = viewer.camera.positionCartographic.height;
  399. if (options.height) {
  400. distance = options.height;
  401. }
  402. // 起始时间
  403. var startTime = Cesium.JulianDate.fromDate(new Date());
  404. // 结束时间,设置一个结束时间,意思是360秒之后时间结束
  405. // var stopTime = Cesium.JulianDate.addSeconds(startTime,angle, new Cesium.JulianDate());
  406. viewer.clock.startTime = startTime.clone(); // 开始时间
  407. // viewer.clock.stopTime = stopTime.clone(); // 结速时间
  408. viewer.clock.currentTime = startTime.clone(); // 当前时间
  409. viewer.clock.clockRange = Cesium.ClockRange.CLAMPED; // 行为方式
  410. viewer.clock.clockStep = Cesium.ClockStep.SYSTEM_CLOCK; // 时钟设置为当前系统时间; 忽略所有其他设置。
  411. var Exection = function TimeExecution() {
  412. // 当前已经过去的时间,单位s
  413. var delTime = Cesium.JulianDate.secondsDifference(viewer.clock.currentTime, viewer.clock.startTime);
  414. // 根据过去的时间,计算偏航角的变化
  415. var heading = Cesium.Math.toRadians(delTime * angle) + initialHeading;
  416. viewer.scene.camera.setView({
  417. destination: position, // 点的坐标
  418. orientation: {
  419. heading: heading,
  420. pitch: pitch,
  421. }
  422. });
  423. viewer.scene.camera.moveBackward(distance);
  424. if (Cesium.JulianDate.compare(viewer.clock.currentTime, viewer.clock.stopTime) >= 0) {
  425. viewer.clock.onTick.removeEventListener(Exection);
  426. }
  427. //监听点击事件
  428. var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
  429. handler.setInputAction(function(click) {
  430. viewer.clock.onTick.removeEventListener(Exection);
  431. viewer.entities.remove(entity);
  432. }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
  433. };
  434. viewer.clock.onTick.addEventListener(Exection);
  435. },
  436. });
  437. /* 输出 */
  438. export default jtMap3d;