引言

本篇为Cesium开发的一些小技巧。

判断Cesium场景是否加载完毕这件事是非常有意义的。

  • 加载场景本身是个异步过程,然而我们经常会遇到一些业务场景是需要基于某一个模型加载完毕后再进行初始化操作,然后对模型进行操作。
  • 包含三维场景的页面和日常浏览的网页在加载效率上是不同的,人们往往对包含三维场景页面加载时长的容忍度会比较高。我们需要给出一个直观的加载过程用于安慰用户耐心等待较长的加载过程。
  • Cesium的模型加载策略是由粗到细分片加载,我们需要用户可以直接看到一个已经加载完毕的场景,而不是一点点细化的过程。

先看效果:
基础场景加载有点快,加载模型或者地图时,效果应该更明显些。
在这里插入图片描述


一、监听场景加载进度

这个功能要用到 CeiusmEventHelper 子类,监听 tileLoadProgressEvent 方法

1. 基础代码

  const helper = new Cesium.EventHelper();
  helper.add(viewer.scene.globe.tileLoadProgressEvent, (e) => {
	console.log(e);
  });

解释下代码,这里初始化了一个EventHelper实例,并监听tileLoadProgressEvent方法,他会监听每帧场景中切片加载队列的长度。回调函数入参 e 为int类型数字,代表当前场景中剩余未加载的切片数量。

2. 加工代码

  const helper = new Cesium.EventHelper();
  let maxTile = 0;
  let isLoaded = false;
  helper.add(viewer.scene.globe.tileLoadProgressEvent, (e) => {
    maxTile = Math.max(maxTile, e);
    const progress = Math.floor(((maxTile - e) / maxTile) * 100);
    isLoaded = viewer.scene.globe.tilesLoaded;
    console.log("progress", progress);
    console.log("tilesLoaded", isLoaded);

解释下代码,这里在基础代码上做了一点点加工,在外部设置个最大切片数量的变量,使用Math.max赋予最大的切片数量值,通过最大值和当前值的计算可得一个百分比进度值。此外 viewer.scene.globe.tilesLoaded 是一个Boolean值,更直观的表达了切片是否加载完成。此时我们得到了加载进度和加载完成的标志。


二、进一步封装代码

1. 已知存在的弊端

我们已经知道了如何监听场景切片的加载进度,但是它会在每一次拖动地球转动时同样监听到这个微调的过程。我们希望只有在页面初始化时、加载模型时调用一次监听事件提供进度提示,其他时候不监听。

2. 封装hooks函数

想象一下函数的使用场景,我们需要监听场景中切片的进度和完成标志,我们还需要它只监听一次就清理监听事件,额外提供销毁方法不要继续占用资源,最后需要它能够实时输出进度值和加载完成标志。

利用vue3的响应式变量方法ref,将progress 、isLoaded 包装为响应式变量。

import { ref } from "vue";

export const useTileloadProgress = () => {
  const helper = new Cesium.EventHelper();

  let isLoaded = ref(false);
  let progress = ref(0);

  /**
   * @description: 触发监听事件
   * @return {*}
   */
  const _onLoad = () => {
    let maxTile = 0;
    helper.add(viewer.scene.globe.tileLoadProgressEvent, (e) => {
      maxTile = Math.max(maxTile, e);
      progress.value = Math.floor(((maxTile - e) / maxTile) * 100);
      isLoaded.value = viewer.scene.globe.tilesLoaded;
      //   当一次加载完成后移除监听事件
      if (isLoaded.value) {
        _onRemove();
      }
    });
  };

  /**
   * @description: 移除监听事件
   * @return {*}
   */
  const _onRemove = () => {
    helper.removeAll();
  };

  /**
   * @description: 移除监听事件,清理EventHelper实例,初始化变量值。
   * @return {*}
   */
  const _onDestroy = () => {
    remove();
    helper = null;
    isLoaded.value = false;
    progress.value = 0;
  };

  return {
    progress,
    isLoaded,
    _onLoad,
    _onRemove,
    _onDestroy,
  };
};


三、使用hooks方法

1. 如何使用该hooks方法

初始化场景请参考:【WebGis开发 - Cesium】三维可视化项目教程—初始化场景

在获取了progress和isLoaded两个变量后,可以进一步使用项目UI框架做提示,或者美化一个进度加载的界面。自由发挥

<script setup>
import { onMounted } from "vue";
import { initCesiumMap } from "@/utils/cesium/index.js";
import { useTileloadProgress } from "@/hooks/useTileloadProgress.js";
const { progress, isLoaded, _onLoad, _onRemove, _onDestroy } =
  useTileloadProgress();
onMounted(() => {
// 初始化地球场景
  initCesiumMap();
// 监听加载进度
  _onLoad();
});
</script>

三、总结

本篇主要介绍了如何利用 EventHelpertileLoadProgressEvent 来判断一个Cesium场景是否加载完成。解决了Cesium场景无法感知加载进度的问题,给业务场景开发提供了明确完成标志。

利用vue3.0的新特性,将以上方法封装为hooks函数,更方便业务测使用。

再接再厉~

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