Cesium可视化空间数据(二)

admin0条评论 648 次浏览

可视化空间数据

本教程将教您如何使用Cesium的实体API来绘制空间数据,如点,标记,标签,线条,模型,形状和体积。不需要预先获得铯的知识,但如果您完全没有使用铯的经验,您可能需要从我们的第一个教程开始,Cesium开始运行

什么是实体API?

Cesium拥有丰富的空间数据API,可以分为两类:面向图形开发人员的低级API(通常称为Primitive API)和用于数据驱动的可视化的高级API(称为实体API。

Primitive API的主要目标是揭示执行手头任务所需的最少量抽象。它期望我们像图形程序员一样思考并使用图形术语。它旨在为给定的可视化类型提供最高性能和灵活的实现,而不是API一致性。加载模型与创建广告牌不同,它们与创建多边形完全不同。每种类型的可视化都有其独特的功能。此外,他们每个人都有不同的表现特征,需要遵循不同的最佳做法。尽管功能强大且灵活,但大多数应用程序的抽象级别比Primitive API提供的要高。

实体API的目标是公开一组统一设计的高级对象,这些对象将相关的可视化和信息聚合成统一的数据结构,我们称之为实体。它让我们专注于数据的呈现,而不用担心可视化的潜在机制。它还提供了一种构造方式,用于以与静态数据自然吻合的方式轻松构建复杂的时间动态可视化。虽然Entity API实际上在底层使用了Primitive API,但这是我们将(几乎)不必关心的实现细节。通过对我们提供的数据应用各种启发式,Entity API能够提供灵活,高性能的可视化,同时展示一致,易学易用的界面。

我们的第一个实体

学习实体API基础知识的最佳方法之一是查看一些代码。为了简单起见,我们将在Cesium Sandcastle中构建Hello World示例。如果您的设置是在本地进行Cesium开发,请随时使用您自己的应用程序。

假设我们想从经度和纬度的列表中为美国怀俄明州添加一个多边形。(选择怀俄明是因为它是一个简单的多边形。)我们可以将以下代码复制并粘贴到Sandcastle中:

var viewer = new Cesium.Viewer('cesiumContainer');

var wyoming = viewer.entities.add({
  name : 'Wyoming',
  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);

点击运行按钮(或F8为那些喜欢键盘),让我们下面的图像:

怀俄明我们的第一个实体 怀俄明州从未如此激动人心。

由于我们的目标之一是使铯代码易于理解,所以希望上述内容能够自我解释。我们创建Viewer窗口小部件,作为几乎所有Cesium应用程序的基础,然后通过viewer.entities.add添加一个新实体。我们传递添加的对象只是一个提供初始值的选项参数。返回值是实际的实体实例。最后,我们调用viewer.zoomTo来确保实体在视图中。

有一个令人难以置信的实体选项可用,但现在我们为多边形内部指定半透明红色,为边框指定黑色边框。我们也给实体显示名称“怀俄明州”。

形状和体积

有了创建多边形的基本知识,并且由于Entity API的同质性,我们现在可以通过简单地使用Sandcastle中的示例作为参考来创建各种图形。以下是支持的形状和体积的完整列表。

框 entity.box – 代码示例 – 参考文档
圆和椭圆 椭圆 entity.ellipse – 代码示例 – 参考文档
走廊 走廊 entity.corridor – 代码示例 – 参考文档
圆筒和锥体 圆筒 entity.cylinder – 代码示例 – 参考文档
多边形 多边形 entity.polygon – 代码示例 – 参考文档
折线 折线 entity.polyline – 代码示例 – 参考文档
折线卷 卷 entity.polylineVolume – 代码示例 – 参考文档
矩形 长方形 entity.rectangle – 代码示例 – 参考文档
球体和椭球体 椭球 entity.ellipsoid – 代码示例 – 参考文档
墙壁 壁 entity.wall – 代码示例 – 参考文档

材料和概述

无论其几何定义如何,所有形状和体积都有一组共同的属性来控制它们的外观。该fill属性是一个布尔值,用于指定曲面的内部是否已填充,而outline属性控制是否勾勒出形状的边缘。

fill设置为时truematerial属性确定填充看起来像什么。在我们的下一个例子中,我们来创建一个半透明的蓝色椭圆。默认情况下,fillis trueoutline是false,所以我们只需要指定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

材质颜色

图片

我们可以轻松地为图片指定一个网址。

ellipse.material = '//cesiumjs.org/tutorials/images/cats.jpg';

材料图像

在上述两种情况下,ColorMaterialPropertyImageMaterialProperty都是在分配时自动为我们创建的。对于更复杂的材料,我们需要自己创建一个MaterialProperty实例。目前,实体形状和体积支持颜色,图像,棋盘格,条纹和网格材质。

棋盘

ellipse.material = new Cesium.CheckerboardMaterialProperty({
  evenColor : Cesium.Color.WHITE,
  oddColor : Cesium.Color.BLACK,
  repeat : new Cesium.Cartesian2(4, 4)
});

棋盘格材质

条纹

ellipse.material = new Cesium.StripeMaterialProperty({
  evenColor : Cesium.Color.WHITE,
  oddColor : Cesium.Color.BLACK,
  repeat : 32
});

条纹材料

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)
});

