|
|
@@ -0,0 +1,393 @@
|
|
|
+<template>
|
|
|
+ <div class="container">
|
|
|
+ <div class="map-container" v-if="isShow == 1">
|
|
|
+ <div id="skysceneryContainer"></div>
|
|
|
+ <div class="infoDialog" v-show="infoDialogShow">
|
|
|
+ <div class="close" @click="closeWin">×</div>
|
|
|
+ <div class="content" v-if="nowPoint != null">
|
|
|
+ <el-scrollbar>
|
|
|
+ <div class="item" v-for="info in nowPointInfo" :key="info">{{info.key}}: {{ info.value }}</div>
|
|
|
+ </el-scrollbar>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ <div class="page-content" v-if="isShow == 2">
|
|
|
+ <vue-office-excel
|
|
|
+ :src="excelUrl"
|
|
|
+ :options="{
|
|
|
+ xls: true,
|
|
|
+ xlsx: true,
|
|
|
+ }"
|
|
|
+ @rendered="onRendered"
|
|
|
+ @error="onError"
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ <div class="page-content" v-if="isShow == 3">
|
|
|
+ <div style="height: 100%; display: flex; align-items: center; justify-content: center;">
|
|
|
+ <el-empty class="custom-empty" description="不支持的文件类型" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script>
|
|
|
+import { ElMessage } from 'element-plus'
|
|
|
+import VueOfficeExcel from '@vue-office/excel'
|
|
|
+import '@vue-office/excel/lib/index.css'
|
|
|
+import { toRaw } from "vue";
|
|
|
+export default {
|
|
|
+ name: "",
|
|
|
+ components: {
|
|
|
+ VueOfficeExcel
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ dataJson:[],
|
|
|
+ pointImg:require('@static/images/point.png'),
|
|
|
+ geometryArr:[],
|
|
|
+ mapHandle:null,
|
|
|
+ infoDialogShow:false,
|
|
|
+ nowPoint: null,
|
|
|
+ nowPointInfo:null,
|
|
|
+ excelUrl:'',
|
|
|
+ loading:false,
|
|
|
+ error:'',
|
|
|
+ isShow:1,
|
|
|
+ };
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ const queryParams = new URLSearchParams(window.location.search);
|
|
|
+ let url = queryParams.get('url');
|
|
|
+ console.log(queryParams.get('url')); // 输出: value1
|
|
|
+ if(url){
|
|
|
+ let arr = url.split('.');
|
|
|
+ let type = arr[arr.length-1];
|
|
|
+ if(type == 'json' || type == 'geojson'){
|
|
|
+ let param = {url:url}
|
|
|
+ this.isShow = 1
|
|
|
+ window.SkySceneryConfig = {};
|
|
|
+ window.loadScripts([systemConfig.scriptMain]).then(() => {
|
|
|
+ this.creatMap();
|
|
|
+ setTimeout(() => {
|
|
|
+ this.getVectorData(param);
|
|
|
+ }, 1000)
|
|
|
+
|
|
|
+ });
|
|
|
+ }else if(type == 'xlsx' || type == 'xls'){
|
|
|
+ this.isShow = 2
|
|
|
+ this.excelUrl = url
|
|
|
+ this.loadExcel();
|
|
|
+ }else{
|
|
|
+ this.isShow = 3
|
|
|
+ // ElMessage.error('不支持的文件类型')
|
|
|
+ }
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ methods: {
|
|
|
+ onRendered() {
|
|
|
+ // ElMessage.success('Excel文件渲染完成')
|
|
|
+ },
|
|
|
+ loadExcel() {
|
|
|
+ if (!this.excelUrl) {
|
|
|
+ // this.error = '请输入Excel文件在线地址'
|
|
|
+ return
|
|
|
+ }
|
|
|
+ this.loading = true
|
|
|
+ this.error = ''
|
|
|
+ // 加载Excel文件,实际加载由VueOfficeExcel组件处理
|
|
|
+ setTimeout(() => {
|
|
|
+ this.loading = false
|
|
|
+ }, 1000)
|
|
|
+ },
|
|
|
+ onError(err) {
|
|
|
+ ElMessage.error('Excel文件加载失败:', err)
|
|
|
+ // this.error = 'Excel文件加载失败,请检查文件地址是否正确'
|
|
|
+ this.loading = false
|
|
|
+ },
|
|
|
+ creatMap() {
|
|
|
+ window.viewer = new SkyScenery.Viewer("skysceneryContainer", {
|
|
|
+ animation: false, //是否创建动画小器件,左下角仪表
|
|
|
+ baseLayerPicker: false, //是否显示图层选择器
|
|
|
+ imageryProvider: new SkyScenery.SingleTileImageryProvider({
|
|
|
+ url: (function createColorCanvas(color) {
|
|
|
+ var width = 1,
|
|
|
+ height = 1;
|
|
|
+ var canvas = document.createElement("canvas");
|
|
|
+ canvas.width = width;
|
|
|
+ canvas.height = height;
|
|
|
+ var ctx = canvas.getContext("2d");
|
|
|
+ ctx.fillStyle = color;
|
|
|
+ ctx.fillRect(0, 0, width, height);
|
|
|
+ return canvas.toDataURL();
|
|
|
+ })("#ffffff00"),
|
|
|
+ rectangle: SkyScenery.Rectangle.fromDegrees(-180.0, -90.0, 180.0, 90.0),
|
|
|
+ }),
|
|
|
+ fullscreenButton: false, //是否显示全屏按钮
|
|
|
+ geocoder: false, //是否显示geocoder小器件,右上角查询按钮
|
|
|
+ homeButton: false, //是否显示Home按钮
|
|
|
+ infoBox: false, //是否显示信息框
|
|
|
+ sceneModePicker: false, //是否显示3D/2D选择器
|
|
|
+ selectionIndicator: false, //是否显示选取指示器组件
|
|
|
+ timeline: false, //是否显示时间轴
|
|
|
+ navigationHelpButton: false, //是否显示右上角的帮助按钮
|
|
|
+ scene3DOnly: true, //如果设置为true,则所有几何图形以3D模式绘制以节约GPU资源
|
|
|
+ shouldAnimate: false, //是否自动播放
|
|
|
+ // 性能优化配置
|
|
|
+ requestRenderMode: true,
|
|
|
+ maximumRenderTimeChange: Infinity,
|
|
|
+ preserveDrawingBuffer: false,
|
|
|
+ useBrowserRecommendedResolution: true,
|
|
|
+ });
|
|
|
+
|
|
|
+ // 添加地图服务
|
|
|
+ viewer.imageryLayers.addImageryProvider(
|
|
|
+ new SkyScenery.ArcGisMapServerImageryProvider({
|
|
|
+ url:
|
|
|
+ "https://szlszxdt.qpservice.org.cn/internal_map/?servertype=shmap_blue_web&proxyToken=" +
|
|
|
+ SkySceneryConfig.token,
|
|
|
+ enablePickFeatures: false, // 禁用要素拾取功能以提高性能
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ // 定位
|
|
|
+ viewer.camera.setView({
|
|
|
+ destination: SkyScenery.Cartesian3.fromDegrees(121.1158994,31.15205574, 30000.0), // 设置位置
|
|
|
+ orientation: {
|
|
|
+ heading: SkyScenery.Math.toRadians(0.0), // 方向
|
|
|
+ pitch: SkyScenery.Math.toRadians(-90.0), // 倾斜角度
|
|
|
+ roll: 0,
|
|
|
+ },
|
|
|
+ });
|
|
|
+
|
|
|
+ },
|
|
|
+ closeWin() {
|
|
|
+ this.infoDialogShow = false;
|
|
|
+ this.nowPoint = null;
|
|
|
+ this.nowPointInfo = null;
|
|
|
+ },
|
|
|
+ dwanMap(){
|
|
|
+ let that = this;
|
|
|
+ if(that.geometryArr.length>0){
|
|
|
+ that.geometryArr.map(function (info) {
|
|
|
+ viewer.entities.remove(info)
|
|
|
+ })
|
|
|
+ }
|
|
|
+ that.geometryArr = that.dataJson.features.map(function (info) {
|
|
|
+ if(info.geometry.type == "Point"){
|
|
|
+ return that.addPoint(info)
|
|
|
+ }else if(info.geometry.type == "LineString"){
|
|
|
+ return that.addLine(info)
|
|
|
+ }else{
|
|
|
+ return that.addPolygon(info)
|
|
|
+ }
|
|
|
+
|
|
|
+ })
|
|
|
+ that.pointTCHandle();
|
|
|
+ },
|
|
|
+ addPolygon(param){
|
|
|
+ let arr = [];
|
|
|
+ param.geometry.coordinates.forEach(element => {
|
|
|
+ element.forEach(e => {
|
|
|
+ arr.push(e[0]);
|
|
|
+ arr.push(e[1]);
|
|
|
+ })
|
|
|
+ });
|
|
|
+ return viewer.entities.add(new SkyScenery.Entity({
|
|
|
+ name: " polygon",
|
|
|
+ polygon: {
|
|
|
+ hierarchy: {
|
|
|
+ positions: SkyScenery.Cartesian3.fromDegreesArray(arr)
|
|
|
+ },
|
|
|
+ heightReference: SkyScenery.HeightReference.CLAMP_TO_GROUND,
|
|
|
+ material: SkyScenery.Color.CYAN.withAlpha(0.5)
|
|
|
+ },
|
|
|
+ info: {
|
|
|
+ coor: [arr[0], arr[1]],
|
|
|
+ properties: param.properties
|
|
|
+ },
|
|
|
+ }));
|
|
|
+ },
|
|
|
+ addLine(param){
|
|
|
+ return viewer.entities.add({
|
|
|
+ name: "line",
|
|
|
+ polyline: {
|
|
|
+ //经纬度数组转世界坐标,带高度的话是fromDegreesArrayHeights
|
|
|
+ positions: SkyScenery.Cartesian3.fromDegreesArray(param.geometry.coordinates),
|
|
|
+ width: 2,
|
|
|
+ material: SkyScenery.Color.CYAN,
|
|
|
+ info: {
|
|
|
+ properties: param.properties
|
|
|
+ },
|
|
|
+ }
|
|
|
+ });
|
|
|
+ },
|
|
|
+ addPoint(param){
|
|
|
+ let that = this;
|
|
|
+ return viewer.entities.add(new SkyScenery.Entity({
|
|
|
+ name:"point",
|
|
|
+ position: SkyScenery.Cartesian3.fromDegrees(param.geometry.coordinates[0], param.geometry.coordinates[1]),
|
|
|
+ type: "point",
|
|
|
+ info: {
|
|
|
+ coor: [param.geometry.coordinates[0], param.geometry.coordinates[1]],
|
|
|
+ properties: param.properties
|
|
|
+ },
|
|
|
+ billboard: {
|
|
|
+ image: that.pointImg,
|
|
|
+ disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
|
|
+ scale: 0.3,
|
|
|
+ horizontalOrigin: SkyScenery.HorizontalOrigin.CENTER,
|
|
|
+ verticalOrigin: SkyScenery.VerticalOrigin.BOTTOM,
|
|
|
+ }
|
|
|
+ }));
|
|
|
+ },
|
|
|
+ // 点击事件绑定
|
|
|
+ pointTCHandle() {
|
|
|
+ let that = this;
|
|
|
+ if (!this.mapHandle) {
|
|
|
+ this.mapHandle = new SkyScenery.ScreenSpaceEventHandler(viewer.canvas, this);
|
|
|
+ this.mapHandle.setInputAction(function (movement) {
|
|
|
+ that.infoDialogShow = false
|
|
|
+ const pickedObject = viewer.scene.pick(movement.position);
|
|
|
+
|
|
|
+ let cartesian = viewer.camera.pickEllipsoid(
|
|
|
+ movement.position,
|
|
|
+ viewer.scene.globe.ellipsoid
|
|
|
+ );
|
|
|
+ // 空间坐标转世界坐标(弧度)
|
|
|
+ let cartographic = SkyScenery.Cartographic.fromCartesian(cartesian);
|
|
|
+ // 弧度转为角度(经纬度)
|
|
|
+ let lon = SkyScenery.Math.toDegrees(cartographic.longitude); // 经度值
|
|
|
+ let lat = SkyScenery.Math.toDegrees(cartographic.latitude); // 纬度值
|
|
|
+ let center = [lon,lat]
|
|
|
+ if (SkyScenery.defined(pickedObject) && SkyScenery.defined(pickedObject.id)) {
|
|
|
+ const entity = pickedObject.id;
|
|
|
+ that.infoDialogShow = true
|
|
|
+ that.nowPoint = entity.info;
|
|
|
+ that.nowPointInfo = Object.keys(that.nowPoint.properties).map(key => ({ key, value: that.nowPoint.properties[key] }));
|
|
|
+ that.nowPoint["type"] = "info";
|
|
|
+ // let xy = that.lonlatConvertToScreenXY(entity.info.coor)
|
|
|
+ let xy = that.lonlatConvertToScreenXY(center)
|
|
|
+ document.querySelector(".infoDialog").style.top = (xy.y - 230) + "px";
|
|
|
+ document.querySelector(".infoDialog").style.left = (xy.x - 100) + "px";
|
|
|
+ } else {
|
|
|
+ // console.log('未拾取到实体');
|
|
|
+ }
|
|
|
+ }, SkyScenery.ScreenSpaceEventType.LEFT_CLICK);
|
|
|
+ viewer.scene.postRender.addEventListener(that.updatePosition, this);
|
|
|
+ } else {
|
|
|
+ toRaw(this.mapHandle).destroy();
|
|
|
+ this.mapHandle = null
|
|
|
+ that.nowPointInfo = null
|
|
|
+ viewer.scene.postRender.removeEventListener(that.updatePosition, this);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 经纬度转屏幕坐标
|
|
|
+ lonlatConvertToScreenXY(lonlat) {
|
|
|
+ // 定义经纬度
|
|
|
+ var longitude = SkyScenery.Math.toRadians(lonlat[0]); // 例如:东经116.391度
|
|
|
+ var latitude = SkyScenery.Math.toRadians(lonlat[1]); // 例如:北纬39.907度
|
|
|
+ var height = 0; // 高度,通常在地表为0
|
|
|
+ // 将经纬度转换为笛卡尔坐标
|
|
|
+ // var cartographic = SkyScenery.Cartographic.fromDegrees(longitude, latitude, height);
|
|
|
+ var cartesian = SkyScenery.Cartesian3.fromRadians(longitude, latitude, height, viewer.scene.globe.ellipsoid);
|
|
|
+ // 将笛卡尔坐标转换为窗口坐标
|
|
|
+ var canvasCoordinates = viewer.scene.cartesianToCanvasCoordinates(cartesian);
|
|
|
+ return canvasCoordinates
|
|
|
+ },
|
|
|
+ // 位置更新
|
|
|
+ updatePosition() {
|
|
|
+ try {
|
|
|
+ if (this.nowPoint != null) {
|
|
|
+ const obj = toRaw(this.nowPoint);
|
|
|
+ let xy = this.lonlatConvertToScreenXY(obj.coor)
|
|
|
+ if (!xy) {
|
|
|
+ document.querySelector(".infoDialog").style.top = "-9999px";
|
|
|
+ document.querySelector(".infoDialog").style.left = "-9999px";
|
|
|
+ } else {
|
|
|
+ document.querySelector(".infoDialog").style.top = (xy.y - 230) + "px";
|
|
|
+ document.querySelector(".infoDialog").style.left = (xy.x - 100) + "px";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ // debugger
|
|
|
+ }
|
|
|
+ },
|
|
|
+
|
|
|
+ getVectorData(param){
|
|
|
+ let that = this;
|
|
|
+ fetch(param.url, {
|
|
|
+ method: 'GET',
|
|
|
+ }).then(response => response.json()) // 假设服务器返回 JSON 数据
|
|
|
+ .then(data => {
|
|
|
+ console.log('[ eee ] >')
|
|
|
+ that.dataJson = data;
|
|
|
+ that.closeWin()
|
|
|
+ that.dwanMap()
|
|
|
+ })
|
|
|
+ },
|
|
|
+ },
|
|
|
+ beforeDestroy() {
|
|
|
+ viewer = undefined
|
|
|
+ }
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="less" scoped>
|
|
|
+.container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ padding: 0px;
|
|
|
+ margin: 0 auto;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+.map-container {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+}
|
|
|
+.page-content {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ background-color: #fff;
|
|
|
+ border-radius: 4px;
|
|
|
+ box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
|
|
|
+ overflow: hidden;
|
|
|
+ }
|
|
|
+.infoDialog {
|
|
|
+ position: absolute;
|
|
|
+ top: 0px;
|
|
|
+ left: 0px;
|
|
|
+ max-width: 500px;
|
|
|
+ height: 200px;
|
|
|
+ // background: #01346f99;
|
|
|
+ background: #ffffff;
|
|
|
+ border-radius: 10px;
|
|
|
+
|
|
|
+ .close {
|
|
|
+ font-size: 24px;
|
|
|
+ position: absolute;
|
|
|
+ top: 6px;
|
|
|
+ right: 8px;
|
|
|
+ line-height: 24px;
|
|
|
+ width: 24px;
|
|
|
+ height: 24px;
|
|
|
+ cursor: pointer;
|
|
|
+ // color: #ffffff;
|
|
|
+ color: #000000;
|
|
|
+ }
|
|
|
+
|
|
|
+ .content {
|
|
|
+ height: 160px;
|
|
|
+ // color: #ffffff;
|
|
|
+ color: #000000;
|
|
|
+ margin: 30px 0px 10px 20px;
|
|
|
+ overflow: auto;
|
|
|
+ .item {
|
|
|
+ line-height: 30px;
|
|
|
+ margin-right: 20px;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+</style>
|