地图坐标以及点击弹框

2022/8/16 cesium三维地图

# 点位显示

export default {
  ...
  mounted () {
    this.init()
    this.loadPoints()
  },
  // Vue方法定义
  methods: {
    // 地图初始化
    init() {
      ...
    },
    // 模拟点位数据
    loadPoints() {
      // 用模拟数据测试
      this.pointInfo = [
        {
          id: '392f7fbb-ae25-4eef-ac43-58fd91148d1f',
          latitude: '31.87532',
          longitude: '120.55538',
          psName: '有限公司1',
        },
        {
          id: '0278a88c-b4f4-4d64-9ccb-65831b3fb19d',
          latitude: '31.991057',
          longitude: '120.700713',
          psName: '有限公司2',
        },
        {
          id: '248f6853-2ced-4aa6-b679-ea6422a5f3ac',
          latitude: '31.94181',
          longitude: '120.51517',
          psName: '有限公司3',
        },
        {
          id: 'F8DADA95-A438-49E1-B263-63AE3BD7DAC4',
          latitude: '31.97416',
          longitude: '120.56132',
          psName: '有限公司4',
        },
        {
          id: '9402a911-78c5-466a-9162-d5b04d0e48f0',
          latitude: '31.91604',
          longitude: '120.57771',
          psName: '有限公司5',
        },
        {
          id: 'EB392DD3-6998-437F-8DCB-F805AD4DB340',
          latitude: '31.88727',
          longitude: '120.48887',
          psName: '有限公司6',
        },
      ]
      this.addMarker()
    },
    // cesium 加载点位
    addMarker() {
      const Cesium = this.cesium
      // 清除上一次加载的点位
      this.viewer.entities.removeAll()
      // foreach循环加载点位
      this.pointInfo.forEach((pointObj) => {
        this.viewer.entities.add({
          name: pointObj.psName,
          code: pointObj.id,
          id: pointObj.id,
          position: Cesium.Cartesian3.fromDegrees(pointObj.longitude * 1, pointObj.latitude * 1),
          // 点
          // point: {
          //   pixelSize: 5,
          //   color: Cesium.Color.RED,
          //   outlineColor: Cesium.Color.WHITE,
          //   outlineWidth: 2,
          // },
          // 文字标签
          label: {
            // show: false,
            text: pointObj.psName,  
            font: "12px monospace",
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            fillColor: Cesium.Color.fromCssColorString("rgb(11, 255, 244)"),
            outlineWidth: 4,
            verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // 垂直方向以底部来计算标签的位置
            pixelOffset: new Cesium.Cartesian2(0, -20), // 偏移量
          },
           // 图标
          billboard: {
            image: require("@/assets/logo.png"),
            width: 18,
            height: 24,
          },
        })
      })
    },
  }
}

这里用到啦API中的viewer (opens new window)entities.removeAll() (opens new window)entities.add() (opens new window)

# 点击坐标弹框显示

引入弹框组件

// 地图组件
<template>
  <div class="map-box">
    <div id="cesiumContainer"></div>
     <!-- 地图弹框 -->
    <div class="dynamic-layer" id="one">
      <div class="line"></div>
      <div class="main">
        <cesiumPopup :pointInfo="popData" ref="popUp" />
        <!-- 下方箭头 -->
          <div class="tooltip-arrow"></div>
      </div>
    </div>
  </div>
</template>
// 弹框组件
<template>
  <div>
    我是弹框
  </div>
</template>

<script>
export default {
  name: '',
  props:['pointInfo'],
  // Vue方法定义
  methods: {
    defalutSetting() {},
  }
}
</script>

用到啦jQuery 需要 npm i jQuery 安装挂载到main.js中

import $ from 'jquery';
Vue.prototype.$ = $;

给地图绑定点击事件,使弹框元素出现

