前言

本文为大家介绍几个Cesium的Demo,通过这几个Demo能够对如何使用Cesium有进一步的了解,并能充分理解Cesium的强大之处和新功能。其他的无需多言,如果还不太了解什么是Cesium,可以参见我的另外两篇关于Cesium的博客,下面直接进入正题。

一、 监听HTML控件

在Cesium中可以很方便的监听前台HTML控件,类似C#等语言中的MVVM。

1.1 前台控件

前台控件效果如下:

代码如下:

<div id="toolbar">
<div>SRTM</div>
<input min="0" max="100" step="1" data-bind="value: srtm, valueUpdate: 'input'" type="range">
<input size="5" data-bind="value: srtm" type="text">
<div>SLOPE</div>
<input min="0" max="100" step="1" data-bind="value: slope, valueUpdate: 'input'" type="range">
<input size="5" data-bind="value: slope" type="text">
<div>Type</div>
<select data-bind="options: types, optionsText: 'name', value: selectedType, optionsCaption: 'Choose a Type...'"></select>
</div>

首先创建一个div,js监测此div中的控件,重要的是id。

在此div中创建input,一个或多个input对应js中的一个变量,当然此多个input之间也是相互绑定的关系。如:

<input min="0" max="100" step="1" data-bind="value: srtm, valueUpdate: 'input'" type="range">
<input size="5" data-bind="value: srtm" type="text">

此二者均对应js端的srtm变量,第一个是range类型,代表一个slide控件,第二个是一个文本框,二者相互联动,只选择其中一个控件也是可以的。重要的是data-bind属性中value后的变量名称需与js中对应。

当然也可以绑定一个下拉列表框:

<select data-bind="options: types, optionsText: 'name', value: selectedType, optionsCaption: 'Choose a Type...'"></select>

这里就对应了js中的两个变量:types和selectedType。前者代表所有的可选列表及其值,后者代表选择的结果。

1.2 后台

首先创建一个viewModel对象,里面包含上述创建的各个变量,如下:

var viewModel = {
srtm: 10,
slope: 5,
types: [{
name: 'type1',
values: '100'
}, {
name: 'type2',
values: '200'
}
],
selectedType: undefined
};

而后对此变量进行监控并绑定到前台的相应控件:

Cesium.knockout.track(viewModel); // 跟踪此Model
var toolbar = document.getElementById('toolbar'); // 获取前端监控div
Cesium.knockout.applyBindings(viewModel, toolbar); // 绑定监控

这样就可以监听控件的变化事件:

Cesium.knockout.getObservable(viewModel, 'srtm').subscribe(function(value) {
...
});

可以对此值进行处理比如发送到后台或者请求相应的瓦片图层等等。不过下拉列表框的情况稍微复杂点:

Cesium.knockout.getObservable(viewModel, 'selectedType').subscribe(function(options) {
var values = options.values;
...
});

其实也就是多了一步,在定义types的时候除了name变量我们还定义了values变量,此处就需要通过options.values来取出此值,其他不变。

二、 根据地形瓦片直接绘制高程、坡度及等高线

这是Cesium 1.4.0版新添加的功能,所以一定要更新到此版本。只需要正确加载地形瓦片,Cesium可以自动算出高程设色瓦片、坡度设色瓦片以及等高线。其实也不难理解,地形瓦片中包含了空三等信息,根据这些信息自然能够计算出高度图、坡度图以及等高线,先来看效果:

加载地形瓦片图层无需多言,前面已经有过介绍:

viewer.terrainProvider = new Cesium.CesiumTerrainProvider({
url : 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask : true,
requestVertexNormals : true
});

然后就可以开始计算高程设色瓦片和坡度设色瓦片以及等高线,当然此块涉及到的东西太多,我只能凭借我粗浅的理解简单介绍,如有错误,望批评指正:

首先来看一下生成等高线:

var contourUniforms = {};
material = Cesium.Material.fromType('ElevationContour');
contourUniforms = material.uniforms;
contourUniforms.width = 1;
contourUniforms.spacing = 500;
contourUniforms.color = Cesium.Color.RED;

很简单的几行代码,其中Cesium.Material.fromType函数定义如下:

