Cesium模型拖拽

一、父组件代码

<template>
  <div class="map">
      <div class=treeBox>
         <el-tree
          :data="treeData"
          :props="defaultProps"
          draggable
          highlight-current
          :allow-drop="allowDrop"
          :allow-drag="allowDrag"
          @node-drag-start="handleDragStart">
        </el-tree>
      </div>
  
      <div id="mapBox">
        <!-- middle-地图 -->
        <Cesium
          @drop.native="drop"
          @dragenter.native.prevent
          @dragover.native.prevent
          ref="cesiumRef"></Cesium>
      </div>
  </div>
</template>

<script>

import Cesium from './Cesium'

export default {
  name: "",
  components: {
      Cesium,
  },
  props: {},
  data() {
    return {
		// tree数据
		treeData:[
			{
				label:'飞机模型',
				value:1,
				path:'模型路径'
			}
		]
		defaultProps:{
			children:"children",
			label:"label",
			value:"value"
		}
		
		// 模型路径
		modelPath:null,
	};
  },
  computed: {},
  created() {},
  mounted() {},
  methods: {
    // -----------------------<<地图>>----------------------
    // 开始拖拽
    handleDragStart(node, ev) {
		this.modelPath = node.path
	},

    // 拖拽结束
    drop(e) {
      let toLeft = null, // cesium元素距离左边距离
        toTop = null, // cesium元素距离顶部距离
        x = null, // cesium元素屏幕坐标x轴位置
        y = null; // cesium元素屏幕坐标y轴位置

      // 获取cesium元素距离左边位置
      toLeft = document.getElementById("mapBox").getBoundingClientRect().left;
      // 获取cesium元素距离顶部位置
      toTop = document.getElementById("mapBox").getBoundingClientRect().top;

      // 计算地图屏幕坐标
      // 计算cesium元素屏幕坐标x轴位置
      x = e.clientX - toLeft;
      // 计算cesium元素屏幕坐标y轴位置
      y = e.clientY - toTop;

      //创建模型
      this.$refs.cesiumRef.addModel(this.modelPath, {x,y,});
    },
	
	// 是否允许拖拽
    allowDrag(draggingNode) {
      if (draggingNode.childNodes && draggingNode.childNodes.length !== 0) {
        return false;
      } else {
        return true;
      }
    },

    // 是否允许放置
    allowDrop(draggingNode, dropNode, type) {
      return false;
    },
  },
};
</script>

<style lang="less" scoped>
.map{
	width:100%;
	height:100vh;
	
	.treeBox{
		width:20%;
		height:100%;
	}
	
	.mapBox{
		widht:80%;
		height:100%;
	}
}

</style>

二、Cesium组件代码

<template>
  <div id="cesiumContainer">
  </div>
</template>