网格材质

纲要

不同于fill属性,outline不具有相应的材料,而是依赖于两个单独的outlineColoroutlineWidth特性。outlineWidth仅适用于非Windows系统,如Android,iOS,Linux和OS X.在Windows系统上,轮廓总是宽度为1.这是由于在所有三种主要浏览器引擎中实施WebGL的限制在Windows上。

ellipse.fill = false;
ellipse.outline = true;
ellipse.outlineColor = Cesium.Color.YELLOW;
ellipse.outlineWidth = 2.0;

纲要

折线

折线是一种特殊情况,因为它们没有填充或大纲属性。相反,他们依赖于除了颜色以外的任何其他材料。由于这些特殊材料,不同宽度和轮廓宽度的多段线将适用于所有系统。

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);

折线

多彩轮廓

polyline.material = new Cesium.PolylineOutlineMaterialProperty({
    color : Cesium.Color.ORANGE,
    outlineWidth : 3,
    outlineColor : Cesium.Color.BLACK
});

多彩轮廓

折线发光

polyline.material = new Cesium.PolylineGlowMaterialProperty({
    glowPower : 0.2,
    color : Cesium.Color.BLUE
});

折线发光

高度和挤压

所有悬垂在地球上的形状,当前的圆形,椭圆形,多边形和矩形也可以放置在高空或挤压成一个体积。在这两种情况下,形状或体积仍然符合它下面的地球曲率。

我们需要为高度做的所有事情都是在相应的图形对象上设置高度属性,对于我们上面列出的所有形状都是一样的。这可能是提到Cesium总是使用米,弧度和秒来表示单位的好时机,除非函数明确另外说明,例如Cartesian3.fromDegrees。下面的代码行将多边形提升到地球上方250,000米。

wyoming.polygon.height = 250000;

怀俄明州在25万米怀俄明州在25万米。

将形状挤出成一个容易的同时,我们只需要设置extrudedHeight属性。音量将在height和之间创建extrudedHeight。如果heightundefined,音量从0开始。因此,要创建一个始于200,000米并延伸到250,000米的音量,我们可以使用下面的代码。这当然意味着卷本身高达5万米。

wyoming.polygon.height = 200000;
wyoming.polygon.extrudedHeight = 250000;

挤压多边形您可以轻松地将一个平面多边形挤出到一个体积中。

查看器中的实体功能

在深入探讨我们可以创建的其他类型的可视化之前,让我们看看Viewer为实体工作提供的开箱即用功能。

选择和说明

除非我们特别禁用它,否则单击查看器中的实体将在Entity的位置显示SelectionIndicator小部件,并显示InfoBox小部件以提供更多信息。回到我们最初的例子,我们只给wyoming实体提供了一个确定InfoBox标题的名称,但我们也可以通过Entity.description属性在HTML中提供额外的数据。让我们将下面的代码块添加到第一个示例的末尾。

wyoming.description = '\
<img\
  width="50%"\
  style="float:left; margin: 0 1em 1em 0;"\
  src="//cesiumjs.org/images/2015/02-02/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 62,448 in 2013.\
</p>\
<p>\
  Source: \
  <a style="color: WHITE"\
    target="_blank"\
    href="http://en.wikipedia.org/wiki/Wyoming">Wikpedia</a>\
</p>';

设置实体描述设置实体描述允许在InfoBox中显示HTML格式的信息。

许多应用程序将从服务器检索描述,而不是使用硬编码的字符串,但是这两种方法都是有效的。

默认情况下,InfoBox中显示的所有HTML 都是沙盒。这可以防止外部数据源将恶意代码注入Cesium应用程序。如果您希望能够在描述中运行JavaScript或浏览器插件,则可以通过viewer.infoBox.frame属性访问用于沙盒的iframe 。有关控制iframe沙箱的更多信息,请参阅这篇文章

相机控制

正如我们在第一个例子中看到的,我们可以使用zoomTo命令来显示特定的实体。同样的事情可以通过按InfoBox左上角的相机按钮或通过双击实体来完成。还有一个flyTo方法,可以产生相同的视图,但执行动画相机飞行而不是立即跳转。除了采用单个实体外,这两种方法都可以通过一个EntityCollection传递给我们,后面我们将讨论这个EntityCollection,一个DataSource,用于加载常见的数据格式,如GeoJSON,并且正在获取自己的教程,或者一个标准的JavaScript实体数组

默认情况下,任何方法都会计算一个视图,以确保提供的实体可见。相机将朝北并从45度角俯视目标。我们可以通过提供自己的标题,音高和范围来自定义此视图。下面的代码将旋转相机从东方观看怀俄明州,并以30度角俯视状态。由于我们没有指定范围,所以仍然会使用计算出的默认值。

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如果航班成功完成或false航班取消,即用户在此航班完成之前启动了其他航班或缩放,或者由于目标没有相应的可视化,即没有任何可缩放的内容,传递给我们回调的结果参数将为。

有时候,特别是在处理时间动态数据时,我们希望摄像机保持集中在一个实体上而不是地球上。这是通过设置viewer.trackedEntity属性来完成的。跟踪实体需要设置该位置。要用我们的第一个例子尝试这种模式,我们可以向怀俄明州添加一个位置并像这样追踪它:

wyoming.position = Cesium.Cartesian3.fromDegrees(-107.724, 42.68);
viewer.trackedEntity = wyoming;

我们可以停止或者设置跟踪viewer.trackedEntityundefined或点击的的左上角的取消按钮信息框。调用zoomToflyTo也会取消跟踪并且viewer.trackedEntity将变为undefined

对于很多用例来说,Viewer提供的特定于实体的相机功能已经绰绰有余,但如果您想在应用程序中进一步自定义视图,请查看Camera教程

管理实体

EntityCollection是一个关联数组,可以轻松管理和监视一组实体。我们已经以viewer.entities属性的形式遇到了它的一个实例。EntityCollection包含传统方法,例如add, removeremoveAll ; 以及我们在下面讨论的实体特定功能。

许多应用程序依赖于存储在服务器上的数据,直到客户端需要为止。有时这意味着我们需要更新我们以前创建的实体。所有实体实例都有一个唯一的id属性,可用于这种情况。由于我们没有在第一个示例中指定标识符,因此Cesium 为我们生成了一个GUID,这导致了一个唯一的字符串182bdba4-2b3e-47ae-bf0b-83f6fde285fd。服务器上的数据很可能具有我们想要使用的唯一标识符,因此我们可以在实体创建时指定它:

viewer.entities.add({
    id : 'uniqueId'
});

稍后,我们可以使用getById检索实体。在没有提供id的实体存在的情况下,undefined返回。

var entity = viewer.entities.getById('uniqueId');

另一个常见用例是更新一个实体,如果它已经存在,但是如果它不存在,则创建一个新实体。getOrCreateEntity将始终使用提供的ID返回一个有效的实例,创建一个新实例并在必要时将其添加到集合中。

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(中removedchanged数组始终在此例中为空,因为它只会增加实体)。铯还内部订阅此事件以在需要时更新可视化。当一次更新大量实体时,排队更改并在最后发送一个大事件更具性能。这可以提高性能,因为Cesium可以一次处理任何所需的更改。为此,我们可以在更新开始时调用viewer.entities.suspendEvents,然后调用viewer.entities.resumeEvents

让我们试试这个。在第一个viewer.entities.add之前添加暂停呼叫,并在示例结尾处添加简历呼叫。当我们再次运行演示时,我们现在得到一个包含全部65个实体的事件。这些调用是引用计数,因此多个挂起和恢复调用可以嵌套而不会出现任何问题。但是,忘记在处理结束时调用简历将导致场景中没有任何内容显示,因为在每次挂起的呼叫都有匹配的呼叫恢复之前,不会发送任何消息。

选择

拣选(即通常使用鼠标在给定的屏幕坐标处选择对象)仍然是Cesium中需要与Primitive API简要对接的区域之一。这将在未来版本的Cesium中通过引入实体特定的拣选功能进行补救。现在,我们可以使用底层函数scene.pickscene.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;
};

以下是他们的工作方式。尽管各种场景选取方法返回的是具有原始信息而不是实体实例的对象,但实体API的结构使得与实体相对应的每个原语都具有该实体作为其id属性。所以我们所要做的就是检查拾取的对象的id是否是实体的一个实例。尽管这些功能很简单,但它们并未作为Cesium的一部分,因为我们已经计划了更强大的功能。

点,广告牌和标签

留下形状和体积,让我们看看如何可视化铯中的特定兴趣点。

创建一个图形点或标签很简单,我们只需要为我们的实体指定一个位置, 并为可视化指定标签对象。例如,也许我们希望在我们最喜欢的运动队的主场馆放置一个点。

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);