Material.fromType = function(type, uniforms) {
if (!defined(Material._materialCache.getMaterial(type))) {
throw new DeveloperError('material with type \'' + type + '\' does not exist.');
} var material = new Material({
fabric : {
type : type
}
}); if (defined(uniforms)) {
for (var name in uniforms) {
if (uniforms.hasOwnProperty(name)) {
material.uniforms[name] = uniforms[name];
}
}
} return material;
};

此函数返回一个Material对象,根据ElevationContour可以知道这是一个等高线类型的材质。uniforms是glsl着色器语言中的变量,用于控制对象颜色、位置等等。所以此处可以简单理解为得到ElevationContour类型的unifrom值并将此值作用于场景。Cesium根据此uniform生成相应类型的等高线。

理解了这一点,高程设色和坡度设色也就明白了。

高程设色如下:

var shadingUniforms = {};
material = Cesium.Material.fromType('ElevationRamp');
shadingUniforms = material.uniforms;
shadingUniforms.minHeight = -414.0;
shadingUniforms.maxHeight = 8777;

坡度设色如下:

var shadingUniforms = {};
material = Cesium.Material.fromType('SlopeRamp');
shadingUniforms = material.uniforms;

二者都需要为shadingUniforms变量添加一个色表:

shadingUniforms.image = getColorRamp(selectedShading);

var elevationRamp = [0.0, 0.045, 0.1, 0.15, 0.37, 0.54, 1.0];
var slopeRamp = [0.0, 0.29, 0.5, Math.sqrt(2)/2, 0.87, 0.91, 1.0];
function getColorRamp(selectedShading) {
var ramp = document.createElement('canvas');
ramp.width = 100;
ramp.height = 1;
var ctx = ramp.getContext('2d'); var values = selectedShading === 'elevation' ? elevationRamp : slopeRamp; var grd = ctx.createLinearGradient(0, 0, 100, 0);
grd.addColorStop(values[0], '#000000'); //black
grd.addColorStop(values[1], '#2747E0'); //blue
grd.addColorStop(values[2], '#D33B7D'); //pink
grd.addColorStop(values[3], '#D33038'); //red
grd.addColorStop(values[4], '#FF9742'); //orange
grd.addColorStop(values[5], '#ffd700'); //yellow
grd.addColorStop(values[6], '#ffffff'); //white ctx.fillStyle = grd;
ctx.fillRect(0, 0, 100, 1); return ramp;
}

对高程和坡度归一化后的值设置颜色。这样就可以正常显示高程设色和坡度设色。

三、 同一场景下显示两个不同的瓦片图层

不是简单的两个图层叠加,而是真实的分割整个地图,左右显示两个不同的瓦片图层。效果如下:

首先添加两个图层,第一个创建Viewer的时候设置基础图层,第二个采用layers.addImageryProvider的方式添加(当然也可以两个都采用此种方式添加),具体添加图层的方式参考前面的博客。

layer1 = layers.addImageryProvider(...);
layer2 = layers.addImageryProvider(...);

只需要设置layer1或则layer2的splitDirection属性即可:

layer2.splitDirection = Cesium.ImagerySplitDirection.LEFT;

当然还需要设置图层分割的位置:

viewer.scene.imagerySplitPosition = 0.5;

可以改变此值来改变左右图层的分割位置,0.5表示在中间。如果需要动态调整分割位置则需要加一个分割器,监听位置变化事件。整体代码如下:

前台:

<!--css-->
#slider {
position: absolute;
left: 50%;
top: 0px;
background-color: #D3D3D3;
width: 5px;
height: 100%;
z-index: 9999;
} #slider:hover {
cursor: ew-resize;
} <!--html-->
<div id="cesiumContainer">
<div id="slider"></div>
</div>

后台:

