Cesium開發(fā)工具篇 | 02事件應用

無論是前端系統(tǒng),還是二維/三維GIS應用系統(tǒng),都離不開各種事件的應用,尤其是鼠標的單擊、雙擊事件。 Cesium 根據(jù)事件的類型、用途,將事件應用分成了三大類。一種是以鼠標操作(左鍵、中鍵、右鍵操作等)為主的 ScreenSpaceEventHandler 類,另一種是通用的事件類 Event ,該類通常在容器類內部實例化,并作為某個屬性的類型直接被調用,比如 viewer.clock.onTick、viewer.selectedEntityChanged、camera.moveStart、camera.moveEnd、scene.preRender、cesium3DTileset.allTilesLoaded等這些屬性都是 Event 類型;最后一種則是相機控制方面的事件類 screenSpaceCameraController,該類通過與CameraEventType類配合實現(xiàn)相機的控制。下面我主要介紹幾個比較常用的事件應用。

鼠標事件

鼠標事件可以說是GIS系統(tǒng)里面關于事件應用最常用的一個了,點擊地圖上的某一個 graphic,并獲取其屬性信息,就是鼠標事件應用最熟悉的一個場景了。Cesium為實現(xiàn)這一功能,分成了兩個過程。首先,傳遞viewer.canvas參數(shù)實例化ScreenSpaceEventHandler類,比如實例化后的名稱為handler;其次,為 handler 注冊鼠標事件的監(jiān)聽;最后,在監(jiān)聽事件的回調方法中獲取 event.position ,并將其作為參數(shù)執(zhí)行scene.pick 方法獲取對應的選中對象。

1)ScreenSpaceEventHandler
對 ScreenSpaceEventHandler 類進行實例化,注冊事件、注銷事件代碼如下:

   var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
    let eventType = Cesium.ScreenSpaceEventType.LEFT_CLICK;
    //注冊事件
    handler.setInputAction((event) => {
      console.log(event);
    }, eventType);

    //注銷事件
    handler.removeInputAction(eventType);

上面代碼中的事件類型 eventType 直接采用了 ScreenSpaceEventType 中的常量,示例中注冊鼠標左擊事件。根據(jù)實際場景需求,eventType 的值可按需賦值,包括以下幾種:

2)要素拾取
假如應用場景是點擊要素獲取其屬性信息,這個時候就需要在鼠標左鍵的注冊事件中獲取 event 結果,核心代碼如下:

var picked = viewer.scene.pick(event.position);

這個時候就可以根據(jù)獲取到的對象類型進行操作了。

     if (Cesium.defined(picked)) {
        if (picked.id && picked.id instanceof Cesium.Entity) {
          console.log("選中了Entity");
        }
        if (picked.primitive instanceof Cesium.Primitive) {
          console.log("選中了Primitive");
        }
        if (picked.primitive instanceof Cesium.Model) {
          console.log("選中了模型");
        }
        if (picked instanceof Cesium.Cesium3DTileFeature) {
          console.log("選中了3DTile");
        }
      }

3)Entity選擇
Cesium 針對于通過 Entity 方式添加的幾何圖形,提供了一個非常方便的屬性selectedEntityChanged(viewer類事件類型的屬性)來幫助我們獲取選中的Entity,通過這個屬性,用戶無需再寫注冊鼠標事件了。示例代碼如下:

    viewer.selectedEntityChanged.addEventListener(function (entity) {
      console.log(entity.id);
    });

在某些場景中,我們可能需要跟蹤某一輛車或某一個人員,這是我們可以把車輛或人員Entity賦給viewer.trackedEntity,相機就會自動跟蹤你綁定的Entity了。實際場景中,我們并不是始終跟蹤某一個車輛,有時需要切換到另一個車輛,當你切換正在跟蹤的車輛時,其實我們觸發(fā)了viewer.trackedEntityChanged事件,這樣我們就可以在此事件中實時獲取車輛行駛狀態(tài)了。

    viewer.trackedEntityChanged.addEventListener(function (entity) {
      console.log(entity.id);
    });

相機事件

