本文记录了在cesium地图中指定经纬度点绘制指定高度的柱子的代码。
一、效果展示
结果如下图示,在指定经纬度点绘制指定高度的柱子。
二、输入格式
输入的文件格式是json格式,数据格式如下所示,三个三个一组,分别是经度维度和高度。
//WebGL Globe JSON is an array of series, where each series itself is an
//array of two items, the first containing the series name and the second
//being an array of repeating latitude, longitude, height values.
/
/Here's a more visual example.
[["series1",[latitude, longitude, height, ... ]
["series2",[latitude, longitude, height, ... ]]
三、完整代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<!-- 包含 CesiumJS 的 JavaScript 和 CSS 文件 -->
<script src="cesium/Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="cesium/Build/Cesium/Widgets/widgets.css">
</head>
<body>
<div id="cesiumContainer"></div>
<script type="module">
/**
* 这个类是一个自定义 DataSource 的示例。它加载 Google 的 WebGL Globe(https://github.com/dataarts/webgl-globe)
* 定义的 JSON 数据。
* @alias WebGLGlobeDataSource
* @constructor
*
* @param {string} [name] 此数据源的名称。如果未定义,将从 URL 中派生名称。
*
* @example
* const dataSource = new Cesium.WebGLGlobeDataSource();
* dataSource.loadUrl('sample.json');
* viewer.dataSources.add(dataSource);
*/
function WebGLGlobeDataSource(name) {
// 所有公共配置都被定义为 ES5 属性
// 这些是 "私有" 变量及其默认值。
this._name = name;
this._changed = new Cesium.Event();
this._error = new Cesium.Event();
this._isLoading = false;
this._loading = new Cesium.Event();
this._entityCollection = new Cesium.EntityCollection();
this._seriesNames = [];
this._seriesToDisplay = undefined;
this._heightScale = 10000000;
this._entityCluster = new Cesium.EntityCluster();
}
Object.defineProperties(WebGLGlobeDataSource.prototype, {
// 以下属性必须由所有 DataSource 实例实现
/**
* 获取此实例的可读名称。
* @memberof WebGLGlobeDataSource.prototype
* @type {String}
*/
name: {
get: function () {
return this._name;
},
},
/**
* 由于 WebGL Globe JSON 不是时间动态的,此属性始终为未定义。
* @memberof WebGLGlobeDataSource.prototype
* @type {DataSourceClock}
*/
clock: {
value: undefined,
writable: false,
},
/**
* 获取 Entity 实例的集合。
* @memberof WebGLGlobeDataSource.prototype
* @type {EntityCollection}
*/
entities: {
get: function () {
return this._entityCollection;
},
},
/**
* 获取一个值,指示数据源当前是否正在加载数据。
* @memberof WebGLGlobeDataSource.prototype
* @type {Boolean}
*/
isLoading: {
get: function () {
return this._isLoading;
},
},
/**
* 获取在底层数据发生变化时将被触发的事件。
* @memberof WebGLGlobeDataSource.prototype
* @type {Event}
*/
changedEvent: {
get: function () {
return this._changed;
},
},
/**
* 获取在处理过程中遇到错误时将被触发的事件。
* @memberof WebGLGlobeDataSource.prototype
* @type {Event}
*/
errorEvent: {
get: function () {
return this._error;
},
},
/**
* 获取数据源启动或停止加载时将被触发的事件。
* @memberof WebGLGlobeDataSource.prototype
* @type {Event}
*/
loadingEvent: {
get: function () {
return this._loading;
},
},
// 这些属性特定于此 DataSource。
/**
* 获取系列名称的数组。
* @memberof WebGLGlobeDataSource.prototype
* @type {string[]}
*/
seriesNames: {
get: function () {
return this._seriesNames;
},
},
/**
* 获取或设置要显示的系列的名称。WebGL JSON 被设计为一次只能查看一个系列。
* 有效值在 seriesNames 属性中定义。
* @memberof WebGLGlobeDataSource.prototype
* @type {String}
*/
seriesToDisplay: {
get: function () {
return this._seriesToDisplay;
},
set: function (value) {
this._seriesToDisplay = value;
// 遍历所有实体,并仅在它们属于当前系列时将其 show 属性设置为 true。
const collection = this._entityCollection;
const entities = collection.values;
collection.suspendEvents();
for (let i = 0; i < entities.length; i++) {
const entity = entities[i];
entity.show = value === entity.seriesName;
}
collection.resumeEvents();
},
},
heightScale: {
get: function () {
return this._heightScale;
},
set: function (value) {
if (value <= 0) {
throw new Cesium.DeveloperError("value must be greater than 0");
}
this._heightScale = value;
},
},
/**
* 获取或设置应该显示此数据源的标志。
* @memberof WebGLGlobeDataSource.prototype
* @type {Boolean}
*/
show: {
get: function () {
return this._entityCollection;
},
set: function (value) {
this._entityCollection = value;
},
},
/**
* 获取或设置此数据源的聚类选项。此对象可在多个数据源之间共享。
* @memberof WebGLGlobeDataSource.prototype
* @type {EntityCluster}
*/
clustering: {
get: function () {
return this._entityCluster;
},
set: function (value) {
if (!Cesium.defined(value)) {
throw new Cesium.DeveloperError("value 必须被定义。");
}
this._entityCluster = value;
},
},
});
/**
* 异步加载提供的 URL 中的 GeoJSON,替换任何现有数据。
* @param {object} url 要处理的 URL。
* @returns {Promise} 将在加载 GeoJSON 时解析的 Promise。
*/
WebGLGlobeDataSource.prototype.loadUrl = function (url) {
if (!Cesium.defined(url)) {
throw new Cesium.DeveloperError("url 是必需的。");
}
// 根据 URL 创建一个名称
const name = Cesium.getFilenameFromUri(url);
// 如果名称与当前名称不同,则设置名称。
if (this._name !== name) {
this._name = name;
this._changed.raiseEvent(this);
}
// 将 URL 加载到 json 对象中,然后用 'load' 函数处理它。
const that = this;
return Cesium.Resource.fetchJson(url)
.then(function (json) {
return that.load(json, url);
})
.catch(function (error) {
// 如果出现任何错误或异常,将捕获并触发错误事件并拒绝 Promise。
this._setLoading(false);
that._error.raiseEvent(that, error);
return Promise.reject(error);
});
};
/**
* 加载提供的数据,替换任何现有数据。
* @param {Array} data 要处理的对象。
*/
WebGLGlobeDataSource.prototype.load = function (data) {
//>>includeStart('debug', pragmas.debug);
if (!Cesium.defined(data)) {
throw new Cesium.DeveloperError("data 是必需的。");
}
//>>includeEnd('debug');
// 清除可能已经存在的任何数据。
this._setLoading(true);
this._seriesNames.length = 0;
this._seriesToDisplay = undefined;
const heightScale = this.heightScale;
const entities = this._entityCollection;
// 当对大量实体进行更改时,最好在 suspendEvents 中暂停事件。
// 这将使事件被批处理为最小的函数调用,并在处理结束时(调用 resumeEvents 时)全部发生。
entities.suspendEvents();
entities.removeAll();
// WebGL Globe JSON 是一个系列的数组,其中每个系列本身是一个由两个项组成的数组,
// 第一个项包含系列名称,第二个项是重复的纬度、经度、高度值数组。
//
// 这里有一个更直观的例子。
//[["series1",[latitude, longitude, height, ... ]
// ["series2",[latitude, longitude, height, ... ]]
// 遍历每个系列
for (let x = 0; x < data.length; x++) {
const series = data[x];
const seriesName = series[0];
const coordinates = series[1];
// 将系列名称添加到我们可能值的列表中。
this._seriesNames.push(seriesName);
// 默认情况下使第一个系列可见
const show = x === 0;
if (show) {
this._seriesToDisplay = seriesName;
}
// 现在遍历系列中的每个坐标,并从数据中创建我们的实体。
for (let i = 0; i < coordinates.length; i += 3) {
const latitude = coordinates[i];
const longitude = coordinates[i + 1];
const height = coordinates[i + 2];
// 忽略高度为零的线条。
if (height === 0) {
continue;
}
const color = Cesium.Color.fromHsl(0.6 - height * 0.5, 1.0, 0.5);
const surfacePosition = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
0
);
const heightPosition = Cesium.Cartesian3.fromDegrees(
longitude,
latitude,
height * heightScale
);
// WebGL Globe 只包含线条,所以这是唯一创建的图形。
const polyline = new Cesium.PolylineGraphics();
polyline.material = new Cesium.ColorMaterialProperty(color);
polyline.width = new Cesium.ConstantProperty(2);
polyline.arcType = new Cesium.ConstantProperty(
Cesium.ArcType.NONE
);
polyline.positions = new Cesium.ConstantProperty([
surfacePosition,
heightPosition,
]);
//Polyline 实例本身需要在一个实体上。
const entity = new Cesium.Entity({
id: `${seriesName} index ${i.toString()}`,
show: show,
polyline: polyline,
seriesName: seriesName, // 自定义属性,指示系列名称
});
// 将实体添加到集合中。
entities.add(entity);
}
}
// 完成所有数据处理后,调用 resumeEvents 并触发 changed 事件。
entities.resumeEvents();
this._changed.raiseEvent(this);
this._setLoading(false);
};
WebGLGlobeDataSource.prototype._setLoading = function (isLoading) {
if (this._isLoading !== isLoading) {
this._isLoading = isLoading;
this._loading.raiseEvent(this, isLoading);
}
};
// 现在我们已经定义了自己的 DataSource,我们可以使用它来加载
// 任何针对 WebGL Globe 格式化的 JSON 数据。
const dataSource = new WebGLGlobeDataSource();
dataSource
.loadUrl("cesium/Apps/SampleData/HLtest1.json")
.then(function () {
// 初始化加载后,创建按钮让用户在系列之间切换。
function createSeriesSetter(seriesName) {
return function () {
dataSource.seriesToDisplay = seriesName;
};
}
for (let i = 0; i < dataSource.seriesNames.length; i++) {
const seriesName = dataSource.seriesNames[i];
Sandcastle.addToolbarButton(
seriesName,
createSeriesSetter(seriesName)
);
}
});
// 创建 Viewer 实例并添加 DataSource。
const viewer = new Cesium.Viewer("cesiumContainer", {
animation: false,
timeline: false,
});
viewer.clock.shouldAnimate = false;
viewer.dataSources.add(dataSource);
</script>
</div>
</body>
</html>