点标签公民银行公园在宾夕法尼亚州费城。费城费城人的家乡。

这些选项大部分都是自我记录,但其中的一些需要一些解释。例如,字体设置遵循CSS紧凑字体语法

默认情况下,标签在该位置水平和垂直居中。由于标签和点共享相同的位置,它们通常会在屏幕上相互重叠。为了在点上方绘制标签,我们可以指定它的原点应该是底部,这意味着文本的底部是触及实体位置的部分,并且还指定屏幕空间中的偏移量。在上面的例子中,我们使用(0,-9),当与它结合时VerticalOrigin.BOTTOM,意味着标签的底部比实体位置高9个像素。该值为负值是因为我们想要减小屏幕坐标的Y值,该值从顶部开始,随着屏幕向下移动而增加。设置原点和偏移量可确保标签总是高于我们的要点,而不管用户观看的角度或旋转角度如何。

当然,使用一个点并不是很令人兴奋,所以我们可以用一个广告牌来替代这个点,这是一个始终面向用户的标记。

var citizensBankPark = viewer.entities.add({
  position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534),
  billboard : {
    image : 'http://localhost:81/images/2015/02-02/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示例,以查看其中每个实例:标签广告牌

3D模型

Cesium通过glTF(用于WebGL,Op​​enGL ES和OpenGL的运行时资产格式)支持3D模型。它还包括一些随时可用的glTF机型:带有动画螺旋桨的飞机,带动画轮子的地面车辆以及带走皮循环的角色。所有这些都可以在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 : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf'
    }
});
viewer.trackedEntity = entity;

卡车模型Cesium附带的示例卡车模型。

您可以选择提供一个scale属性,该属性可以统一缩放模型的原始大小以及minimumPixelSize属性,从而防止模型出现比所提供的像素大小更小的属性。

默认情况下,模型直立并朝东。我们可以通过为Entity.orientation属性指定一个Quaternion来控制模型的方向。这比我们仅限于位置的例子要多一点,但让我们控制模型的标题,俯仰和滚动。我们可以将以下代码粘贴到Sandcastle中,并使用这些值来查看设置如何影响方向。

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, heading, pitch, roll);

var entity = viewer.entities.add({
    position : position,
    orientation : orientation,
    model : {
        uri : '../../SampleData/models/CesiumGround/Cesium_Ground.gltf'
    }
});
viewer.trackedEntity = entity;

由于需要将模型转换为用于Cesium的gltF格式,因此我们提供了一个基于Web的转换器,可以让您上传COLLADA模型并返回glTF版本。

尽管Entity API目前不支持高级模型用例,例如节点选取或直接动画控制,但我们可以使用Primitive API来完成它们。我们有一个单独的3D模型原始教程涵盖了这些情况。我们绝对计划在未来增强Entity API以包含这些功能。原始教程还包含调试模型的提示,这些模型在Cesium中不能正确显示,所以一定要检查一下。如果您创建自己的模型,请务必在glTF艺术家提示中查看我们的帖子。

财产制度

到目前为止,我们只为实体和图形对象赋值,我们从来没有真正读过任何值。事实上,如果我们试图这样做,我们会对结果感到惊讶。以我们true在第一个例子中分配给我们的多边形轮廓属性为例。直觉会告诉我们一个电话console.log会打印出来true

console.log(wyoming.polygon.outline);

上述代码的实际输出是[object Object]。这是因为outline它不是一个简单的布尔值,而是一个ConstantProperty的实例。实际上,整个教程实际上都使用了一种称为隐式属性转换的简写形式,在这种情况下,它会自动获取原始值并为我们创建一个对应的ConstantProperty实例。没有这个简写,我们就不得不写一个更长的版本的初始例子(为简洁起见省略了):

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不仅能够表达常量值,而且能够随着时间的推移而变化。

所有属性都实现了Property接口,并且Cesium中有很多不同类型的属性。本教程的第二部分将专注于Property系统并使用它来创建动画和其他时间动态可视化。现在,我们唯一需要知道的是,为了读取Property的值,我们需要调用getValue函数。因此,为了从多边形中检索轮廓属性,我们将调用下面的代码,其中时间是当前场景时间。

console.log(wyoming.polygon.outline.getValue(viewer.clock.currentTime));

从技术上讲,如果我们确信我们正在查询的属性是一个ConstantProperty,我们可以避免传递一段时间,但总是指定它是个好习惯。

从这往哪儿走

我们几乎没有弄清楚我们在Cesium中如何处理空间数据,但我们已经释放了大量的功能。在等待本教程的第二部分时,您可能会对Cesium对Imagery LayersTerrain and Water的支持感兴趣。一如既往,可以查看Cesium教程的完整列表,以决定接下来要学习的内容。