相機控制事件類 screenSpaceCameraController 并不是像鼠標事件相關類 ScreenSpaceEventHandler 那樣需要提前實例化。Cesium在Viewer類的實例化過程中,也實例化了其他很多類,其中就包括ScreenSpaceCameraController類,并把實例化結果賦值給了viewer.scene.screenSpaceCameraController。所以,我們直接去操作viewer.scene.screenSpaceCameraController就可以了。

1)通過鼠標控制
通過鼠標控制相機的方式取決于CameraEventType的常量,包括以下幾種:

其中,鼠標的默認操作如下:

下面我們修改默認的鼠標操作,實現(xiàn)中鍵縮放、右鍵旋轉。核心代碼如下:

    viewer.scene.screenSpaceCameraController.tiltEventTypes = [
      Cesium.CameraEventType.RIGHT_DRAG,
      Cesium.CameraEventType.PINCH,
      {
        eventType: Cesium.CameraEventType.LEFT_DRAG,
        modifier: Cesium.KeyboardEventModifier.CTRL,
      },
      {
        eventType: Cesium.CameraEventType.RIGHT_DRAG,
        modifier: Cesium.KeyboardEventModifier.CTRL,
      },
    ];

    viewer.scene.screenSpaceCameraController.zoomEventTypes = [
      Cesium.CameraEventType.MIDDLE_DRAG,
      Cesium.CameraEventType.WHEEL,
      Cesium.CameraEventType.PINCH,
    ];

2)通過鍵盤控制
主要是通過操作鍵盤實現(xiàn)相機的漫游,比如前進、后退、向上、向下等等,是不是感覺自己在玩穿越火線游戲,響起熟悉的聲音:headshot、double kill、multi kill、fire in the hole、......,打住?。。】顸c鼠標也不會發(fā)射子彈的。好了,我們把感覺拉回來現(xiàn)場,繼續(xù)學習Cesium。實現(xiàn)鍵盤漫游主要是通過鍵盤調用相機的moveForward、moveBackward、moveLeft、moveRight、moveUp、moveDown方法。下面為部分核心代碼,查看完整代碼請瀏覽GitHub地址https://github.com/ls870061011/cesium_training/tree/main/examples中的3_2部分。

    viewer.clock.onTick.addEventListener(function (clock) {
      var camera = viewer.camera;

      if (flags.looking) {
        var width = canvas.clientWidth;
        var height = canvas.clientHeight;

        // Coordinate (0.0, 0.0) will be where the mouse was clicked.
        var x = (mousePosition.x - startMousePosition.x) / width;
        var y = -(mousePosition.y - startMousePosition.y) / height;

        var lookFactor = 0.05;
        camera.lookRight(x * lookFactor);
        camera.lookUp(y * lookFactor);
      }

      // Change movement speed based on the distance of the camera to the surface of the ellipsoid.
      var cameraHeight = ellipsoid.cartesianToCartographic(camera.position)
        .height;
      var 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);
      }
    });

場景渲染事件

場景渲染事件主要包括以下四種:

  • scene.preUpdate: 更新或呈現(xiàn)場景之前將引發(fā)的事件
  • scene.postUpdate: 場景更新后以及渲染場景之前立即引發(fā)的事件
  • scene.preRender: 場景更新后以及渲染場景之前將引發(fā)的事件
  • scene.postRender: 渲染場景后立即引發(fā)的事件
    事件的添加和移除代碼示例如下:
  viewer.scene.preUpdate.addEventListender(callbackFunc);
  viewer.scene.preUpdate.removeEventListender(callbackFunc);

比如我們自己寫了一個指北針、標簽,都可以在scene.preRender監(jiān)聽事件的回調函數(shù)中更新指北針狀態(tài)或者是標簽的位置信息。下面的部分核心代碼,為場景重新選然后更新自定義標簽位置。

   viewer.scene.scene-preRender.addEventListener(() => {
      if (positions instanceof Array && htmlSize instanceof Array) {
        positions.map((ele, index) => {
          const html = document.getElementById(`infoTip${index}`);
          if (html) {
            const canvasPosition = ConversionUtil.degreesToCartesian2(ele.x, ele.y, ele.z);
            if (canvasPosition) {
              html.style.top = `${canvasPosition.y - htmlSize[index].offsetHeight}px`;
              html.style.left = `${canvasPosition.x - htmlSize[index].offsetWidth}px`;
            }
          }
        });
      }
   )
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容