CesiumOverviewMapControl.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563
  1. var CesiumOverviewMapControl = function () {
  2. this.init.apply(this, arguments);
  3. };
  4. CesiumOverviewMapControl.prototype = {
  5. _container: null,
  6. _miniMap: null,
  7. _viewerMoving: false,
  8. _miniMapMoving: false,
  9. _userToggledDisplay: false,
  10. _minimized: false,
  11. _isScreen:false,
  12. _oldWidth:'',
  13. _oldHeight:'',
  14. viewer: null,
  15. tileLayer: null,
  16. pipeLayerObj:null,
  17. pipeLayer:{
  18. url:"",
  19. subLayers:null
  20. },
  21. options: {
  22. position: 'bottomleft',
  23. toggleDisplay: true,
  24. zoomLevelOffset: -5,
  25. zoomLevelFixed: false,
  26. centerFixed: false,
  27. zoomControl: false,
  28. zoomAnimation: false,
  29. autoToggleDisplay: false,
  30. minimized: false,
  31. isScreen:false,
  32. width: '150px',
  33. height: '150px',
  34. collapsedWidth: '19px',
  35. collapsedHeight: '19px',
  36. aimingRectOptions: { color: '#ff7800', weight: 1, interactive: false },
  37. shadowRectOptions: { color: '#000000', weight: 1, interactive: false, opacity: 0, fillOpacity: 0 },
  38. strings: { hideText: '隐藏鹰眼', showText: '显示鹰眼' },
  39. mapOptions: {
  40. toggleDisplay: true,
  41. aimingRectOptions: {
  42. color: "#ff1100",
  43. weight: 3
  44. },
  45. shadowRectOptions: {
  46. color: "#0000AA",
  47. weight: 1,
  48. opacity: 0,
  49. fillOpacity: 0
  50. }
  51. }
  52. },
  53. init: function (viewer, layer, options) {
  54. this.viewer = viewer;
  55. this.tileLayer = layer;
  56. this._container = options.container;
  57. L.Util.setOptions(this, options);
  58. this.options.aimingRectOptions.interactive = false;
  59. this.options.shadowRectOptions.interactive = false;
  60. this._isScreen=this.options.isScreen;
  61. this._initMap();
  62. this._showInitView();
  63. return this;
  64. },
  65. updateAimingRect: function () {
  66. var _this = this;
  67. var rect = _this._getViewRange();
  68. if(rect)
  69. _this._aimingRect.setBounds(rect);
  70. },
  71. splitScreen: function (options) {//分屏
  72. this._oldWidth=this.options.width;
  73. this._oldHeight=this.options.height;
  74. this.options.width=options.width;
  75. this.options.height=options.height;
  76. this._container.style.width = this.options.width;
  77. this._container.style.height = this.options.height;
  78. this._miniMap.remove();
  79. $(this._container).empty().removeAttr("style").removeAttr("tabindex").removeClass("leaflet-container").removeClass("leaflet-touch").removeClass("leaflet-fade-anim");
  80. this._miniMap=null;
  81. this._isScreen=true;
  82. setTimeout(function () {
  83. this.viewer.scene.camera.moveEnd._listeners=[];
  84. this.viewer.scene.camera.moveEnd._scopes=[];
  85. this.viewer.scene.camera.moveStart._listeners=[];
  86. this.viewer.scene.camera.moveStart._scopes=[];
  87. this._initMap();
  88. this._showInitView();
  89. }.bind(this), 300);
  90. },
  91. restoreScreen:function(){
  92. this.options.width=this._oldWidth;
  93. this.options.height=this._oldHeight;
  94. this._container.style.width = this.options.width;
  95. this._container.style.height = this.options.height;
  96. this._miniMap.remove();
  97. $(this._container).empty().removeAttr("style").removeAttr("tabindex").removeClass("leaflet-container").removeClass("leaflet-touch").removeClass("leaflet-fade-anim");
  98. this._miniMap=null;
  99. this._isScreen=false;
  100. setTimeout(function () {
  101. this.viewer.scene.camera.moveEnd._listeners=[];
  102. this.viewer.scene.camera.moveEnd._scopes=[];
  103. this.viewer.scene.camera.moveStart._listeners=[];
  104. this.viewer.scene.camera.moveStart._scopes=[];
  105. this._initMap();
  106. this._showInitView();
  107. }.bind(this), 300);
  108. },
  109. _initMap: function () {
  110. var _this = this;
  111. this._container.style.width = this.options.width;
  112. this._container.style.height = this.options.height
  113. L.DomEvent.disableClickPropagation(_this._container);
  114. L.DomEvent.on(_this._container, 'mousewheel', L.DomEvent.stopPropagation);
  115. var mapOptions = {
  116. logoControl: false,
  117. attributionControl: false,
  118. dragging: !_this.options.centerFixed,
  119. zoomControl: _this.options.zoomControl,
  120. zoomAnimation: _this.options.zoomAnimation,
  121. autoToggleDisplay: _this.options.autoToggleDisplay,
  122. touchZoom: _this.options.centerFixed ? 'center' : !_this._isZoomLevelFixed(),
  123. scrollWheelZoom: _this.options.centerFixed ? 'center' : !_this._isZoomLevelFixed(),
  124. doubleClickZoom: _this.options.centerFixed ? 'center' : !_this._isZoomLevelFixed(),
  125. boxZoom: !_this._isZoomLevelFixed(),
  126. crs: L.CRS.EPSG4326,//L.CRS.TianDiTu_WGS84,
  127. //crs: L.CRS.EPSG3857,
  128. center: [0, 0],
  129. zoom: 1
  130. };
  131. mapOptions = L.Util.extend(_this.options.mapOptions, mapOptions); // merge
  132. // with
  133. // priority
  134. // of
  135. // the
  136. // local
  137. // mapOptions
  138. // object.
  139. _this._miniMap = new L.Map(_this._container, mapOptions);
  140. var layer = this.tileLayer;
  141. layer.forEach(function(item,index){
  142. _this._miniMap.addLayer(item);
  143. }.bind(_this))
  144. if(this.pipeLayer && this.pipeLayer.subLayers)
  145. this.addPipeLayers(this.pipeLayer.url,this.pipeLayer.subLayers);
  146. // These bools are used to prevent infinite loops of the two maps
  147. // notifying each other that they've moved.
  148. _this._viewerMoving = true;
  149. _this._miniMapMoving = false;
  150. // Keep a record of _this to prevent auto toggling when the user
  151. // explicitly doesn't want it.
  152. _this._userToggledDisplay = false;
  153. _this._minimized = false;
  154. if (this.options.toggleDisplay && this._isScreen==false) {
  155. this._addToggleButton();
  156. }
  157. _this._miniMap.whenReady(L.Util.bind(function () {
  158. var bounds = _this._getViewRange();
  159. if(bounds){
  160. _this._aimingRect = L.rectangle(bounds, _this.options.aimingRectOptions).addTo(_this._miniMap);
  161. _this._shadowRect = L.rectangle(bounds, _this.options.shadowRectOptions).addTo(_this._miniMap);
  162. if(_this._isScreen==true){
  163. this._aimingRect.setStyle({opacity: 0, fillOpacity: 0});
  164. }
  165. var camera = _this.viewer.scene.camera;
  166. camera.moveEnd.addEventListener(_this._moveEnd.bind(_this));
  167. camera.moveStart.addEventListener(_this._moveStart.bind(_this));
  168. _this._miniMap.on('movestart', _this._onMiniMapMoveStarted, _this);
  169. _this._miniMap.on('move', _this._onMiniMapMoving, _this);
  170. _this._miniMap.on('moveend', _this._onMiniMapMoved, _this);
  171. if(_this.options.minimized==true && _this._isScreen==false)
  172. _this._toggleDisplayButtonClicked();
  173. _this._container.style.visibility='visible';
  174. }
  175. }, _this));
  176. return _this._container;
  177. },
  178. _moveEnd:function (e) {
  179. var _this = this;
  180. if(_this._miniMap){
  181. var rect = _this._getViewRange();
  182. if (!_this._miniMapMoving) {
  183. _this._viewerMoving = true;
  184. if(rect){
  185. var zrect = _this._getZoomOutRange(rect);
  186. _this._miniMap.fitBounds(zrect);
  187. _this._setDisplay(_this._decideMinimized());
  188. }
  189. } else {
  190. _this._miniMapMoving = false;
  191. }
  192. if(rect)
  193. _this._aimingRect.setBounds(rect);
  194. }
  195. },
  196. _moveStart:function (e) {
  197. var _this = this;
  198. if(_this._miniMap){
  199. var rect = _this._getViewRange();
  200. if(rect)
  201. _this._aimingRect.setBounds(rect);
  202. }
  203. },
  204. _addToggleButton: function () {
  205. this._toggleDisplayButton = this.options.toggleDisplay ? this._createButton(
  206. '', this._toggleButtonInitialTitleText(), ('leaflet-control-minimap-toggle-display leaflet-control-minimap-toggle-display-' +
  207. this.options.position), this._container, this._toggleDisplayButtonClicked, this) : undefined;
  208. // this._toggleDisplayButton.style.zIndex = 99999;
  209. this._toggleDisplayButton.style.width = this.options.collapsedWidth;
  210. this._toggleDisplayButton.style.height = this.options.collapsedHeight;
  211. },
  212. _toggleButtonInitialTitleText: function () {
  213. if (this.options.minimized) {
  214. return this.options.strings.showText;
  215. } else {
  216. return this.options.strings.hideText;
  217. }
  218. },
  219. _createButton: function (html, title, className, container, fn, context) {
  220. var link = L.DomUtil.create('a', className, container);
  221. link.innerHTML = html;
  222. link.href = '#';
  223. link.title = title;
  224. var stop = L.DomEvent.stopPropagation;
  225. L.DomEvent
  226. .on(link, 'click', stop)
  227. .on(link, 'mousedown', stop)
  228. .on(link, 'dblclick', stop)
  229. .on(link, 'click', L.DomEvent.preventDefault)
  230. .on(link, 'click', fn, context);
  231. return link;
  232. },
  233. _toggleDisplayButtonClicked: function () {
  234. this._userToggledDisplay = true;
  235. if (!this._minimized) {
  236. this._minimize();
  237. } else {
  238. this._restore();
  239. }
  240. },
  241. _showInitView: function () {
  242. var rect = this._getViewRange();
  243. if(rect){
  244. var zrect = this._getZoomOutRange(rect);
  245. this._miniMap.fitBounds(zrect);
  246. }
  247. },
  248. _setDisplay: function (minimize) {
  249. if (minimize !== this._minimized) {
  250. if (!this._minimized) {
  251. this._minimize();
  252. } else {
  253. this._restore();
  254. }
  255. }
  256. },
  257. _minimize: function () {
  258. // hide the minimap
  259. if (this.options.toggleDisplay) {
  260. this._container.style.width = this.options.collapsedWidth;
  261. this._container.style.height = this.options.collapsedHeight;
  262. this._toggleDisplayButton.className += (' minimized-' + this.options.position);
  263. this._toggleDisplayButton.title = this.options.strings.showText;
  264. } else {
  265. this._container.style.display = 'none';
  266. }
  267. this._minimized = true;
  268. this.options.minimized=true;
  269. this._onToggle();
  270. },
  271. _restore: function () {
  272. if (this.options.toggleDisplay) {
  273. this._container.style.width = this.options.width;
  274. this._container.style.height = this.options.height;
  275. this._toggleDisplayButton.className = this._toggleDisplayButton.className
  276. .replace('minimized-' + this.options.position, '');
  277. this._toggleDisplayButton.title = this.options.strings.hideText;
  278. } else {
  279. this._container.style.display = 'block';
  280. }
  281. this._minimized = false;
  282. this.options.minimized=false;
  283. this._onToggle();
  284. },
  285. _onMiniMapMoveStarted: function (e) {
  286. if (!this.options.centerFixed) {
  287. var lastAimingRect = this._aimingRect.getBounds();
  288. var sw = this._miniMap.latLngToContainerPoint(lastAimingRect.getSouthWest());
  289. var ne = this._miniMap.latLngToContainerPoint(lastAimingRect.getNorthEast());
  290. this._lastAimingRectPosition = { sw: sw, ne: ne };
  291. }
  292. },
  293. _onMiniMapMoving: function (e) {
  294. if (!this.options.centerFixed) {
  295. if (!this._viewerMoving && this._lastAimingRectPosition) {
  296. this._shadowRect.setBounds(new L.LatLngBounds(this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.sw), this._miniMap.containerPointToLatLng(this._lastAimingRectPosition.ne)));
  297. this._shadowRect.setStyle(this._isScreen?{opacity: 0, fillOpacity: 0}:{ opacity: 1, fillOpacity: 0.3 });
  298. }
  299. }
  300. },
  301. _onMiniMapMoved: function (e) {
  302. if (!this._viewerMoving&&!this._minimized) {
  303. this._miniMapMoving = true;
  304. var rect = this._isScreen?this._miniMap.getBounds():this._shadowRect.getBounds();
  305. var west = rect.getWest();
  306. var east = rect.getEast();
  307. var north = rect.getNorth();
  308. var south = rect.getSouth();
  309. var destination = Cesium.Rectangle.fromDegrees(west, south, east, north);
  310. var centerPt=null;
  311. centerPt=Cesium.Rectangle.center(destination, centerPt);
  312. var viewer = this.viewer;
  313. var camera = viewer.scene.camera;
  314. var cartographic=Cesium.Cartographic.fromCartesian(camera.position);
  315. var longitude = Cesium.Math.toDegrees(cartographic.longitude);
  316. var latitude = Cesium.Math.toDegrees(cartographic.latitude);
  317. var currentHeight=this.viewer.scene.getHeight(longitude,latitude);
  318. destination.height=(cartographic.height-currentHeight)+this.viewer.scene.getHeight(Cesium.Math.toDegrees(centerPt.longitude),Cesium.Math.toDegrees(centerPt.latitude));;
  319. var orientation = {
  320. heading: Cesium.Math.toRadians(0),
  321. pitch:camera.pitch,//Cesium.Math.toRadians(-90),
  322. roll:camera.roll//0.0
  323. };
  324. this.viewer.scene.camera.setView({
  325. destination: destination,
  326. orientation: orientation
  327. });
  328. //获取当前地图范围
  329. /*var bounds = this._miniMap.getBounds();//map.getExtent();
  330. //根据给定的地图范围计算场景的高度
  331. var altitude = _calculateAltitudeFromBounds(bounds);
  332. //获取地图中心点
  333. var center = map.getCenter();
  334. //设置场景相机
  335. var camera = new SuperMap.Web.Realspace.Camera(center.lon, center.lat, altitude);
  336. camera.set_heading(0);
  337. sceneControl.get_scene().set_camera(camera);*/
  338. this._shadowRect.setStyle({ opacity: 0, fillOpacity: 0 });
  339. } else {
  340. this._viewerMoving = false;
  341. }
  342. },
  343. _isZoomLevelFixed: function () {
  344. var zoomLevelFixed = this.options.zoomLevelFixed;
  345. return this._isDefined(zoomLevelFixed) && this._isInteger(zoomLevelFixed);
  346. },
  347. _decideMinimized: function () {
  348. if (this._userToggledDisplay) {
  349. return this._minimized;
  350. }
  351. if (this.options.autoToggleDisplay) {
  352. var bounds = this._getViewRange();
  353. if (bounds.contains(this._miniMap.getBounds())) {
  354. return true;
  355. }
  356. return false;
  357. }
  358. return this._minimized;
  359. },
  360. _isInteger: function (value) {
  361. return typeof value === 'number';
  362. },
  363. _isDefined: function (value) {
  364. return typeof value !== 'undefined';
  365. },
  366. _onToggle: function () {
  367. L.Util.requestAnimFrame(function () {
  368. L.DomEvent.on(this._container, 'transitionend', this._fireToggleEvents, this);
  369. if (!L.Browser.any3d) {
  370. L.Util.requestAnimFrame(this._fireToggleEvents, this);
  371. }
  372. }, this);
  373. },
  374. _fireToggleEvents: function () {
  375. L.DomEvent.off(this._container, 'transitionend', this._fireToggleEvents, this);
  376. },
  377. _getViewRange: function () {
  378. var viewer = this.viewer;
  379. var bounds=null;
  380. if(viewer){
  381. var camera = viewer.scene.camera;
  382. var range = camera.computeViewRectangle();
  383. if(camera && range){
  384. var west=undefined,east=undefined,north=undefined,south=undefined;
  385. if(range.west !=undefined)
  386. west = range.west / Math.PI * 180;
  387. if(range.east !=undefined)
  388. east = range.east / Math.PI * 180;
  389. if(range.north !=undefined)
  390. north = range.north / Math.PI * 180;
  391. if(range.south !=undefined)
  392. south = range.south / Math.PI * 180;
  393. if(west!=undefined && east!=undefined && north!=undefined && south!=undefined)
  394. bounds = new L.LatLngBounds(
  395. new L.LatLng(north, west),
  396. new L.LatLng(south, east)
  397. );
  398. }
  399. }
  400. return bounds;
  401. },
  402. _getZoomOutRange: function (rect) {
  403. var west = rect.getWest();
  404. var east = rect.getEast();
  405. var north = rect.getNorth();
  406. var south = rect.getSouth();
  407. if(this._isScreen==false){
  408. var factor = 3.0;
  409. var xdis = Math.abs(east - west);
  410. var ydis = Math.abs(north - south);
  411. var xoff = xdis * (factor - 1) / 2.0;
  412. var yoff = ydis * (factor - 1) / 2.0;
  413. west -= xoff;
  414. east += xoff;
  415. north += yoff;
  416. south -= yoff;
  417. }else{
  418. //获取场景相机
  419. var viewer = this.viewer;
  420. var camera = viewer.scene.camera;
  421. var cartographic=Cesium.Cartographic.fromCartesian(camera.position);
  422. //获取场景高度
  423. var altitude =cartographic.height;
  424. //获取经度
  425. var longitude = Cesium.Math.toDegrees(cartographic.longitude);
  426. //获取纬度
  427. var latitude = Cesium.Math.toDegrees(cartographic.latitude);
  428. //根据给定的场景高度计算地图中显示范围的宽度
  429. var size = this._calculateSizeFromAltitude(altitude);
  430. size = size * 0.19;
  431. west=longitude - size;
  432. east=longitude + size;
  433. north=latitude + size;
  434. south=latitude - size;
  435. }
  436. if (west < -180) {
  437. west = -180;
  438. }
  439. if (east > 180) {
  440. east = 180;
  441. }
  442. if (north > 90) {
  443. north = 90;
  444. }
  445. if (south < -90) {
  446. south = -90;
  447. }
  448. var bounds = new L.LatLngBounds(
  449. new L.LatLng(north, west),
  450. new L.LatLng(south, east)
  451. );
  452. return bounds;
  453. },
  454. /// <summary>
  455. /// 根据给定的场景高度计算地图中显示范围的宽度
  456. /// </summary>
  457. /// <param name="altitude">场景高度</param>
  458. /// <returns>地图显示范围尺寸</returns>
  459. _calculateSizeFromAltitude(altitude) {
  460. var _PI = 3.1415926;
  461. var _earthRadius = 6378137;
  462. var size;
  463. if (altitude >= _earthRadius) {//当场景高度大于可全幅显示整球的高度时
  464. var ratio = (altitude + _earthRadius) * 0.5;
  465. size = 120 * ratio / _earthRadius
  466. }
  467. else {//当场景高度小于可全幅显示整球的高度时,即无法看到整球时
  468. var tan30 = Math.tan(_PI / 6);
  469. //设置方程组的a,b,c
  470. var a = (Math.pow(tan30, 2) + 1) * Math.pow(_earthRadius, 2);
  471. var b = -2 * (_earthRadius + altitude) * _earthRadius * Math.pow(tan30, 2);
  472. var c = Math.pow(tan30, 2) * Math.pow(_earthRadius + altitude, 2) - Math.pow(_earthRadius, 2.0);
  473. //解一元二次方程,取锐角,因此余弦值较大
  474. var cosd = (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
  475. var d = Math.acos(cosd);
  476. var widthd = 2 * d * _earthRadius;
  477. size = (widthd / (_PI * _earthRadius)) * 180;
  478. }
  479. return size;
  480. },
  481. /// <summary>
  482. /// 根据给定的地图范围计算场景的高度
  483. /// </summary>
  484. /// <param name="bounds">地图范围</param>
  485. /// <returns>场景高度</returns>
  486. _calculateAltitudeFromBounds(bounds) {
  487. var _PI = 3.1415926;
  488. var _earthRadius = 6378137;
  489. var altitude = _earthRadius;
  490. //var boundsWidth = bounds.right - bounds.left;
  491. var boundsWidth = bounds.getEast() - bounds.getWest();
  492. if (boundsWidth >= 120) {
  493. altitude = _earthRadius * boundsWidth / 60 - _earthRadius;
  494. }
  495. else if (boundsWidth != 0) {
  496. var angle1 = (boundsWidth / 360) * _PI;
  497. var height = Math.sin(angle1) * _earthRadius;
  498. var a = height / Math.tan(angle1);
  499. var b = height / Math.tan(_PI / 6);
  500. altitude = a + b - _earthRadius;
  501. }
  502. return altitude;
  503. },
  504. addPipeLayers :function (url, subLayers) {
  505. this.createTempLayer(url, subLayers);
  506. },
  507. getLayerStatusList: function (subLayers) {
  508. var parameters = new SuperMap.SetLayerStatusParameters();
  509. for (var i = 0; i < subLayers.length; i++) {
  510. var layerStatus = new SuperMap.LayerStatus();
  511. layerStatus.layerName = subLayers[i].name;
  512. layerStatus.isVisible = eval(subLayers[i].visible);
  513. parameters.layerStatusList.push(layerStatus);
  514. }
  515. parameters.holdTime=30;
  516. return parameters;
  517. },
  518. createTempLayer:function (url, subLayers) {
  519. var layerStatusParameters = this.getLayerStatusList(subLayers);
  520. L.supermap.layerInfoService(url).setLayerStatus(layerStatusParameters, function (createTempLayerEventArgs) {
  521. var tempLayerID = createTempLayerEventArgs.result.newResourceID;
  522. if(this.pipeLayerObj){
  523. this._miniMap.removeLayer(this.pipeLayerObj);
  524. }
  525. this.pipeLayerObj=L.supermap.tiledMapLayer(url, { layersID: tempLayerID });
  526. this.pipeLayerObj.addTo(this._miniMap);
  527. }.bind(this));
  528. },
  529. CLASS_NAME: "CesiumOverviewMapControl"
  530. };