<script>
export default {
  name: "Cesium",
  components: {},
  data() {
    return {
      // ----------------------<<地图>>----------------------
      // cesium相机初始位置
      ps: {
        lon: 104.06,
        lat: 30.67,
        alt: 10000,
      },
	  
	  modelId:1,
    };
  },
  mounted() {
    this.initMap();
  },
  methods: {
    // ---------------------<<地图>>---------------------
    // 初始化地图
    initMap() {
      // 配置在线地图token
      Cesium.Ion.defaultAccessToken = "map-Key"

      //在线地图
      imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
          url: "在线地图地址",
        });

      window.viewer = new Cesium.Viewer("cesiumContainer", {
        geocoder: false, //右上角搜索
        homeButton: false, //右上角home
        sceneModePicker: false, //右上角2D/3D切换
        baseLayerPicker: false, //右上角地形
        navigationHelpButton: false, //右上角帮助
        animation: false, //左下角圆盘动画控件
        timeline: true, //底部时间轴
        fullscreenButton: false, //右下角全屏控件
        vrButton: false, //如果设置为true,将创建VRButton小部件。
        scene3DOnly: false, // 每个几何实例仅以3D渲染以节省GPU内存
        infoBox: false, //隐藏点击要素后的提示信息
        imageryProvider: imageryProvider, //地图地址
      });

      // 隐藏左下角商标信息
      viewer._cesiumWidget._creditContainer.style.display = "none";
      // 隐藏底部时间轴
      viewer.timeline.container.style.display = "none";
      viewer.scene.globe.depthTestAgainstTerrain = true; //开启深度检测

      // 相机初始位置
      viewer.camera.setView({
        destination: Cesium.Cartesian3.fromDegrees(
          this.ps.lon,
          this.ps.lat,
          this.ps.alt
        ),
        // 方向,俯视和仰视的视角
        orientation: {
          heading: Cesium.Math.toRadians(0), //坐标系旋转0度
          pitch: Cesium.Math.toRadians(-90), //设置俯仰角度为-15度
        },
      });
    },

    addModel(path, ps) {
      // 鼠标位置转换为二维笛卡尔坐标
      const twoCoordinate = new Cesium.Cartesian2(ps.x, ps.y);

      // 获取鼠标位置的对应椭球面位置
      const wordCoordinate = viewer.scene.camera.pickEllipsoid(
        twoCoordinate,
        viewer.scene.globe.ellipsoid
      );

      // 笛卡尔坐标转弧度
      let cartographic = Cesium.Cartographic.fromCartesian(
        wordCoordinate,
        viewer.scene.globe.ellipsoid,
        new Cesium.Cartographic()
      );

      // Cesium.Math.toDegrees 将弧度转换成经纬度
      let lng = Cesium.Math.toDegrees(cartographic.longitude);
      let lat = Cesium.Math.toDegrees(cartographic.latitude);
      let alt = 1000;

      // 转换笛卡尔空间直角坐标
      let position = new Cesium.Cartesian3.fromDegrees(lng, lat, alt);

      //模型朝向
      const heading = Cesium.Math.toRadians(0);
      const pitch = 0;
      const roll = 0;
      const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
      const orientation = Cesium.Transforms.headingPitchRollQuaternion(
        position,
        hpr
      );

      const entity = viewer.entities.add({
		id:"plane" + this.modelId,
        position: position, //模型位置,高度
        orientation: orientation,
        model: {
          uri: path, //模型文件
          minimumPixelSize: 100, //模型最小像素大小
          maximumScale: 1000, //模型最大像素大小
        },
      });

      // 同一场景modelId自增
      this.modelId++;

      // 定位到模型
      // viewer.trackedEntity = entity;
    },
  },
};
</script>

<style lang="less" scoped>
#cesiumContainer {
  width: 100%;
  height: 100%;
  position: relative;
}
</style>

123

三、Cesiun模型拖拽

        已添加到地图的模型拖拽功能