init(){
  ...
  // 给全图绑定事件
  const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
  handler.setInputAction((click)=>{
    // 屏幕坐标 转 世界坐标
    const cartesian = this.viewer.camera.pickEllipsoid(click.position,this.viewer.scene.globe.ellipsoid)
    // 世界坐标 转 地理坐标
    const cartographic = Cesium.Cartographic.fromCartesian(cartesian)

    // 保留5位数以十进制方式显示
    const lon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(5)
    const lat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(5)
    console.log("🚀 ~ file: No01-init.vue ~ line 76 ~ handler.setInputAction ~ lat lon",lon,lat)
    // 获取地图上的点位实体(entity)坐标
    const pick = this.viewer.scene.pick(click.position);
    console.log("🚀 ~ file: No01-init.vue ~ line 92 ~ handler.setInputAction ~ pick", pick)
    // 如果pick不是undefined 那么他就是点位
    if(pick&&pick.id){
      const data = {
        layerId: "layer1", // 英文,且唯一,内部entity会用得到
        lon: lon,
        lat: lat,
        element: "#one", // 弹框的唯一id
        boxHeightMax: 0, // 中间立方体的最大高度
      };
      this.$("#one").css("z-index", 9990);
      this.showDynamicLayer(this.viewer, data, () => { // 回调函数 改变弹窗的内容;
        this.popData.title = pick.id.name;
        this.popData.pointId = pick.id.id;
      });
      // 调用弹框的默认方法
      this.$refs.popUp.defalutSetting();

      // 点位地图定位
      this.locationToCenter(lon, lat);
    } else {
      // 移除弹框
      if (document.querySelector("#one")) {
        this.removeDynamicLayer(this.viewer, { element: "#one" });
        this.$("#one").css("z-index", -1);
      }
    }
    
  },Cesium.ScreenSpaceEventType.LEFT_CLICK)  //函数方法 单击
},
// 创建一个动态实体弹窗
showDynamicLayer(viewer, data, callback) {
  /* 弹窗的dom操作--默认必须*/
  this.$(data.element).css({ opacity: 0 }); // 使用hide()或者display是不行的 因为cesium是用pre定时重绘的div导致 left top display 会一直重绘
  this.$(".dynamic-layer .line").css({ width: 0 });
  this.$(data.element).find(".main").hide(0);
  /* 弹窗的dom操作--针对性操作*/
  callback();

  // 添加div弹窗
  const lon = data.lon * 1, lat = data.lat * 1;
  // data.boxHeightMax为undef也没事
  var divPosition = this.cesium.Cartesian3.fromDegrees(lon, lat, data.boxHeightMax);
  this.$("#one").css({ opacity: 1 });
  this.$("#one").find(".line").animate({
    width: 50 // 线的宽度
  }, 500, () => {
    this.$("#one").find(".main").fadeIn(500);
  });
  // 当为true的时候,表示当element在地球背面会自动隐藏。默认为false,置为false,不会这样。但至少减轻判断计算压力
  this.creatHtmlElement(viewer, data.element, divPosition, [10, -0], true);
},
// 创建一个 htmlElement元素 并且,其在earth背后会自动隐藏
creatHtmlElement(viewer, element, position, arr, flog) {
  const Cesium = this.cesium;
  var ele = document.querySelector(element);
  var scratch = new Cesium.Cartesian2(); // cesium二维笛卡尔 笛卡尔二维坐标系就是我们熟知的而二维坐标系;三维也如此
  var scene = viewer.scene, camera = viewer.camera;
  scene.preRender.addEventListener(() => {
    var canvasPosition = scene.cartesianToCanvasCoordinates(position, scratch); // cartesianToCanvasCoordinates 笛卡尔坐标(3维度)到画布坐标
    if (Cesium.defined(canvasPosition)) {
      ele.style.left = (canvasPosition.x + arr[0] - 534/2 - 15 + 5) + 'px';
      ele.style.top = (canvasPosition.y + arr[1] - 30 - 22) + 'px';
      /* 此处进行判断**/// var px_position = Cesium.SceneTransforms.wgs84ToWindowCoordinates(scene, cartesian)
      if (flog && flog == true) {
        var e = position, i = camera.position, n = scene.globe.ellipsoid.cartesianToCartographic(i).height
        if (!(n += 1 * scene.globe.ellipsoid.maximumRadius, Cesium.Cartesian3.distance(i, e) > n)) {
          // $(element).show()
          ele.style.display = "block";
        } else {
          ele.style.display = "none";
          // $(element).hide()
        }
      }
    }
  });
},
// 移除动态弹窗 为了方便 这里的移除 是真的移除,因此 到时是需要重建弹窗的doom的
removeDynamicLayer(viewer, data) {
  document.querySelector(data.element).style.opacity = 0;
},

# 定位中心点在地图中间

init(){
  ...
  // 给全图绑定事件
  const handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas); 
  handler.setInputAction((click)=>{
    // 点位地图定位
    this.locationToCenter(lon, lat);
  },Cesium.ScreenSpaceEventType.LEFT_CLICK)
  ...
},
// 点位定位到地图中心
locationToCenter(lon, lat) {
  const Cesium = this.cesium;
  const pointLocation = new Cesium.BoundingSphere(Cesium.Cartesian3.fromDegrees(lon * 1, lat * 1, 100), 15000); // 120.55538, 31.87532
  this.viewer.camera.flyToBoundingSphere(pointLocation);
},

Last Updated: 2023/3/6 21:56:10