前言
这两天在研究Cesium中如何实现沿线飞行或漫游功能,上网查资料发现有好多博主的解决办法都包含了什么什么Property……勾起了我强烈的好奇心,遂去了Cesium官网一探究竟,一下我就被第一句话震惊到了。
All values we define for our entities are stored as Property
objects.
实体的所有值都被维护成了Property
对象,这让我不得不往下看,但我越看越气,这么重要的东西,你这啥也没讲啊。算了还是我自己研究吧。
什么是Property机制
个人感觉Cesium的Property本质上与Object.defineProperties
类似,defineProperties
直接封装了基本类型,如果是Object,则是引用形式。通过Property的封装,将引用或复制的权力交给了设计者,同时提供一些特殊的功能以满足需求。
为什么要用Property
首先用一个例子来简单展示一下Property的作用。
1 2 3 4 5 6 7 8
| var box = viewer.entities.add({ name: "box", position: Cesium.Cartesian3.fromDegrees(121.54035, 38.92146, 2000), box: { dimensions: new Cesium.Cartesian3(1000.0, 1000.0, 1000.0), }, });
|
假如我们想实现盒子的大小随时间变化而变化,第一想到的应该就是用setInterval
去改变盒子的dimensions
,但这样对性能是个不小的挑战。而Cesium提供一种机制,可以让其随时间自动变化并赋值,这就是Property。以下代码是在5秒内让盒子大小变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var property = new Cesium.SampledProperty(Cesium.Cartesian3);
property.addSample( Cesium.JulianDate.fromDate(new Date()), new Cesium.Cartesian3(1000.0, 1000.0, 1000.0) );
property.addSample( Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ), new Cesium.Cartesian3(2000.0, 2000.0, 2000.0) );
box.box.dimensions = property;
|
我们通过addSample
向Property实例添加关键帧并定义想要修改的属性,最后赋值给box的dimensions
,效果如下
所以说,Property可以和时间轴进行关联,并根据时间返回对应的属性值,而Entity则可以通过返回的值动态改变实体的位置、大小等。
Property分类及使用方法
上文中我们举例使用的SampledProperty
提供了插值功能,还有很多Property的类型,我们可以在API文档中搜索一下Property,整整有29个之多。
简单归类一下可以分为几类:
- 基本类型:
ConstantProperty
,SampledProperty
,TimeIntervalCollectionProperty
,CompositeProperty
- 其他类型:
CallbackProperty
,ReferenceProperty
,PropertyArray
,PropertyBag
,VelocityOrientationProperty
,VelocityVectorProperty
- 材质类型:
MaterialProperty
及带material字样的
- 位置类型:带Position字样的
同时Cesium提供了一个Property
类作为所有类型的基类,并定义了几个公共属性及接口。
getValue(time, result) → Cartesian3
获取特定时间点下的属性值
equal
用来判断属性值是否相等。
接下来我们就一些常用的Property做一下讲解和代码实现。
基本类型
SampledProperty
第一个例子中我们使用的就是它,通过添加不同时间点的Sample,在每两个时间点之间进行线性插值,这里不做演示,代码和效果都在第一个例子中了。
TimeIntervalCollectionProperty
用来指定具体时间段内的属性值,每个时间段内属性值不变。所以和SampledProperty
不同,它呈现出的变化为跳跃式。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| var property = new Cesium.TimeIntervalCollectionProperty( Cesium.Cartesian3 );
property.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 2, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded:true, isStopIncluded:false, data: new Cesium.Cartesian3(1000.0, 1000.0, 1000.0), }) ); property.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 6, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded:true, isStopIncluded:false, data: new Cesium.Cartesian3(2000.0, 2000.0, 2000.0), }) ); property.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 10, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded:true, isStopIncluded:true, data: new Cesium.Cartesian3(3000.0, 3000.0, 3000.0), }) );
box.box.dimensions = property;
|
ConstantProperty
不随时间的变化而变化的属性。
相对于上述两种Property,更加常用的可能就是这个ConstantProperty
了,在我们平常设置实体的属性时一般都是如下设置:
1
| box.box.dimensions = new Cesium.Cartesian3(100, 100, 100);
|
但是实际上其实完整的写法应该是:
1
| box.box.dimensions = new ConstantProperty(new Cesium.Cartesian3(100, 100, 100));
|
这么看我们可以发现,box中的dismensions
属性其实是Property
类型,在Cesium内部偷偷的将我们传入的Cartesian3转化成了ConstantProperty
类型。
ConstantProperty
也并非不能更改,它提供了setValue
方法去修改属性值,利用setValue
会修改原有的属性值,而非创建新的ConstantProperty
。
CompositeProperty
顾名思义这是个复合属性,它可以将多种Property进行组合操作,例如在一段时间内需要跳跃性变化,然后进行平滑变化,则可以使用这种类型。看代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| var lineProperty = new Cesium.SampledProperty(Cesium.Cartesian3);
lineProperty.addSample( Cesium.JulianDate.fromDate(new Date()), new Cesium.Cartesian3(1000.0, 1000.0, 1000.0) );
lineProperty.addSample( Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ), new Cesium.Cartesian3(3000.0, 3000.0, 3000.0) );
var timeProperty = new Cesium.TimeIntervalCollectionProperty( Cesium.Cartesian3 );
timeProperty.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded: true, isStopIncluded: false, data: new Cesium.Cartesian3(3000.0, 3000.0, 3000.0), }) ); timeProperty.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 10, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded: true, isStopIncluded: false, data: new Cesium.Cartesian3(4000.0, 4000.0, 4000.0), }) ); timeProperty.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 15, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded: true, isStopIncluded: true, data: new Cesium.Cartesian3(5000.0, 5000.0, 5000.0), }) );
var compositeProperty = new Cesium.CompositeProperty(); compositeProperty.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.fromDate(new Date()), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ), isStartIncluded: false, isStopIncluded: false, data: lineProperty, }) ); compositeProperty.intervals.addInterval( new Cesium.TimeInterval({ start: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ), stop: Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 20, new Cesium.JulianDate() ), isStartIncluded: false, isStopIncluded: false, data: timeProperty, }) );
box.box.dimensions = compositeProperty;
|
位置类型
PositionProperty
同Property,PositionProperty是一个虚基类,不能直接实例化,它增加了referenceFrame
,只能表示position
。
referenceFrame
用来获取position的参考系,目前Cesium提供两种参考系FIXED
和INERTIAL
。默认使用的FIXED
参考系,即坐标在地球上的位置是固定的。
基于PositionProperty的类型有以下几种:
- CompositePositionProperty
- ConstantPositionProperty
- PositionProperty
- PositionPropertyArray
- SampledPositionProperty
- TimeIntervalCollectionPositionProperty
用法上和基本类型基本相同,只不过它们专门用来表示位置信息。这里不做举例。
材质类型
MaterialProperty
专门用来表示材质,扩展了getType
方法来获取材质类型。
同样它也有很多派生类,比如ColorMaterialProperty
,ImageMaterialProperty
等等,我们在平时的demo和项目中也都有使用。
我们可以利用基本类型和材质类型实现一个颜色的动态效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var colorProperty = new Cesium.SampledProperty(Cesium.Color);
colorProperty.addSample( Cesium.JulianDate.fromDate(new Date()), new Cesium.Color(0, 1, 0) );
colorProperty.addSample( Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ), new Cesium.Color(0, 0, 1) );
box.box.material = new Cesium.ColorMaterialProperty(colorProperty);
|
其他类型
CallbackProperty
这里主要介绍一下CallbackProperty
,它是自由度最高的一种类型,我们只需要提供一个回调函数来返回我们需要的值即可,在回调函数中我们可以随意进行操作。在这我们实现一个随机变化颜色并且不断增高的box。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| let l = 2000.0; box.box.dimensions = new Cesium.CallbackProperty(function (time, result) { result = result || new Cesium.Cartesian3(0, 0, 0);
l += 20.0; if (l > 7000.0) { l = 2000.0; }
result.x = 4000.0; result.y = 3000.0; result.z = l; return result; }, false); box.box.material = new Cesium.ColorMaterialProperty( new Cesium.CallbackProperty(function () { return Cesium.Color.fromRandom({ alpha: 1.0, }); }, false) );
|
ReferenceProperty
该property可以直接链接到另一个对象的Property,做引用效果。
参数 |
类型 |
描述 |
targetCollection |
EntityCollection |
将用于解析引用的实体集合。 |
targetId |
String |
被引用的实体的 id。 |
targetPropertyNames |
Array. |
将使用的目标实体上的属性名称。 |
PropertyBag
它用来对一个对象进行包装,使得该对象的每一个属性都可作为一个动态的Property进行修改。比如之前修改dimensions的话,dimensions是作为一个Cartesian3类型变量整体封装到Property中去的,如果我们只想修改dimensions的x。则可以使用PropertyBag来实现。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var zp = new Cesium.SampledProperty(Number); zp.addSample(Cesium.JulianDate.fromDate(new Date()), 2000.0); zp.addSample(Cesium.JulianDate.addSeconds( Cesium.JulianDate.fromDate(new Date()), 5, new Cesium.JulianDate() ),, 7000.0);
box.box.dimensions = new Cesium.PropertyBag({ x: 4000.0, y: 3000.0, z: zp });
|
VelocityOrientationProperty
该Property用来Entity的position的位置变化,来计算出移动的方向,最后把速度方向输出成Orientation。Cesium自带的示例中有一个Interpolation中有其用法,不再赘述。
使用场景
Property机制很强大,我们可以在很多场景中使用它,比如实现一些沿线飞行、路径漫游或者实体的大小属性变化等。可以说只要有修改属性的地方我们都可以用到它。