// 注册鼠标事件-模型拖拽
setMouseEvent() {
  let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

  // *****注册鼠标左键按下事件*****
  handler.setInputAction((event) => {
    let pick = viewer.scene.pick(event.position);

    // 如果点击空白区域
    if (!Cesium.defined(pick)) {
      return;
    }

    // 将相机锁定,不然后续移动实体时相机也会动
    // 左键拖拽锁定视角
    // viewer.scene.screenSpaceCameraController.enableRotate = false;
    // 右键拖拽锁定视角
    viewer.scene.screenSpaceCameraController.enableZoom = false;

    //设置选中时的颜色
    pick.id.model.color = Cesium.Color.fromAlpha(Cesium.Color.TOMATO, 0.5);

    // *****注册鼠标移动事件*****
    viewer.screenSpaceEventHandler.setInputAction((arg) => {
      // arg有startPosition与endPosition两个属性,即移动前后的位置信息:Cartesian2对象
      const position = arg.endPosition;
      const cartesian = viewer.scene.globe.pick(
        viewer.camera.getPickRay(position),
        viewer.scene
      );

      //将Cartesian2转为Cartesian3
      pick.id.position._value = cartesian;
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    // *****注册鼠标抬起事件*****
    viewer.screenSpaceEventHandler.setInputAction(({ position }) => {
      // 取消相机锁定
      viewer.scene.screenSpaceCameraController.enableRotate = true;
      pick.id.model.color = null; //设置颜色

      // *****解除viewer的MOUSE_MOVE事件监听器*****
      viewer.screenSpaceEventHandler.removeInputAction(
        Cesium.ScreenSpaceEventType.MOUSE_MOVE
      );

      // 解除相机锁定
      viewer.scene.screenSpaceCameraController.enableZoom = true;
    }, Cesium.ScreenSpaceEventType.RIGHT_UP);
  }, Cesium.ScreenSpaceEventType.RIGHT_DOWN);
},

### 实现Cesium中三维模型的卷帘对比 在Cesium实现三维模型的卷帘对比主要依赖于创建两个不同视角或状态下的模型实例,并通过拖动分隔线来切换显示区域。具体来说,这涉及到设置`splitDirection`属性以及处理鼠标事件以更新视图。 #### HTML结构定义 为了支持交互式的卷帘操作,在页面上需增加一个用于表示分割线的HTML元素: ```html <div id="slider"></div> ``` 此元素被定位为绝对布局并置于场景中央作为垂直方向上的分界线[^3]。 #### CSS样式配置 对于上述`<div>`标签应用特定CSS规则使其外观适合作为可拖拽的手柄: ```css #slider { position: absolute; left: 50%; top: 0px; background-color: #d3d3d3; width: 5px; height: 100%; z-index: 9999; } #slider:hover { cursor: ew-resize; } ``` 这些样式使得该条目看起来像一条细长矩形框位于屏幕中间位置,并且当鼠标悬停其上方时会改变光标的形状提示用户可以水平调整宽度。 #### JavaScript逻辑编写 接下来是核心部分——JavaScript代码负责监听用户的输入动作并将之转化为实际渲染变化。这里假设已经初始化了一个名为`viewer`的对象代表整个Cesium Viewer环境。 首先加载两个不同的3D Tiles数据集分别对应左侧和右侧要展示的内容: ```javascript const viewerLeft = new Cesium.Viewer('cesiumContainer', {}); const viewerRight = new Cesium.Viewer('cesiumContainer', {}); // 加载左半边的数据源 viewerLeft.scene.primitives.add( Cesium.createTileset({ url : 'path/to/left/tileset.json' }) ); // 加载右半边的数据源 viewerRight.scene.primitives.add( Cesium.createTileset({ url : 'path/to/right/tileset.json' }) ); ``` 接着定义滑块的位置变量及相应的DOM Event Handler函数用来控制可视范围的变化: ```javascript let splitPosition = 0.5; document.getElementById('slider').addEventListener('mousedown', function(event){ document.addEventListener('mousemove', onMouseMove, false); }); function onMouseMove(event){ const rect = viewer.canvas.getBoundingClientRect(); let mouseX = event.clientX - rect.left; // 计算新的比例值 splitPosition = (mouseX / rect.width).toFixed(2); updateSplitView(splitPosition); } function updateSplitView(position){ // 更新左右两侧相机参数保持同步视角 viewerRight.camera.setView(viewerLeft.camera.viewRectangle); // 设置裁剪平面使超过指定界限的部分不可见 viewerLeft.scene.fxaa.enabled = true; viewerLeft.scene.postProcessStages.stencilMask.executeInOrder = true; viewerLeft.scene.globe.depthTestAgainstTerrain = true; var clipPlane = new Cesium.ClipPlanex(Cesium.Cartesian4(-position, 0, 0, 0)); viewerLeft.scene.frustumNearFarScalar = [clipPlane]; viewerRight.scene.fxaa.enabled = true; viewerRight.scene.postProcessStages.stencilMask.executeInOrder = true; viewerRight.scene.globe.depthTestAgainstTerrain = true; var clipPlaneR = new Cesium.ClipPlanes([new Cesium.Plane(new Cesium.Cartographic(Math.PI * (-position), Math.PI / 2, 0))]); viewerRight.scene.clipPlanes = clipPlaneR; } ``` 以上脚本片段实现了基本的功能需求:允许用户通过击并拖曳的方式动态修改两组地理空间对象之间的可见边界。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值