Cesium关于Entity中的parent、isShowing、entityCollection和监听事件的探讨

15 篇文章 0 订阅
12 篇文章 18 订阅

Entity在项目中使用的比较多,但是有几个属性值一直没有使用到,抱着好奇的心态去看了下源码。这些属性实际发挥着什么样的作用。

definitionChanged

我接触过的项目中,很少有使用到这个事件监听器。它的用法比较简单,直接entity.definitionChanged.addEventListener(方法,上下文);在官方文档的Event有案例。

监听事件接收四个参数,第一个参数为当前的entity,第二个参数为更改属性的名称,比如position更改了就会是字符串形式的'position',第三个值为更改之后的新值newValue,第四个值为更改之前的旧值oldValue。

源码中直接赋予监听事件的属性值有show,parent,isShowing这三个。

// 203行   到   220行
function updateShow(entity, children, isShowing) {
  const length = children.length;
  for (let i = 0; i < length; i++) {
    const child = children[i];
    const childShow = child._show;
    const oldValue = !isShowing && childShow;
    const newValue = isShowing && childShow;
    if (oldValue !== newValue) {
      updateShow(child, child._children, isShowing);
    }
  }
  entity._definitionChanged.raiseEvent(
    entity,
    "isShowing",
    isShowing,
    !isShowing
  );
}

// 268行   到   293行
  show: {
    get: function () {
      return this._show;
    },
    set: function (value) {
      //>>includeStart('debug', pragmas.debug);
      if (!defined(value)) {
        throw new DeveloperError("value is required.");
      }
      //>>includeEnd('debug');

      if (value === this._show) {
        return;
      }

      const wasShowing = this.isShowing;
      this._show = value;
      const isShowing = this.isShowing;

      if (wasShowing !== isShowing) {
        updateShow(this, this._children, isShowing);
      }

      this._definitionChanged.raiseEvent(this, "show", value, !value);
    },
  }
// 314行   到   344行
  parent: {
    get: function () {
      return this._parent;
    },
    set: function (value) {
      const oldValue = this._parent;

      if (oldValue === value) {
        return;
      }

      const wasShowing = this.isShowing;
      if (defined(oldValue)) {
        const index = oldValue._children.indexOf(this);
        oldValue._children.splice(index, 1);
      }

      this._parent = value;
      if (defined(value)) {
        value._children.push(this);
      }

      const isShowing = this.isShowing;

      if (wasShowing !== isShowing) {
        updateShow(this, this._children, isShowing);
      }

      this._definitionChanged.raiseEvent(this, "parent", value, oldValue);
    },
  }

其他属性的更改也是可以被监听到的,只不过并没有在Entity.js文件中直接触发监听。而是通过了两种方法。createPropertyTypeDescriptor和createPropertyDescriptor。

虽然是两个,最后执行的都是createPropertyDescriptor方法,另一个只是做了检查而已。最终实现监听的是在createPropertyDescriptor.js 中的createProperty方法里。

function createProperty(
  name,
  privateName,
  subscriptionName,
  configurable,
  createPropertyCallback
) {
  return {
    configurable: configurable,
    get: function () {
      return this[privateName];
    },
    set: function (value) {
      const oldValue = this[privateName];
      const subscription = this[subscriptionName];
      if (defined(subscription)) {
        subscription();
        this[subscriptionName] = undefined;
      }

      const hasValue = value !== undefined;
      if (
        hasValue &&
        (!defined(value) || !defined(value.getValue)) &&
        defined(createPropertyCallback)
      ) {
        value = createPropertyCallback(value);
      }

      if (oldValue !== value) {
        this[privateName] = value;
        this._definitionChanged.raiseEvent(this, name, value, oldValue);
      }

      if (defined(value) && defined(value.definitionChanged)) {
        this[subscriptionName] = value.definitionChanged.addEventListener(
          function () {
            this._definitionChanged.raiseEvent(this, name, value, value);
          },
          this
        );
      }
    },
  };
}

对entity设置监听,我个人的理解可以应用的场景在于一些无法预期下一个值的追踪上。

比如,地图上有一个entity对象,这个对象并不会根据时间的推移而改变位置。而是通过接口或者某个定时行为来设置它的position。这时候就可以设置监听事件来针对position改变来实现代码功能。这种设置只针对于,无法知晓在哪里更新了position值,或者说使用的是其他人封装好的方法,没法在源码基础上添加代码;以及需要延时处理。因为,能直接设置entity的position值的地方,应该可以多放点代码进去。

parent和isShowing

 按官方文档的意思,parent的值是一个entity,代表着它的父级entity。有父级就代表着有子级,可以通过entity._children来知道,有多少个entity儿子。

重新设置parent的时候,如果设置的值与原有的值不相同。则会先把原先的_children中移除当前的entity,然后再加入到新设置的值的_children。这样就不会造成一个entity同时存在于另外两个entity的_children中,当然,人为添加的行为除外。

_parent和_children最终会影响到的,就是当前entity的show属性是否有效。官方文档的解释中,如果你为entity的show设置为了true,那么当它的parent的显示也为true的时候才会显示。说人话就是如果你有parent,你的show并不由你决定了,你要看父级的脸色。

// 300行  到  308行  
isShowing: {
    get: function () {
      return (
        this._show &&
        (!defined(this.entityCollection) || this.entityCollection.show) &&
        (!defined(this._parent) || this._parent.isShowing)
      );
    },
  }

show的值决定是否显示,并不代表着一定会显示。如果需要知道一个entity是否在屏幕内显示,比较简单的判断方法就是进行两次判断。

entity.entityCollection && entity.isShowing

 如果那种自定义的entityCollection或者CustomDataSource,判断就复杂一点。需要用对应的contains方法看是否被添加到viewer的entities或者dataSources里面。

当使用new Cesium.Entity()方式创建一个entity的时候,它并没有添加到哪个entityCollection里面去显示,所以单纯的isShowing判断的并不准确。

子级受父级的限制,那么父级的变化就会影响到子级。体现在了updateShow方法上,它会去遍历所有子级。

function updateShow(entity, children, isShowing) {
  const length = children.length;
  for (let i = 0; i < length; i++) {
    const child = children[i];
    const childShow = child._show;
    const oldValue = !isShowing && childShow;
    const newValue = isShowing && childShow;
    if (oldValue !== newValue) {
      updateShow(child, child._children, isShowing);
    }
  }
  entity._definitionChanged.raiseEvent(
    entity,
    "isShowing",
    isShowing,
    !isShowing
  );
}

常见的用法就是多个entity有关联性,同时显示同时消失,将这些entity的parent都设置为同一个entity。这样控制显示的时候就不用去遍历所有的。也要看量,如果数量比较多,为什么不用entityCollection呢?

实际项目上能用到的场景,比如,一个柱子cylinder和一个标签label。你想让label显示在柱子顶端,但是cylinder根据position定位,label也一样。柱子需要拔地而起,标签需要落在柱子上,那就只能创建两个entity,拥有相同的position定位,只不过label定位的高度是柱子的高度,柱子贴地就是了。

entityCollection

前面两个属性的探讨就是它全部的作用了。官方文档的解释说,通过这个值可以知道当前的entity属于哪个collection集合里面。言简意骇。

在使用viewer.entities.add()方法将entity添加进去的时候,在add方法内部就将entity的entityCollection就指向了viewer.entities了。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值