viewPreview.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. <template>
  2. <div class="container">
  3. <div class="map-container" v-if="isShow == 1">
  4. <div id="skysceneryContainer"></div>
  5. <div class="infoDialog" v-show="infoDialogShow">
  6. <div class="close" @click="closeWin">×</div>
  7. <div class="content" v-if="nowPoint != null">
  8. <el-scrollbar>
  9. <div class="item" v-for="info in nowPointInfo" :key="info">{{info.key}}: {{ info.value }}</div>
  10. </el-scrollbar>
  11. </div>
  12. </div>
  13. </div>
  14. <div class="page-content" v-if="isShow == 2">
  15. <vue-office-excel
  16. :src="excelUrl"
  17. :options="{
  18. xls: true,
  19. xlsx: true,
  20. }"
  21. @rendered="onRendered"
  22. @error="onError"
  23. />
  24. </div>
  25. <div class="page-content" v-if="isShow == 3">
  26. <div style="height: 100%; display: flex; align-items: center; justify-content: center;">
  27. <el-empty class="custom-empty" description="不支持的文件类型" />
  28. </div>
  29. </div>
  30. </div>
  31. </template>
  32. <script>
  33. import { ElMessage } from 'element-plus'
  34. import VueOfficeExcel from '@vue-office/excel'
  35. import '@vue-office/excel/lib/index.css'
  36. import { toRaw } from "vue";
  37. export default {
  38. name: "",
  39. components: {
  40. VueOfficeExcel
  41. },
  42. data() {
  43. return {
  44. dataJson:[],
  45. pointImg:require('@static/images/point.png'),
  46. geometryArr:[],
  47. mapHandle:null,
  48. infoDialogShow:false,
  49. nowPoint: null,
  50. nowPointInfo:null,
  51. excelUrl:'',
  52. loading:false,
  53. error:'',
  54. isShow:1,
  55. };
  56. },
  57. created() {
  58. },
  59. mounted() {
  60. const queryParams = new URLSearchParams(window.location.search);
  61. let url = queryParams.get('url');
  62. console.log(queryParams.get('url')); // 输出: value1
  63. if(url){
  64. let arr = url.split('.');
  65. let type = arr[arr.length-1];
  66. if(type == 'json' || type == 'geojson'){
  67. let param = {url:url}
  68. this.isShow = 1
  69. window.SkySceneryConfig = {};
  70. window.loadScripts([systemConfig.scriptMain]).then(() => {
  71. this.creatMap();
  72. setTimeout(() => {
  73. this.getVectorData(param);
  74. }, 1000)
  75. });
  76. }else if(type == 'xlsx' || type == 'xls'){
  77. this.isShow = 2
  78. this.excelUrl = url
  79. this.loadExcel();
  80. }else{
  81. this.isShow = 3
  82. // ElMessage.error('不支持的文件类型')
  83. }
  84. }
  85. },
  86. methods: {
  87. onRendered() {
  88. // ElMessage.success('Excel文件渲染完成')
  89. },
  90. loadExcel() {
  91. if (!this.excelUrl) {
  92. // this.error = '请输入Excel文件在线地址'
  93. return
  94. }
  95. this.loading = true
  96. this.error = ''
  97. // 加载Excel文件,实际加载由VueOfficeExcel组件处理
  98. setTimeout(() => {
  99. this.loading = false
  100. }, 1000)
  101. },
  102. onError(err) {
  103. ElMessage.error('Excel文件加载失败:', err)
  104. // this.error = 'Excel文件加载失败,请检查文件地址是否正确'
  105. this.loading = false
  106. },
  107. creatMap() {
  108. window.viewer = new SkyScenery.Viewer("skysceneryContainer", {
  109. animation: false, //是否创建动画小器件,左下角仪表
  110. baseLayerPicker: false, //是否显示图层选择器
  111. imageryProvider: new SkyScenery.SingleTileImageryProvider({
  112. url: (function createColorCanvas(color) {
  113. var width = 1,
  114. height = 1;
  115. var canvas = document.createElement("canvas");
  116. canvas.width = width;
  117. canvas.height = height;
  118. var ctx = canvas.getContext("2d");
  119. ctx.fillStyle = color;
  120. ctx.fillRect(0, 0, width, height);
  121. return canvas.toDataURL();
  122. })("#ffffff00"),
  123. rectangle: SkyScenery.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
  124. }),
  125. fullscreenButton: false, //是否显示全屏按钮
  126. geocoder: false, //是否显示geocoder小器件,右上角查询按钮
  127. homeButton: false, //是否显示Home按钮
  128. infoBox: false, //是否显示信息框
  129. sceneModePicker: false, //是否显示3D/2D选择器
  130. selectionIndicator: false, //是否显示选取指示器组件
  131. timeline: false, //是否显示时间轴
  132. navigationHelpButton: false, //是否显示右上角的帮助按钮
  133. scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
  134. shouldAnimate: false, //是否自动播放
  135. // 性能优化配置
  136. requestRenderMode: true,
  137. maximumRenderTimeChange: Infinity,
  138. preserveDrawingBuffer: false,
  139. useBrowserRecommendedResolution: true,
  140. });
  141. // 添加地图服务
  142. viewer.imageryLayers.addImageryProvider(
  143. new SkyScenery.ArcGisMapServerImageryProvider({
  144. url:
  145. "https://szlszxdt.qpservice.org.cn/internal_map/?servertype=shmap_blue_web&proxyToken=" +
  146. SkySceneryConfig.token,
  147. enablePickFeatures: false, // 禁用要素拾取功能以提高性能
  148. })
  149. );
  150. // 定位
  151. viewer.camera.setView({
  152. destination: SkyScenery.Cartesian3.fromDegrees(121.1158994,31.15205574, 30000.0), // 设置位置
  153. orientation: {
  154. heading: SkyScenery.Math.toRadians(0.0), // 方向
  155. pitch: SkyScenery.Math.toRadians(-90.0), // 倾斜角度
  156. roll: 0,
  157. },
  158. });
  159. },
  160. closeWin() {
  161. this.infoDialogShow = false;
  162. this.nowPoint = null;
  163. this.nowPointInfo = null;
  164. },
  165. dwanMap(){
  166. let that = this;
  167. if(that.geometryArr.length>0){
  168. that.geometryArr.map(function (info) {
  169. viewer.entities.remove(info)
  170. })
  171. }
  172. that.geometryArr = that.dataJson.features.map(function (info) {
  173. if(info.geometry.type == "Point"){
  174. return that.addPoint(info)
  175. }else if(info.geometry.type == "LineString"){
  176. return that.addLine(info)
  177. }else{
  178. return that.addPolygon(info)
  179. }
  180. })
  181. that.pointTCHandle();
  182. },
  183. addPolygon(param){
  184. let arr = [];
  185. param.geometry.coordinates.forEach(element => {
  186. element.forEach(e => {
  187. arr.push(e[0]);
  188. arr.push(e[1]);
  189. })
  190. });
  191. return viewer.entities.add(new SkyScenery.Entity({
  192. name: " polygon",
  193. polygon: {
  194. hierarchy: {
  195. positions: SkyScenery.Cartesian3.fromDegreesArray(arr)
  196. },
  197. heightReference: SkyScenery.HeightReference.CLAMP_TO_GROUND,
  198. material: SkyScenery.Color.CYAN.withAlpha(0.5)
  199. },
  200. info: {
  201. coor: [arr[0], arr[1]],
  202. properties: param.properties
  203. },
  204. }));
  205. },
  206. addLine(param){
  207. return viewer.entities.add({
  208. name: "line",
  209. polyline: {
  210. //经纬度数组转世界坐标,带高度的话是fromDegreesArrayHeights
  211. positions: SkyScenery.Cartesian3.fromDegreesArray(param.geometry.coordinates),
  212. width: 2,
  213. material: SkyScenery.Color.CYAN,
  214. info: {
  215. properties: param.properties
  216. },
  217. }
  218. });
  219. },
  220. addPoint(param){
  221. let that = this;
  222. return viewer.entities.add(new SkyScenery.Entity({
  223. name:"point",
  224. position: SkyScenery.Cartesian3.fromDegrees(param.geometry.coordinates[0], param.geometry.coordinates[1]),
  225. type: "point",
  226. info: {
  227. coor: [param.geometry.coordinates[0], param.geometry.coordinates[1]],
  228. properties: param.properties
  229. },
  230. billboard: {
  231. image: that.pointImg,
  232. disableDepthTestDistance: Number.POSITIVE_INFINITY,
  233. scale: 0.3,
  234. horizontalOrigin: SkyScenery.HorizontalOrigin.CENTER,
  235. verticalOrigin: SkyScenery.VerticalOrigin.BOTTOM,
  236. }
  237. }));
  238. },
  239. // 点击事件绑定
  240. pointTCHandle() {
  241. let that = this;
  242. if (!this.mapHandle) {
  243. this.mapHandle = new SkyScenery.ScreenSpaceEventHandler(viewer.canvas, this);
  244. this.mapHandle.setInputAction(function (movement) {
  245. that.infoDialogShow = false
  246. const pickedObject = viewer.scene.pick(movement.position);
  247. let cartesian = viewer.camera.pickEllipsoid(
  248. movement.position,
  249. viewer.scene.globe.ellipsoid
  250. );
  251. // 空间坐标转世界坐标(弧度)
  252. let cartographic = SkyScenery.Cartographic.fromCartesian(cartesian);
  253. // 弧度转为角度(经纬度)
  254. let lon = SkyScenery.Math.toDegrees(cartographic.longitude); // 经度值
  255. let lat = SkyScenery.Math.toDegrees(cartographic.latitude); // 纬度值
  256. let center = [lon,lat]
  257. if (SkyScenery.defined(pickedObject) && SkyScenery.defined(pickedObject.id)) {
  258. const entity = pickedObject.id;
  259. that.infoDialogShow = true
  260. that.nowPoint = entity.info;
  261. that.nowPointInfo = Object.keys(that.nowPoint.properties).map(key => ({ key, value: that.nowPoint.properties[key] }));
  262. that.nowPoint["type"] = "info";
  263. // let xy = that.lonlatConvertToScreenXY(entity.info.coor)
  264. let xy = that.lonlatConvertToScreenXY(center)
  265. document.querySelector(".infoDialog").style.top = (xy.y - 230) + "px";
  266. document.querySelector(".infoDialog").style.left = (xy.x - 100) + "px";
  267. } else {
  268. // console.log('未拾取到实体');
  269. }
  270. }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
  271. viewer.scene.postRender.addEventListener(that.updatePosition, this);
  272. } else {
  273. toRaw(this.mapHandle).destroy();
  274. this.mapHandle = null
  275. that.nowPointInfo = null
  276. viewer.scene.postRender.removeEventListener(that.updatePosition, this);
  277. }
  278. },
  279. // 经纬度转屏幕坐标
  280. lonlatConvertToScreenXY(lonlat) {
  281. // 定义经纬度
  282. var longitude = SkyScenery.Math.toRadians(lonlat[0]); // 例如:东经116.391度
  283. var latitude = SkyScenery.Math.toRadians(lonlat[1]); // 例如:北纬39.907度
  284. var height = 0; // 高度,通常在地表为0
  285. // 将经纬度转换为笛卡尔坐标
  286. // var cartographic = SkyScenery.Cartographic.fromDegrees(longitude, latitude, height);
  287. var cartesian = SkyScenery.Cartesian3.fromRadians(longitude, latitude, height, viewer.scene.globe.ellipsoid);
  288. // 将笛卡尔坐标转换为窗口坐标
  289. var canvasCoordinates = viewer.scene.cartesianToCanvasCoordinates(cartesian);
  290. return canvasCoordinates
  291. },
  292. // 位置更新
  293. updatePosition() {
  294. try {
  295. if (this.nowPoint != null) {
  296. const obj = toRaw(this.nowPoint);
  297. let xy = this.lonlatConvertToScreenXY(obj.coor)
  298. if (!xy) {
  299. document.querySelector(".infoDialog").style.top = "-9999px";
  300. document.querySelector(".infoDialog").style.left = "-9999px";
  301. } else {
  302. document.querySelector(".infoDialog").style.top = (xy.y - 230) + "px";
  303. document.querySelector(".infoDialog").style.left = (xy.x - 100) + "px";
  304. }
  305. }
  306. } catch (error) {
  307. // debugger
  308. }
  309. },
  310. getVectorData(param){
  311. let that = this;
  312. fetch(param.url, {
  313. method: 'GET',
  314. }).then(response => response.json()) // 假设服务器返回 JSON 数据
  315. .then(data => {
  316. console.log('[ eee ] >')
  317. that.dataJson = data;
  318. that.closeWin()
  319. that.dwanMap()
  320. })
  321. },
  322. },
  323. beforeDestroy() {
  324. viewer = undefined
  325. }
  326. };
  327. </script>
  328. <style lang="less" scoped>
  329. .container {
  330. width: 100%;
  331. height: 100%;
  332. padding: 0px;
  333. margin: 0 auto;
  334. overflow: hidden;
  335. }
  336. .map-container {
  337. width: 100%;
  338. height: 100%;
  339. }
  340. .page-content {
  341. width: 100%;
  342. height: 100%;
  343. background-color: #fff;
  344. border-radius: 4px;
  345. box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
  346. overflow: hidden;
  347. }
  348. .infoDialog {
  349. position: absolute;
  350. top: 0px;
  351. left: 0px;
  352. max-width: 500px;
  353. height: 200px;
  354. // background: #01346f99;
  355. background: #ffffff;
  356. border-radius: 10px;
  357. .close {
  358. font-size: 24px;
  359. position: absolute;
  360. top: 6px;
  361. right: 8px;
  362. line-height: 24px;
  363. width: 24px;
  364. height: 24px;
  365. cursor: pointer;
  366. // color: #ffffff;
  367. color: #000000;
  368. }
  369. .content {
  370. height: 160px;
  371. // color: #ffffff;
  372. color: #000000;
  373. margin: 30px 0px 10px 20px;
  374. overflow: auto;
  375. .item {
  376. line-height: 30px;
  377. margin-right: 20px;
  378. }
  379. }
  380. }
  381. </style>