You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

Viewer.js 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /*
  2. * @Author: Caven
  3. * @Date: 2019-12-27 17:13:24
  4. * @Last Modified by: Caven
  5. * @Last Modified time: 2020-05-11 23:32:52
  6. */
  7. import { LayerEventType, MouseEvent, ViewerEvent, SceneEvent } from '../event'
  8. import { ViewerOption, CameraOption } from '../option'
  9. import {
  10. Attribution,
  11. ContextMenu,
  12. LocationBar,
  13. MapSplit,
  14. MapSwitch,
  15. Popup,
  16. Tooltip,
  17. HawkeyeMap,
  18. Compass
  19. } from '../widget'
  20. import { DomUtil } from '../utils'
  21. import Transform from '../transform/Transform'
  22. import Position from '../position/Position'
  23. const { Cesium } = DC.Namespace
  24. const DEF_OPTS = {
  25. animation: false, //Whether to create animated widgets, lower left corner of the meter
  26. baseLayerPicker: false, //Whether to display the layer selector
  27. fullscreenButton: false, //Whether to display the full-screen button
  28. geocoder: false, //To display the geocoder widget, query the button in the upper right corner
  29. homeButton: false, //Whether to display the Home button
  30. infoBox: false, //Whether to display the information box
  31. sceneModePicker: false, //Whether to display 3D/2D selector
  32. selectionIndicator: false, //Whether to display the selection indicator component
  33. timeline: false, //Whether to display the timeline
  34. navigationHelpButton: false, //Whether to display the help button in the upper right corner
  35. navigationInstructionsInitiallyVisible: false,
  36. creditContainer: undefined,
  37. shouldAnimate: true
  38. }
  39. class Viewer {
  40. constructor(id, options = {}) {
  41. if (!id || !document.getElementById(id)) {
  42. throw new Error('Viewer:the id is empty')
  43. }
  44. this._delegate = new Cesium.Viewer(id, {
  45. ...options,
  46. ...DEF_OPTS
  47. }) // Initialize the viewer
  48. /**
  49. * Register events
  50. */
  51. new MouseEvent(this) // Register global mouse events
  52. this._viewerEvent = new ViewerEvent() // Register viewer events
  53. this._sceneEvent = new SceneEvent(this) // Register viewer events
  54. this._viewerOption = new ViewerOption(this) // Initialize the viewer option
  55. this._cameraOption = new CameraOption(this) // Initialize the camera option
  56. this._dcContainer = DomUtil.create(
  57. 'div',
  58. 'dc-container',
  59. document.getElementById(id)
  60. ) //Register the custom container
  61. this._baseLayerPicker = new Cesium.BaseLayerPickerViewModel({
  62. globe: this._delegate.scene.globe
  63. })
  64. this._layerCache = {}
  65. this._effectCache = {}
  66. /**
  67. * Add default components
  68. */
  69. this._comps = {
  70. popup: new Popup(),
  71. contextMenu: new ContextMenu(),
  72. tooltip: new Tooltip(),
  73. mapSwitch: new MapSwitch(),
  74. mapSplit: new MapSplit(),
  75. locationBar: new LocationBar(),
  76. hawkeyeMap: new HawkeyeMap(),
  77. compass: new Compass(),
  78. attribution: new Attribution()
  79. }
  80. Object.keys(this._comps).forEach(key => {
  81. this.use(this._comps[key])
  82. })
  83. }
  84. get delegate() {
  85. return this._delegate
  86. }
  87. get dcContainer() {
  88. return this._dcContainer
  89. }
  90. get scene() {
  91. return this._delegate.scene
  92. }
  93. get camera() {
  94. return this._delegate.camera
  95. }
  96. get canvas() {
  97. return this._delegate.scene.canvas
  98. }
  99. get dataSources() {
  100. return this._delegate.dataSources
  101. }
  102. get clock() {
  103. return this._delegate.clock
  104. }
  105. get viewerEvent() {
  106. return this._viewerEvent
  107. }
  108. get popup() {
  109. return this._comps.popup
  110. }
  111. get contextMenu() {
  112. return this._comps.contextMenu
  113. }
  114. get tooltip() {
  115. return this._comps.tooltip
  116. }
  117. get mapSplit() {
  118. return this._comps.mapSplit
  119. }
  120. get mapSwitch() {
  121. return this._comps.mapSwitch
  122. }
  123. get locationBar() {
  124. return this._comps.locationBar
  125. }
  126. get hawkeyeMap() {
  127. return this._comps.hawkeyeMap
  128. }
  129. get compass() {
  130. return this._comps.compass
  131. }
  132. get cameraPosition() {
  133. let position = Transform.transformCartesianToWGS84(this.camera.positionWC)
  134. if (position) {
  135. position.heading = Cesium.Math.toDegrees(this.camera.heading)
  136. position.pitch = Cesium.Math.toDegrees(this.camera.pitch)
  137. position.roll = Cesium.Math.toDegrees(this.camera.roll)
  138. }
  139. return position
  140. }
  141. /**
  142. *
  143. * @param {*} layer
  144. */
  145. _addLayer(layer) {
  146. if (layer && layer.layerEvent) {
  147. !this._layerCache[layer.type] && (this._layerCache[layer.type] = {})
  148. if (!Object(this._layerCache[layer.type]).hasOwnProperty(layer.id)) {
  149. layer.layerEvent.fire(LayerEventType.ADD, this)
  150. this._layerCache[layer.type][layer.id] = layer
  151. }
  152. }
  153. }
  154. /**
  155. *
  156. * @param {*} layer
  157. */
  158. _removeLayer(layer) {
  159. if (
  160. layer &&
  161. layer.layerEvent &&
  162. Object(this._layerCache[layer.type]).hasOwnProperty(layer.id)
  163. ) {
  164. layer.layerEvent.fire(LayerEventType.REMOVE, this)
  165. delete this._layerCache[layer.type][layer.id]
  166. }
  167. }
  168. /**
  169. *
  170. * @param {*} effect
  171. */
  172. _addEffect(effect) {
  173. if (effect && effect.effectEvent) {
  174. !this._effectCache[effect.type] && (this._effectCache[effect.type] = {})
  175. if (!Object(this._effectCache[effect.type]).hasOwnProperty(effect.id)) {
  176. effect.effectEvent.fire(EffectEventType.ADD, this)
  177. this._effectCache[effect.type][effect.id] = effect
  178. }
  179. }
  180. }
  181. /**
  182. *
  183. * @param {*} effect
  184. */
  185. _removeEffect(effect) {
  186. if (
  187. effect &&
  188. effect.effectEvent &&
  189. Object(this._effectCache[effect.type]).hasOwnProperty(effect.id)
  190. ) {
  191. effect.effectEvent.fire(EffectEventType.REMOVE, this)
  192. delete this._effectCache[effect.type][effect.id]
  193. }
  194. }
  195. /**
  196. *
  197. * @param {*} options
  198. * Set viewer options
  199. *
  200. */
  201. setOptions(options) {
  202. this._viewerOption.setOptions(options)
  203. return this
  204. }
  205. /**
  206. *
  207. * @param {*} min
  208. * @param {*} max
  209. * Set camera pitch range
  210. *
  211. */
  212. setPitchRange(min = -90, max = -20) {
  213. this._cameraOption.setPichRange(min, max)
  214. return this
  215. }
  216. /**
  217. *
  218. * Restrict camera access underground
  219. *
  220. */
  221. limitCameraToGround() {
  222. this._cameraOption.limitCameraToGround()
  223. return this
  224. }
  225. /**
  226. *
  227. * @param {*} west
  228. * @param {*} south
  229. * @param {*} east
  230. * @param {*} north
  231. */
  232. setBounds(west, south, east, north) {
  233. this._cameraOption.setBounds(west, south, east, north)
  234. return this
  235. }
  236. /**
  237. *
  238. * 修改场景的模式,2:2D,2.5:2.5D,3:3D
  239. * @param {*} sceneMode
  240. * @param {*} duration
  241. *
  242. */
  243. changeSceneMode(sceneMode, duration = 0) {
  244. if (sceneMode === 2) {
  245. this._delegate.scene.morphTo2D(duration)
  246. } else if (sceneMode === 3) {
  247. this._delegate.scene.morphTo3D(duration)
  248. } else if (sceneMode === 2.5) {
  249. this._delegate.scene.morphToColumbusView(duration)
  250. }
  251. return this
  252. }
  253. /**
  254. *
  255. * Add the baselayer to the viewer.
  256. * The baselayer can be a single or an array,
  257. * and when the baselayer is an array, the baselayer will be loaded together
  258. * @param {*} baseLayers
  259. *
  260. */
  261. addBaseLayer(baseLayers, options = {}) {
  262. if (!baseLayers) {
  263. return this
  264. }
  265. this._baseLayerPicker.imageryProviderViewModels.push(
  266. new Cesium.ProviderViewModel({
  267. name: options.name || '地图',
  268. creationFunction: () => {
  269. return baseLayers
  270. }
  271. })
  272. )
  273. if (!this._baseLayerPicker.selectedImagery) {
  274. this._baseLayerPicker.selectedImagery = this._baseLayerPicker.imageryProviderViewModels[0]
  275. }
  276. this._comps.mapSwitch.addMap(options)
  277. return this
  278. }
  279. /**
  280. *
  281. * Change the current globe display of the baselayer
  282. * @param {*} index
  283. *
  284. */
  285. changeBaseLayer(index) {
  286. if (this._baseLayerPicker && index >= 0) {
  287. this._baseLayerPicker.selectedImagery = this._baseLayerPicker.imageryProviderViewModels[
  288. index
  289. ]
  290. }
  291. return this
  292. }
  293. /**
  294. *
  295. * Add the terrain to the viewer.
  296. * @param {*} terrain
  297. *
  298. */
  299. addTerrain(terrain) {
  300. if (!terrain) {
  301. return this
  302. }
  303. this._baseLayerPicker.terrainProviderViewModels.push(
  304. new Cesium.ProviderViewModel({
  305. name: '地形',
  306. creationFunction: () => {
  307. return terrain
  308. }
  309. })
  310. )
  311. if (!this._baseLayerPicker.selectedTerrain) {
  312. this._baseLayerPicker.selectedTerrain = this._baseLayerPicker.terrainProviderViewModels[0]
  313. }
  314. return this
  315. }
  316. /**
  317. *
  318. * Change the current globe display of the terrain
  319. * @param {*} index
  320. *
  321. */
  322. changeTerrain(index) {
  323. if (this._baseLayerPicker && index >= 0) {
  324. this._baseLayerPicker.selectedTerrain = this._baseLayerPicker.terrainProviderViewModels[
  325. index
  326. ]
  327. }
  328. return this
  329. }
  330. /**
  331. *
  332. * Add a layer to the viewer
  333. * @param {*} layer
  334. *
  335. */
  336. addLayer(layer) {
  337. this._addLayer(layer)
  338. return this
  339. }
  340. /**
  341. *
  342. * Remove a layer from the viewer
  343. * @param {*} layer
  344. *
  345. */
  346. removeLayer(layer) {
  347. this._removeLayer(layer)
  348. return this
  349. }
  350. /**
  351. *
  352. * @param {*} id
  353. * Get the layer by id
  354. *
  355. */
  356. getLayer(id) {
  357. let filters = this.getLayers().filter(item.id === id)
  358. return filters && filters.length ? filters[0] : undefined
  359. }
  360. /**
  361. * Get all layers
  362. */
  363. getLayers() {
  364. let result = []
  365. Object.keys(this._layerCache).forEach(type => {
  366. let cache = this._layerCache[type]
  367. Object.keys(cache).forEach(layerId => {
  368. result.push(cache[layerId])
  369. })
  370. })
  371. return result
  372. }
  373. /**
  374. *
  375. * @param {*} method
  376. * @param {*} context
  377. * loop through each layer
  378. *
  379. */
  380. eachLayer(method, context) {
  381. Object.keys(this._layerCache).forEach(type => {
  382. let cache = this._layerCache[type]
  383. Object.keys(cache).forEach(layerId => {
  384. method.call(context, cache[layerId])
  385. })
  386. })
  387. return this
  388. }
  389. /**
  390. *
  391. * @param {*} effect
  392. */
  393. addEffect(effect) {
  394. this._addEffect(effect)
  395. return this
  396. }
  397. /**
  398. *
  399. * @param {*} effect
  400. */
  401. removeEffect(effect) {
  402. this._removeEffect(effect)
  403. return this
  404. }
  405. /**
  406. *
  407. * @param {*} target
  408. *
  409. */
  410. flyTo(target) {
  411. this._delegate.flyTo(target.delegate || target)
  412. return this
  413. }
  414. /**
  415. *
  416. * @param {*} target
  417. *
  418. */
  419. zoomTo(target) {
  420. this._delegate.zoomTo(target.delegate || target)
  421. return this
  422. }
  423. /**
  424. *
  425. * @param {*} position
  426. * @param {*} completeCallback
  427. *
  428. */
  429. flyToPosition(position, completeCallback, duration) {
  430. if (position instanceof Position) {
  431. this._delegate.camera.flyTo({
  432. destination: Transform.transformWGS84ToCartesian(position),
  433. orientation: {
  434. heading: Cesium.Math.toRadians(position.heading),
  435. pitch: Cesium.Math.toRadians(position.pitch),
  436. roll: Cesium.Math.toRadians(position.roll)
  437. },
  438. complete: completeCallback,
  439. duration: duration
  440. })
  441. }
  442. return this
  443. }
  444. /**
  445. *
  446. * @param {*} position
  447. * @param {*} completeCallback
  448. *
  449. */
  450. zoomToPosition(position, completeCallback) {
  451. if (position instanceof Position) {
  452. this._delegate.camera.flyTo({
  453. destination: Transform.transformWGS84ToCartesian(position),
  454. orientation: {
  455. heading: Cesium.Math.toRadians(position.heading),
  456. pitch: Cesium.Math.toRadians(position.pitch),
  457. roll: Cesium.Math.toRadians(position.roll)
  458. },
  459. complete: completeCallback,
  460. duration: 0
  461. })
  462. }
  463. return this
  464. }
  465. /**
  466. *
  467. * @param {*} type
  468. * @param {*} callback
  469. * @param {*} context
  470. *
  471. */
  472. on(type, callback, context) {
  473. this._viewerEvent.on(type, callback, context || this)
  474. this._sceneEvent.on(type, callback, context || this)
  475. return this
  476. }
  477. /**
  478. *
  479. * @param {*} type
  480. * @param {*} callback
  481. * @param {*} context
  482. */
  483. once(type, callback, context) {
  484. this._viewerEvent.once(type, callback, context || this)
  485. return this
  486. }
  487. /**
  488. *
  489. * @param {*} type
  490. * @param {*} callback
  491. * @param {*} context
  492. *
  493. */
  494. off(type, callback, context) {
  495. this._viewerEvent.off(type, callback, context || this)
  496. this._sceneEvent.off(type, callback, context || this)
  497. return this
  498. }
  499. /**
  500. *
  501. * @param {*} plugin
  502. *
  503. */
  504. use(plugin) {
  505. if (plugin && plugin.install) {
  506. plugin.install(this)
  507. }
  508. return this
  509. }
  510. }
  511. export default Viewer