var viewer = new Cesium.Viewer('cesiumContainer', {
baseLayerPicker: false,
imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
url : 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
})
}); var layers = viewer.imageryLayers; var balckMarble = layers.addImageryProvider(Cesium.createTileMapServiceImageryProvider({
url : 'https://cesiumjs.org/blackmarble',
credit : 'Black Marble imagery courtesy NASA Earth Observatory',
flipXY : true
})); balckMarble.splitDirection = Cesium.ImagerySplitDirection.LEFT; var slider = document.getElementById('slider');
viewer.scene.imagerySplitPosition = (slider.offsetLeft) / slider.parentElement.offsetWidth; var handler = new Cesium.ScreenSpaceEventHandler(slider);
var moveActive = false;
function move(movement) {
if(!moveActive) {
return;
}
var relativeOffset = movement.endPosition.x ;
var splitPosition = (slider.offsetLeft + relativeOffset) / slider.parentElement.offsetWidth;
slider.style.left = 100.0 * splitPosition + '%';
viewer.scene.imagerySplitPosition = splitPosition;
} handler.setInputAction(function() {
moveActive = true;
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
handler.setInputAction(function() {
moveActive = true;
}, Cesium.ScreenSpaceEventType.PINCH_START); handler.setInputAction(move, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
handler.setInputAction(move, Cesium.ScreenSpaceEventType.PINCH_MOVE); handler.setInputAction(function() {
moveActive = false;
}, Cesium.ScreenSpaceEventType.LEFT_UP);
handler.setInputAction(function() {
moveActive = false;
}, Cesium.ScreenSpaceEventType.PINCH_END);

四、 改造geocoder控件

Cesium自带了geocoder控件,可以检索并定位到某个地址,原理很简单,就是后台解析此地址,根据解析结果将地图切换到该位置。Cesium默认采用的是微软Bing地址解析引擎,如果我们想要换成其他的如OSM或者我们自己的,只需要对此控件简单改造即可。示例代码如下:

/**
* This class is an example of a custom geocoder. It provides geocoding through the OpenStreetMap Nominatim service.
* @alias OpenStreetMapNominatimGeocoder
* @constructor
*/
function OpenStreetMapNominatimGeocoder() {
} /**
* The function called to geocode using this geocoder service.
*
* @param {String} input The query to be sent to the geocoder service
* @returns {Promise<GeocoderResult[]>}
*/
OpenStreetMapNominatimGeocoder.prototype.geocode = function (input) {
var endpoint = 'https://nominatim.openstreetmap.org/search?';
var query = 'format=json&q=' + input;
var requestString = endpoint + query;
return Cesium.loadJson(requestString) //请求url获取json数据
.then(function (results) {
var bboxDegrees;
return results.map(function (resultObject) {
bboxDegrees = resultObject.boundingbox;
return {
displayName: resultObject.display_name,
destination: Cesium.Rectangle.fromDegrees(
bboxDegrees[2],
bboxDegrees[0],
bboxDegrees[3],
bboxDegrees[1]
)
};
});
});
}; var viewer = new Cesium.Viewer('cesiumContainer', {
geocoder: new OpenStreetMapNominatimGeocoder()
});

首先创建了一个OpenStreetMapNominatimGeocoder类,并为其添加了geocode方法,在此方法中根据输入拼接请求url,解析结果取出经纬度、名称等内容。这样就实现了我们自己的地名解析器,其实这就是C#等语言中的父类和继承的关系。

五、 总结

本文介绍了几个Cesium的案例,都是一些比较有意思和好玩的功能,后续如果搜集到其他好玩的使用案例,同样也会总结放出。

Cesium几个案例介绍的更多相关文章

  1. 3星|《AI极简经济学》:AI的预测、决策、战略等方面的应用案例介绍

    AI极简经济学 主要内容是AI的各种应用案例介绍.作者把这些案例分到五个部分介绍:预测.决策.工具.战略.社会. 看书名和介绍以为会从经济学的角度解读AI,有更多的新鲜的视角和观点,读后比较失望,基本 ...

  2. 转 PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)

    PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)   通过curl_setopt()函数可以方便快捷的抓取网页(采集很方便),curl_setopt 是php的一个 ...

  3. Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程

    2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程 2014-12-07 23:39 2623人阅读 评论(0) ...

  4. Cesium 本地部署案例

    众所周知,cesium的服务器是搭建在国外的,所以我们国内的用户访问的时候贼慢.有时想查个api或者看个案例半天都进不去,今天我来说一下傻瓜式搭建本地的cesium环境,用于大家没事查资料用!步骤:1 ...

  5. SQL Delta实用案例介绍,很好的东西,帮了我不少忙

    SQL Delta实用案例介绍 概述 本篇文章主要介绍SQL DELTA的简单使用.为了能够更加明了的说明其功能,本文将通过实际项目中的案例加以介绍. 主要容 Ÿ   SQL DELTA 简介 Ÿ   ...

  6. 2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程

     1  Lucen目录介绍 2  lucene-core-3.6.2.jar是lucene开发核心jar包 contrib  目录存放,包含一些扩展jar包 3  案例 建立第一个Lucene项目 ...

  7. Mybatis学习笔记之一(环境搭建和入门案例介绍)

    一.Mybatis概述 1.1 Mybatis介绍 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了go ...

  8. Python+Selenium学习--案例介绍

    1. 前言 前面讲解了那么多selenium的基础知识,下面用一个简单案例来介绍,此案例主要实现,运行测试,自动生成html报告,并发生邮件. 2. 测试案例 2.1 目录结构介绍 conf:配置信息 ...

  9. SQL Delta实用案例介绍

    概述 本篇文章主要介绍SQL DELTA的简单使用.为了能够更加明了的说明其功能,本文将通过实际项目中的案例加以介绍. 主要容 Ÿ   SQL DELTA 简介 Ÿ   创建SQL DELTA项目 Ÿ ...

随机推荐

  1. Centos6.8 安装tomcat8.5.11

    1.下载 安装包 wget http://mirrors.aliyun.com/apache/tomcat/tomcat-8/v8.5.11/bin/apache-tomcat-8.5.11.tar. ...

  2. String类型

    String字符串的length属性返回的是该字符串里面16位字符的数量,如果字符串包含double-byte的字符,那么返回的数量可能不对   字符串一旦创建就修改不了 var lang = “Ja ...

  3. 八皇后问题 dfs/递归

    #include <bits/stdc++.h> using namespace std; const int maxn = 55; int ans=0; int vis_Q[maxn]; ...

  4. 从ELK到EFK演进

    背景 作为中国最大的在线教育站点,目前沪江日志服务的用户包含网校,交易,金融,CCTalk 等多个部门的多个产品的日志搜索分析业务,每日产生的各类日志有好十几种,每天处理约10亿条(1TB)日志,热数 ...

  5. MVC架构下,使用NPOI读取.DOCX文档中表格的内容

    1.使用NPOI,可以在没有安装office的设备上读wiod.office.2.本文只能读取.docx后缀的文档.3.MVC架构中,上传文件只能使用form表单提交,转到控制器后要依次实现文件上传. ...

  6. 简单了解split()函数的性质

    当分割的字符在字符串中间时,分割字符前面为一部分,后面为一部分.如: st='abccd' print(st.split('b')) 输出为:['a', 'ccd'] 当分隔符在字符串最前面或最后面时 ...

  7. 如何实现websocket服务器-理论篇

    WebSocket 服务器简单来说就是一个遵循特殊协议监听服务器任意端口的tcp应用.搭建一个定制服务器的任务通常会让让人们感到害怕.然而基于实现一个简单的Websocket服务器没有那么麻烦. 一个 ...

  8. Hadoop 2.2.0单节点的伪分布集成环境搭建

    Hadoop版本发展历史 第一代Hadoop被称为Hadoop 1.0 1)0.20.x 2)0.21.x 3)0.22.x 第二代Hadoop被称为Hadoop 2.0(HDFS Federatio ...

  9. bash, sh, dash 傻傻分不清楚

    原文链接,转载请注明出处: http://www.happycxz.com/m/?p=137 常见shell类型 Bourne shell (sh) UNIX 最初使用,且在每种 UNIX 上都可以使 ...

  10. [NOIP]玩具装箱

    题目:(非常经典的模拟赛题,适合动规入门的OIer) 简要分析:   动态规划,用一维数组 f[i] 表示从位置1 到 位置i 的最优花费 ,由于 f[i ] 以前的最优花费都是确定的,故只需要在 1 ...