cesium 键盘控制相机移动

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

import { onMounted, reactive, ref, onBeforeUnmount } from 'vue';
import * as Cesium from 'cesium';

let viewer, scene, canvas;

onMounted(() => {
  // cesium 初始化
  Cesium.Ion.defaultAccessToken = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI0ZDJiYWZjNy01YWIzLTQ5MDQtOWRjMC1lNzRjMzZlNDkxZjgiLCJpZCI6MTYzNzI4LCJpYXQiOjE2OTM0NzM4NTZ9.TZLI1V4-2pYZoVSbt-zOkV7Yx7elhjAsqfFt5h4Nrlk';
  //加载影像图层
  const esri = new Cesium.ArcGisMapServerImageryProvider({
    url: "https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer",
    enablePickFeatures: false,
    layer: "img",
    style: "default",
    tileMatrixSetID: "w",
    format: "tiles",
    maximumLevel: 18,
  });
  window.viewer = viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider: Cesium.createWorldTerrain({
      requestVertexNormals: true,
      requestWaterMask: true
    }),
    imageryProvider: esri,
    shouldAnimate: true, //是否允许动画
    selectionIndicator: false,
    baseLayerPicker: false,
    fullscreenButton: false,
    geocoder: false,
    homeButton: false,
    infoBox: false,
    sceneModePicker: false,
    timeline: false,
    navigationHelpButton: false,
    navigationInstructionsInitiallyVisible: false,
    showRenderLoopErrors: false,
    shadows: false,
  });
  // 显示帧率
  viewer.scene.debugShowFramesPerSecond = true;
  viewer._cesiumWidget._creditContainer.style.display = "none"; //去除版权信息
  viewer.scene.globe.depthTestAgainstTerrain = true;
  scene = viewer.scene;
  canvas = viewer.canvas;//获取画布。


  canvas.setAttribute("tabindex", "0");
  canvas.onclick = function () {
    canvas.focus();
  };
  const ellipsoid = scene.globe.ellipsoid;//获取描述地球形状的椭球体。
  scene.screenSpaceCameraController.enableRotate = false;//如果为 true,则允许用户旋转转换用户位置的世界
  scene.screenSpaceCameraController.enableTranslate = true;//如果为 true,则允许用户在地图上平移。如果为 false,则相机保持锁定在当前位置
  scene.screenSpaceCameraController.enableZoom = true;//如果为true,则允许用户放大和缩小。如果为 false,则相机将锁定到与椭球的当前距离。
  scene.screenSpaceCameraController.enableTilt = true;//如果为真,则允许用户倾斜相机。如果为 false,则摄像机锁定到当前航向
  scene.screenSpaceCameraController.enableLook = true;//如果为 true,则允许用户使用 free-look。如果为 false,则只能通过平移或旋转来改变摄像机视图方向

  let startMousePosition; // 保存鼠标初始位置
  let mousePosition; // 保存鼠标当前位置
  const flags = { // 一组标志,用于表示不同的操作状态
    looking: false, // 表示是否正在观察/旋转相机
    moveForward: false, // 向前移动
    moveBackward: false, // 向后移动
    moveUp: false, // 上移
    moveDown: false, // 下移
    moveLeft: false, // 左移
    moveRight: false // 右移
  };

  const handler = new Cesium.ScreenSpaceEventHandler(canvas); // 创建一个交互事件处理器

  handler.setInputAction(function (movement) { // 给事件处理器设置一个鼠标左键按下时的处理函数
    flags.looking = true; // 将标志位 flags.looking 设置为 true,表示正在观察/旋转相机
    mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position); // 保存鼠标初始位置
  }, Cesium.ScreenSpaceEventType.LEFT_DOWN); // 当鼠标左键按下时触发事件

  handler.setInputAction(function (movement) { // 当鼠标移动时,更新鼠标当前位置
    mousePosition = movement.endPosition;
  }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

  handler.setInputAction(function (position) { // 当鼠标左键释放时,表示停止观察/旋转相机
    flags.looking = false;
  }, Cesium.ScreenSpaceEventType.LEFT_UP);

  function getFlagForKeyCode(keyCode) { // 定义函数 getFlagForKeyCode,接收一个键盘按键的 keyCode 参数,返回相应的标志名称
    switch (keyCode) { // 使用 switch 语句对 keyCode 进行匹配
      case "W".charCodeAt(0): // 如果 keyCode 与字符 "W" 的 ASCII 码相等
        return "moveForward"; // 返回 "moveForward"
      case "S".charCodeAt(0): // 如果 keyCode 与字符 "S" 的 ASCII 码相等
        return "moveBackward"; // 返回 "moveBackward"
      case "Q".charCodeAt(0): // 如果 keyCode 与字符 "Q" 的 ASCII 码相等
        return "moveUp"; // 返回 "moveUp"
      case "E".charCodeAt(0): // 如果 keyCode 与字符 "E" 的 ASCII 码相等
        return "moveDown"; // 返回 "moveDown"
      case "D".charCodeAt(0): // 如果 keyCode 与字符 "D" 的 ASCII 码相等
        return "moveRight"; // 返回 "moveRight"
      case "A".charCodeAt(0): // 如果 keyCode 与字符 "A" 的 ASCII 码相等
        return "moveLeft"; // 返回 "moveLeft"
      default: // 如果未匹配上任何情况
        return undefined; // 返回 undefined
    }
  }
  document.addEventListener("keydown", function (e) { // 添加键盘按下事件监听器
    const flagName = getFlagForKeyCode(e.keyCode); // 根据按下的键的 keyCode 获取相应的标志名称
    if (typeof flagName !== "undefined") { // 如果获取的标志名称不是 undefined
      flags[flagName] = true; // 将对应的标志设置为 true,表示按键被按下
    }
  }, false);

  document.addEventListener("keyup", function (e) { // 添加键盘释放事件监听器
    const flagName = getFlagForKeyCode(e.keyCode); // 根据释放的键的 keyCode 获取相应的标志名称
    if (typeof flagName !== "undefined") { // 如果获取的标志名称不是 undefined
      flags[flagName] = false; // 将对应的标志设置为 false,表示按键被释放
    }
  }, false);

  viewer.clock.onTick.addEventListener(function (clock) { // 添加监听器,每次时钟更新时触发的事件处理函数
    const camera = viewer.camera; // 获取相机对象

    if (flags.looking) { // 如果正在观察/旋转相机
      const width = canvas.clientWidth; // 获取画布的宽度
      const height = canvas.clientHeight; // 获取画布的高度

      // 计算鼠标移动的偏移量,并根据偏移量调整相机的旋转角度
      const x = (mousePosition.x - startMousePosition.x) / width; // 计算鼠标在水平方向上的移动偏移量
      const y = -(mousePosition.y - startMousePosition.y) / height; // 计算鼠标在垂直方向上的移动偏移量

      const lookFactor = 0.05; // 设置旋转角度调整系数
      camera.lookRight(x * lookFactor); // 根据水平移动偏移量调整相机的水平旋转角度
      camera.lookUp(y * lookFactor); // 根据垂直移动偏移量调整相机的垂直旋转角度
    }

    const cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height; // 获取相机到椭球表面的距离
    const moveRate = cameraHeight / 100.0; // 根据相机到椭球表面的距离,计算移动速度

    // 根据不同的标志位,调用相机对象的对应方法完成相机的移动操作
    if (flags.moveForward) {
      camera.moveForward(moveRate);
    }
    if (flags.moveBackward) {
      camera.moveBackward(moveRate);
    }
    if (flags.moveUp) {
      camera.moveUp(moveRate);
    }
    if (flags.moveDown) {
      camera.moveDown(moveRate);
    }
    if (flags.moveLeft) {
      camera.moveLeft(moveRate);
    }
    if (flags.moveRight) {
      camera.moveRight(moveRate);
    }
  });
});



</script>

<style  scoped>
#cesiumContainer {
  width: 100%;
  height: 100%;
}

#cesiumContainer .cesium-viewer-bottom {
  display: none;
}

.floorSingle {
  position: absolute;
  z-index: 99;
  left: 0px;
  top: 30px;
  background-color: aliceblue;
}
</style>

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值