目录
(8)加载和设计实体(Loading and Styling Entities)
Showcase your work on cesiumjs.org(展示你的作品)
Discover and process content on Cesium ion
(8)加载和设计实体(Loading and Styling Entities)
既然我们已经使用视图配置、影像和地形,这已经为应用程序做好了准备,那么我们可以添加应用程序的主焦点--样例geocache数据(藏宝点数据)。
为了简单可视化,Cesium支持流行的矢量格式数据GeoJson和KML,还有我们特地为描述Cesium中场景所开发的开源数据格式CZML。
无论初始化格式如何,Cesium中所有空间数据都使用实体API表示(the Entity API)。实体API提供了一种灵活可视化格式,这种格式对于Cesium的展现非常有效。一个Cesium实体(Entity)是一种数据对象,它可以与样式化的图形表示形式配对,并定位于空间和时间上,沙堡长廊提供了许多简单实体的例子(many examples of simple entities)。为了快速进入实体API的基础,从这些应用程序中抽出时间来阅读可视化空间数据的(Visualizing Spatial Data)教程。
下面是一些不同实体类型的示例:
一旦你掌握了实体的样子,那么使用Cesium加载数据集就变得很好理解。为了读入一个数据文件,需要创建一个适合数据格式的数据源(DataSource),其将解析托管在指定url中的数据文件,并创建一个实体收集器(EntityCollection),其包含数据集中每个地理空间对象的实体。数据源仅仅定义了数据接口-你需要的确切数据源类型取决于数据格式。例如,KML使用KmlDataSource,它是这样的:
var kmlOptions = {
camera : viewer.scene.camera,
canvas : viewer.scene.canvas,
clampToGround : true
};
// Load geocache points of interest from a KML file
// Data from : http://catalog.opendata.city/dataset/pediacities-nyc-neighborhoods/resource/91778048-3c58-449c-a3f9-365ed203e914
var geocachePromise = Cesium.KmlDataSource.load('./Source/SampleData/sampleGeocacheLocations.kml', kmlOptions);
这段代码通过使用几个选项,调用KmlDataSource.load(options)来从一个KML文件中读取我们样例的藏宝点数据。对于一个KmlDataSource,相机和画布选项是必须的,clampToGround选项支持地面贴近(ground clampling),这是一种流行的显示选项,它使地面几何实体(如多边形和椭圆)符合地形,而不是曲线符合WGS84椭球面。
由于该数据是异步加载的,因此它向KmlDataSource返回一个承诺(Promise),KmlDataSource将保存我们创建的所有实体。
如果对异步函数的Promise API不熟悉的话,这里的异步主要意思是,应该对提供给.then回调函数中的数据做需要做的事情。实际上为了给场景增加这样的实体收集器,我们必须要等promise解决,然后向viewer.datasources增加KmlDataSource。 取消注释下面代码:
// Add geocache billboard entities to scene and style them
geocachePromise.then(function(dataSource) {
// Add the new data as entities to the viewer
viewer.dataSources.add(dataSource);
});
默认情况下,新创建的实体具备可用的功能。点击将显示与实体相关的元数据信息框(Infobox),双击放大并查看实体。要停止查看实体的话,可以点击home按钮,或者点击信息框的关闭相机图标。接下来,我们将添加定制样式来改进应用程序的外观。
对于KML和CZML文件,声明样式已经创建到了文件中。然而,对于这个应用来说,我们将练习手工设置实体的样式。要这样做的话,通过等待数据源加载完成,采取一种相似的方法来实现样式例子(this styling example),然后遍历数据源中的所有实体,修改和增加属性。默认情况下,我们藏宝点标记是作为广告牌(Billboards)和标签(Labels)创建的,因此为了修改这些实体的外观,我们这样做:
// Add geocache billboard entities to scene and style them
geocachePromise.then(function(dataSource) {
// Add the new data as entities to the viewer
viewer.dataSources.add(dataSource);
// Get the array of entities
var geocacheEntities = dataSource.entities.values;
for (var i = 0; i < geocacheEntities.length; i++) {
var entity = geocacheEntities[i];
if (Cesium.defined(entity.billboard)) {
// Entity styling code here
}
}
});
我们可以通过调整标记的锚点、移除标签以减少混乱及设置displayDistanceCondition来改善标记的外观,这样只有在相机设置的距离范围内的点才能可见。
// Add geocache billboard entities to scene and style them
if (Cesium.defined(entity.billboard)) {
// Adjust the vertical origin so pins sit on terrain
entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
// Disable the labels to reduce clutter
entity.label = undefined;
// Add distance display condition
entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0);
}
更多distanceDisplayCondition的帮助,可以查看沙堡例子(sandcastle example)。
接下来,让我们改进每个藏宝点实体的Infobox。信息盒子的标题是实体的名字,内容是实体的表述,显示为HTML。
你可能注意到了,默认的描述不是很有用。由于我们正在显示藏宝点的位置,所以更新用来显示点的经纬度信息。
首先,将实体的位置转化为地图,然后从地图中读取经纬度,再增加到HTML表的描述中。
当点击的时候,藏宝点实体将显示一个格式好的信息框(Infobox),其中包含我们需要的数据。
// Add geocache billboard entities to scene and style them
if (Cesium.defined(entity.billboard)) {
// Adjust the vertical origin so pins sit on terrain
entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
// Disable the labels to reduce clutter
entity.label = undefined;
// Add distance display condition
entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0);
// Compute longitude and latitude in degrees
var cartographicPosition = Cesium.Cartographic.fromCartesian(entity.position.getValue(Cesium.JulianDate.now()));
var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude);
var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
// Modify description
// Modify description
var description = '<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>' +
'<tr><th>' + "Longitude" + '</th><td>' + longitude.toFixed(5) + '</td></tr>' +
'<tr><th>' + "Latitude" + '</th><td>' + latitude.toFixed(5) + '</td></tr>' +
'</tbody></table>';
entity.description = description;
}
我们的藏宝点标记现在看起来应该是这样的: