文章目录
Creating Entities (创建实体)
了解如何使用CesiumJS中的Entity API绘制空间数据,例如点,标记,标签,线,模型,形状和体积。 如果您不熟悉CesiumJS,则可能要开始使用 Getting Started 教程。
What is the Entity API? (什么是 Entity API)
CesiumJS具有丰富的空间数据API,可以将其分为两类:面向图形开发人员的低级Primitive API和用于数据驱动的可视化的高级Entity API。
低级原始API暴露了执行手头任务所需的最少抽象量。 它的结构旨在为图形开发人员提供灵活的实现,而不是为了实现API一致性。 加载模型与创建广告牌不同,并且两者都与创建多边形完全不同。 每种可视化类型都有其自己独特的功能。 此外,每个都有不同的性能特征,并且需要不同的最佳实践。 尽管此方法功能强大且灵活,但可以为更高级别的抽象更好地服务于大多数应用程序。
Entity API公开了一组一致设计的高级对象,这些对象将相关的可视化和信息聚合到一个统一的数据结构中,我们称之为 Entity。它使我们能够专注于数据的表示,而不必担心可视化的潜在机制。 它还提供了一些结构,可轻松构建复杂的,时间动态的可视化文件,并使其自然地适合静态数据。 虽然Entity API实际上是在后台使用Primitive API,但这是我们几乎不必担心的实现细节。 通过将各种启发式方法应用于我们提供的数据,Entity API能够提供灵活,高性能的可视化效果,同时公开一致,易学且易于使用的界面。
Our first entity (我们的第一个entity)
首先,在Sandcastle中打开 Hello World 示例。
从经度和纬度列表中为美国怀俄明州添加一个多边形。
var viewer = new Cesium.Viewer('cesiumContainer');
var wyoming = viewer.entities.add({
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray([
-109.080842,45.002073,
-105.91517,45.002073,
-104.058488,44.996596,
-104.053011,43.002989,
-104.053011,41.003906,
-105.728954,40.998429,
-107.919731,41.003906,
-109.04798,40.998429,
-111.047063,40.998429,
-111.047063,42.000709,
-111.047063,44.476286,
-111.05254,45.002073]),
height : 0,
material : Cesium.Color.RED.withAlpha(0.5),
outline : true,
outlineColor : Cesium.Color.BLACK
}
});
viewer.zoomTo(wyoming);
点击工具栏中的 Run 按钮(或键盘上的F8)将产生以下结果:
上面的代码创建了 Viewer ,后者创建了Globe和其他小部件。 我们通过 viewer.entities.add 创建了一个新的实体。 我们传递来添加的对象为实体提供了初始值。 返回值是实际的Entity实例。 最后,viewer.zoomTo 缩放摄影机以查看实体。
有很多实体选项。 我们为 polygon (多边形) 填充了半透明的红色和指定了黑色的轮廓。
Shapes and volumes (形状和体积)
以下是我们可以使用Entity API创建的受支持的形状和体积的完整列表:
type | prammar | example | documentation |
---|---|---|---|
Boxes | entity.box | Code example | Reference documentation |
Circles and ellipses | entity.ellipse | Code example | Reference documentation |
Corridor | entity.corridor | Code example | Reference documentation |
Cylinder and cones | entity.cylinder | Code example | Reference documentation |
Polygons | entity.polygon | Code example | Reference documentation |
Polylines | entity.polyline | Code example | Reference documentation |
Polyline volumes | entity.polylineVolume | Code example | Reference documentation |
Rectangles | entity.rectangle | Code example | Reference documentation |
Spheres and ellipsoids | entity.ellipsoid | Code example | Reference documentation |
Walls | entity.wall | Code example | Reference documentation |
Materials and outlines (材料和轮廓)
所有形状和体积都有一组共同的属性来控制其外观。 fill 属性指定是否填充几何图形,而 outline 属性指定是否绘制几何图形。
当fill为true时,material 属性确定该填充的外观。 下面将创建一个半透明的蓝色椭圆。
var entity = viewer.entities.add({
position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
ellipse : {
semiMinorAxis : 250000.0,
semiMajorAxis : 400000.0,
material : Cesium.Color.BLUE.withAlpha(0.5)
}
});
viewer.zoomTo(viewer.entities);
var ellipse = entity.ellipse; // For upcoming examples
Image
我们还可以指定图像的URL而不是颜色。
ellipse.material = '/docs/tutorials/creating-entities/images/cats.jpg';
在以上两种情况下,都会在分配时自动为我们创建 ColorMaterialProperty 或 ImageMaterialProperty 。 对于更复杂的材料,我们需要自己创建一个 MaterialProperty 实例。 当前,实体形状和体积支持颜色,图像,棋盘格(Checkerboard),条纹(Stripe)和网格材料(Grid)。
Checkerboard
ellipse.material = new Cesium.CheckerboardMaterialProperty({
evenColor : Cesium.Color.WHITE,
oddColor : Cesium.Color.BLACK,
repeat : new Cesium.Cartesian2(4, 4)
});
Stripe
ellipse.material = new Cesium.StripeMaterialProperty({
evenColor : Cesium.Color.WHITE,
oddColor : Cesium.Color.BLACK,
repeat : 32
});
Grid
ellipse.material = new Cesium.GridMaterialProperty({
color : Cesium.Color.YELLOW,
cellAlpha : 0.2,
lineCount : new Cesium.Cartesian2(8, 8),
lineThickness : new Cesium.Cartesian2(2.0, 2.0)
});
Outlines
outline依赖于outlineColor和outlineWidth属性。 outlineWidth仅适用于非Windows系统,例如Android,iOS,Linux和OSX。在Windows系统上,轮廓的宽度始终为1。这是由于在Windows上实现WebGL的方式受到限制。
ellipse.fill = false;
ellipse.outline = true;
ellipse.outlineColor = Cesium.Color.YELLOW;
ellipse.outlineWidth = 2.0;
Polylines
折线是一种特殊情况,因为它们没有填充或轮廓属性。 他们依靠专业材料来制作颜色以外的任何东西。 由于这些特殊的材料,宽度和轮廓宽度不同的折线将适用于所有系统。
var entity = viewer.entities.add({
polyline : {
positions : Cesium.Cartesian3.fromDegreesArray([-77, 35,
-77.1, 35]),
width : 5,
material : Cesium.Color.RED
}});
viewer.zoomTo(viewer.entities);
var polyline = entity.polyline // For upcoming examples
Polyline outline
polyline.material = new Cesium.PolylineOutlineMaterialProperty({
color : Cesium.Color.ORANGE,
outlineWidth : 3,
outlineColor : Cesium.Color.BLACK
});
Heights and extrusions
可以将包括走廊,椭圆形,多边形和矩形在内的曲面形状放置在高空或挤压成一个体积。 在这两种情况下,形状或体积仍将符合WGS84椭球的曲率。
在相应的图形对象上设置height属性(以米为单位)。 下面的代码行将多边形升高到地球上方25万米。
wyoming.polygon.height = 250000;
要将形状挤出为体积,请设置 extrudedHeight 属性。 该体积将在 height 和 extrudedHeight 之间创建。 如果高度未定义,则体积从0开始。创建一个体积从200,000米开始并扩展到250,000米的体积。
wyoming.polygon.height = 200000;
wyoming.polygon.extrudedHeight = 250000;
Entity features in the Viewer (查看器中的实体功能)
让我们看一下Viewer提供的与实体配合使用的即用型功能。
Selection and description (选择和描述)
在查看器中单击一个实体将在该实体的位置显示 SelectionIndicator 小部件,并调出 InfoBox 以提供更多信息。 我们可以设置一个 name,该名称确定InfoBox的标题。 我们还可以提供HTML作为Entity.description属性。
wyoming.name = 'wyoming';
wyoming.description = '\
<img\
width="50%"\
style="float:left; margin: 0 1em 1em 0;"\
src="//cesium.com/docs/tutorials/creating-entities/Flag_of_Wyoming.svg"/>\
<p>\
Wyoming is a state in the mountain region of the Western \
United States.\
</p>\
<p>\
Wyoming is the 10th most extensive, but the least populous \
and the second least densely populated of the 50 United \
States. The western two thirds of the state is covered mostly \
with the mountain ranges and rangelands in the foothills of \
the eastern Rocky Mountains, while the eastern third of the \
state is high elevation prairie known as the High Plains. \
Cheyenne is the capital and the most populous city in Wyoming, \
with a population estimate of 63,624 in 2017.\
</p>\
<p>\
Source: \
<a style="color: WHITE"\
target="_blank"\
href="http://en.wikipedia.org/wiki/Wyoming">Wikpedia</a>\
</p>';
信息框中显示的所有HTML均已沙箱化。 这样可以防止外部数据源将恶意代码注入Cesium应用程序。 要在描述中运行JavaScript或浏览器插件,请通过viewer.infoBox.frame属性访问用于沙箱处理的iframe。 有关控制iframe沙箱的更多信息,请参见本文。
Camera controls (相机控制)
使用viewer.zoomTo命令查看特定实体。 还有一个 viewer.flyTo 方法,该方法执行动画照相机飞行到实体。 这两种方法都可以传递给Entity,EntityCollection,DataSource 或实体数组。
两种方法都会计算所有提供的实体的视图。 默认情况下,相机朝北,并从45度角向下看。 通过传入HeadingPitchRange对其进行自定义。
var heading = Cesium.Math.toRadians(90);
var pitch = Cesium.Math.toRadians(-30);
viewer.zoomTo(wyoming, new Cesium.HeadingPitchRange(heading, pitch));
zoomTo和flyTo都是异步函数。 也就是说,不能保证他们在返回之前已经完成。 例如,飞越实体会发生在许多动画帧上。 这两个函数都返回 Promises,可用于计划在飞行或缩放完成后要执行的功能。 用下面的代码片段替换示例中的zoomTo。 这将飞往怀俄明州,并在飞行完成后将其选中。
viewer.flyTo(wyoming).then(function(result){
if (result) {
viewer.selectedEntity = wyoming;
}
});
如果成功完成了飞行,则传递给我们的回调函数的结果参数将为true;如果取消飞行,即用户在此飞行完成之前发起了另一个飞行或缩放,或者因为目标没有相应的可视化效果,即存在 没有可缩放的内容。
有时,尤其是在使用时间动态数据时,我们希望相机保持在实体上而不是在地球上居中。 这是通过设置viewer.trackedEntity 来完成的。 跟踪实体需要设置 position。
wyoming.position = Cesium.Cartesian3.fromDegrees(-107.724, 42.68);
viewer.trackedEntity = wyoming;
通过将 viewer.trackedEntity 设置为undefined或通过双击实体来停止跟踪。 调用zoomTo或flyTo也将取消跟踪。
Managing entities (管理 entities)
EntityCollection 是用于管理和监视一组实体的关联数组。 viewer.entities是一个EntityCollection。 EntityCollection包括用于管理实体的方法,例如 add,remove和 removeAll。
有时我们需要更新先前创建的实体。 所有实体实例都有一个唯一的 ID,可用于从集合中检索实体。 我们可以指定一个ID,否则将自动生成一个。
viewer.entities.add({
id : 'uniqueId'
});
使用 getById 检索实体。 如果不存在具有提供的ID的实体,则返回undefined。
var entity = viewer.entities.getById('uniqueId');
要获取实体或创建一个不存在的实体,请使用 getOrCreateEntity。
var entity = viewer.entities.getOrCreateEntity('uniqueId');
手动创建一个新实体,然后使用 add 将其添加到集合中。 如果集合中已经存在具有相同ID的实体,则抛出此方法。
var entity = new Entity({
id : 'uniqueId'
});
viewer.entities.add(entity);
EntityCollection的功能通过 collectionChanged 事件发挥作用。 当在集合中添加,删除或更新实体时,这会通知侦听器。
使用 Sandcastle 中的 Geometry Showcase 示例。 在创建查看器的行之后粘贴以下代码。
function onChanged(collection, added, removed, changed){
var msg = 'Added ids';
for(var i = 0; i < added.length; i++) {
msg += '\n' + added[i].id;
}
console.log(msg);
}
viewer.entities.collectionChanged.addEventListener(onChanged);
运行该示例时,您应该在控制台中看到大约65条消息,每个对viewer.entities.add的调用都将显示一条消息。
一次更新大量实体时,将更改排队并在最后发送一个大事件的性能更高。 这样,Cesium 就可以一次处理所需的更改。 在 viewer.entities.add 之前调用 viewer.entities.suspendEvents ,并在示例末尾调用viewer.entities.resumeEvents。 当我们再次运行该演示时,我们现在得到一个包含所有65个实体的事件。 这些调用是引用计数,因此可以嵌套多个暂停和恢复调用。
Picking
拾取(单击以选择一个对象)是我们需要与Primitive API进行短暂交互的区域之一。 使用 scene.pick 和 scene.drillPick 检索实体。
/**
* Returns the top-most entity at the provided window coordinates
* or undefined if no entity is at that location.
*
* @param {Cartesian2} windowPosition The window coordinates.
* @returns {Entity} The picked entity or undefined.
*/
function pickEntity(viewer, windowPosition) {
var picked = viewer.scene.pick(windowPosition);
if (defined(picked)) {
var id = Cesium.defaultValue(picked.id, picked.primitive.id);
if (id instanceof Cesium.Entity) {
return id;
}
}
return undefined;
};
/**
* Returns the list of entities at the provided window coordinates.
* The entities are sorted front to back by their visual order.
*
* @param {Cartesian2} windowPosition The window coordinates.
* @returns {Entity[]} The picked entities or undefined.
*/
function drillPickEntities(viewer, windowPosition) {
var i;
var entity;
var picked;
var pickedPrimitives = viewer.scene.drillPick(windowPosition);
var length = pickedPrimitives.length;
var result = [];
var hash = {};
for (i = 0; i < length; i++) {
picked = pickedPrimitives[i];
entity = Cesium.defaultValue(picked.id, picked.primitive.id);
if (entity instanceof Cesium.Entity &&
!Cesium.defined(hash[entity.id])) {
result.push(entity);
hash[entity.id] = true;
}
}
return result;
};
Points, billboards, and labels
通过设置位置,point 和 label 来创建图形点或标签。 例如,在我们最喜欢的运动队的主场上放置一个点。
var viewer = new Cesium.Viewer('cesiumContainer');
var citizensBankPark = viewer.entities.add({
name : 'Citizens Bank Park',
position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534),
point : {
pixelSize : 5,
color : Cesium.Color.RED,
outlineColor : Cesium.Color.WHITE,
outlineWidth : 2
},
label : {
text : 'Citizens Bank Park',
font : '14pt monospace',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
pixelOffset : new Cesium.Cartesian2(0, -9)
}
});
viewer.zoomTo(viewer.entities);
默认情况下,标签在水平和垂直方向上居中。 由于标签和点共享相同的位置,因此它们在屏幕上重叠。 为避免这种情况,请指定标签原点 VerticalOrigin.BOTTOM 并将像素偏移设置为(0,-9)。
用 billboard 代替该点,广告牌(billboard)是始终面向用户的标记。
var citizensBankPark = viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534),
billboard : {
image : '//cesium.com/images/docs/tutorials/creating-entities/Philadelphia_Phillies.png',
width : 64,
height : 64
},
label : {
text : 'Citizens Bank Park',
font : '14pt monospace',
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
outlineWidth : 2,
verticalOrigin : Cesium.VerticalOrigin.TOP,
pixelOffset : new Cesium.Cartesian2(0, 32)
}
});
有关更多自定义选项,请参阅Sandcastle Labels 和 Billboards Sandcastle示例。
3D models
CesiumJS通过运行时资产格式 glTF 支持 3D models。 您可以在3D模型Sandcastle示例中找到示例模型。
为glTF模型设置位置和URI,以创建模型实体。
var viewer = new Cesium.Viewer('cesiumContainer');
var entity = viewer.entities.add({
position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
model : {
uri : '../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb'
}
});
viewer.trackedEntity = entity;
默认情况下,模型是直立的并面向东。 通过为 Entity.orientation属性指定一个 Quaternion 来控制模型的方向。 这将控制模型的航向,俯仰和横滚。
var viewer = new Cesium.Viewer('cesiumContainer');
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706);
var heading = Cesium.Math.toRadians(45.0);
var pitch = Cesium.Math.toRadians(15.0);
var roll = Cesium.Math.toRadians(0.0);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, pitch, roll));
var entity = viewer.entities.add({
position : position,
orientation : orientation,
model : {
uri : '../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb'
}
});
viewer.trackedEntity = entity;
有关更多高级模型功能,请参见 3D Model 教程。 如果您创建自己的模型,请务必查看我们在 glTF Tips for Artists。
The property system
我们为实体定义的所有值都存储为Property对象。 例如,请参见怀俄明州大纲的值:
console.log(typeof wyoming.polygon.outline);
outline是 ConstantProperty 的一个实例。 本教程使用一种称为“隐式属性转换”的简写形式,该形式会自动获取原始值并在后台创建相应的Property。 如果没有这个速记,我们将不得不编写一个更长的版本来显示初始示例:
var wyoming = new Cesium.Entity();
wyoming.name = 'Wyoming';
var polygon = new Cesium.PolygonGraphics();
polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.5));
polygon.outline = new Cesium.ConstantProperty(true);
polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.BLACK);
wyoming.polygon = polygon;
viewer.entities.add(wyoming);
使用属性是因为Entity API不仅可以表示常量值,还可以表示随时间变化的值。 请参阅 Callback Property 和 Interpolation Sandcastle examples,以了解一些动态属性。
Resources
查看 Cesium Workshop 教程,以获取有关如何使用GeoJSON和CZML设置样式和创建实体的示例。