Cesium使用记录

文章目录

  • Cesium使用记录
    • 一、软件版本
    • 二、记录
      • 1.初始化地图
      • 2.去除版权信息
      • 3.显示FPS控件
      • 4.飞跃到指定位置(坐标和高度)
      • 5.重置HOME按钮
      • 6.集成导航控件
      • 7.集成画图控件
      • 8.计算两个坐标之间的距离
      • 9.添加点集合
      • 10.Primitive加载Geometry
      • 11.动态设置Geometry显示隐藏
      • 12.控件与数据模型绑定
      • 13.监听事件
    • 三、其它
      • 1.获取当前JS的路径
      • 2.JQuery AJAX获取数据
      • 3.JS代码封装
      • 4.插值算法

Cesium使用记录

一、软件版本

  • Cesium 1.x.x

官网:https://cesium.com/cesiumjs/
官方API文档:https://cesium.com/docs/cesiumjs-ref-doc/
官方例子:https://sandcastle.cesium.com/

二、记录

1.初始化地图

var cesiumDivId = "cesiumContainer";
var online = false;
var cesiumViewer; // 后面会频繁使用

// 设置 token
Cesium.Ion.defaultAccessToken = "设置token值";
// 设置viewer参数 https://cesiumjs.org/Cesium/Build/Documentation/Viewer.html
var options = {
    geocoder: false,
    fullscreenButton: true,
    baseLayerPicker: false,
    navigationHelpButton: false
};
// 判断使用在线地图?还是离线地图?
if(online){// 在线地图
    cesiumViewer = new Cesium.Viewer(cesiumDivId, options);
    
}else{// 离线地图
    options.imageryProvider 
        = new Cesium.createTileMapServiceImageryProvider({
        url : "http://localhost:8080/NaturalEarthII/",
        flipXY: true
    });
    cesiumViewer = new Cesium.Viewer(cesiumDivId, options);
}
  • 在线地图 - 天地图(卫星图)
  1. 设置 ViewerimageryProvider 参数

  2. 注意替换天地图的tk

文档说明:

  • https://cesium.com/docs/cesiumjs-ref-doc/WebMapTileServiceImageryProvider.html?classFilter=WebMapTileServiceImageryProvider
  • http://lbs.tianditu.gov.cn/server/MapService.html
options.imageryProvider = new Cesium.WebMapTileServiceImageryProvider({
            url: "http://t1.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=天地图的tk",
            layer: "tdtBasicLayer",
            style: "default",
            format: "image/jpeg",
            tileMatrixSetID: "GoogleMapsCompatible",
            subdomains: ['t0', "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
            maximumLevel: 18,
            show: false
          })
  • 在线地图 - Google地图(卫星图)

设置 ViewerimageryProvider 参数

文档说明:https://cesium.com/docs/cesiumjs-ref-doc/UrlTemplateImageryProvider.html?classFilter=UrlTemplateImageryProvider

options.imageryProvider = new Cesium.UrlTemplateImageryProvider({
            url:'http://mt3.google.cn/vt/lyrs=s@110&hl=zh-CN&gl=cn&src=app&x={x}&y={y}&z={z}',
            tilingScheme:new Cesium.WebMercatorTilingScheme(),
    		// minimumLevel:1,
            maximumLevel:20,
            subdomains:["mt1","mt2","mt3"],
          })
  • 在线地图 - ArcGIS(卫星图)

设置 ViewerimageryProvider 参数

文档说明:https://cesium.com/docs/cesiumjs-ref-doc/ArcGisMapServerImageryProvider.html

options.imageryProvider = new Cesium.ArcGisMapServerImageryProvider({
    url : 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
});

2.去除版权信息

// 去除版权信息
cesiumViewer._cesiumWidget._creditContainer.style.display = "none";

3.显示FPS控件

// 显示FPS
cesiumViewer.scene.debugShowFramesPerSecond = true;

4.飞跃到指定位置(坐标和高度)

/**
 * 飞跃到指定位置
 * @param scene 场景对象 e.g. Ceisum#Viewer#scene
 * @param location 定位信息 e.g. {lon, lat, height}
 * */
function flyToLocation(scene, location) {
    scene.camera.flyTo({
        destination: Cesium.Cartesian3
        	.fromDegrees(location.lon, location.lat, location.height)
    });
};

5.重置HOME按钮

/**
 * 重置home按钮
 * @param viewer 视图对象 e.g. Ceisum#Viewer
 * @param location 定位信息 e.g. {lon, lat, height}
 * */
function resetHomeButton(viewer, location) {
    viewer.homeButton.viewModel.command.beforeExecute.addEventListener(
        function (e) {
        	e.cancel = true;
            // 飞跃到指定位置
        	flyToLocation(viewer.scene, location);
    	}
    );
}

6.集成导航控件

  • cesium-navigation

    github:https://github.com/alberto-acevedo/cesium-navigation/tree/master

  • 引入外部JS的方式

  1. 安装 nodejs

    官网:https://nodejs.org/en/download/

  2. cd 到项目根目录

  3. 运行命令:npm installnode build.js

  4. 编译完成后,\dist\standalone 拷贝 viewerCesiumNavigationMixin.js

  5. 页面引用 viewerCesiumNavigationMixin.js

/**
 * defaultResetView:导航控件-重置按钮的默认位置
 * (支持Cesium.Rectangle.fromDegrees 和 Cesium.Cartographic.fromDegrees)
 * enableCompass:启用或禁用罗盘
 * enableCompassOuterRing:启用或禁用指南针外环
 * enableDistanceLegend:启用或禁用距离图例
 * enableZoomControls:启用或禁用缩放控件
 */
var options = {
    "defaultResetView": Cesium.Cartographic
    			.fromDegrees(116.403694, 39.914271, 10000000.0),
    "enableCompass": true,
    "enableCompassOuterRing": true,
    "enableDistanceLegend": true,
    "enableZoomControls": false
}
cesiumViewer.extend(Cesium.viewerCesiumNavigationMixin, options);

7.集成画图控件

  • cesium-drawhelper

    https://github.com/leation/drawhelper-with-cesium-v1.41

  • 使用:

  1. 引入 drawhelper 的资源:DrawHelper.jsDrawHelper.css
  2. 页面代码
<div id="toolbar-drawhelper">div>
  1. js 代码
var drawHelper = new DrawHelper(cesiumViewer);
// buttons 属性正常是需要设置全部值的,这里是修改过 drawhelper 项目源码的
var drawToolbar = drawHelper.addToolbar(document.getElementById("toolbar-drawhelper"), {buttons: ['extent']});
// 画图监听
drawToolbar.addListener('extentCreated', function(event) {
    // 构建 polygon
    var extentPrimitive = new DrawHelper.ExtentPrimitive({
        extent: event.extent,
        material: Cesium.Material.fromType(Cesium.Material.StripeType)
    });
    // TODO 添加到 cesium
    // 设置编辑状态
    extentPrimitive.setEditable();
    // 编辑监听
    extentPrimitive.addListener('onEdited', function(event) {
        // TODO 编辑后的逻辑
    });
});
  • 关于 drawhelper 项目源码的修改记录:
  1. DrawHelper.js 初始化时,设置 buttons 属性,添加了是否需要配置某个按钮的判断,主要是应对不需要全部按钮初始化的场景,例如:

    修改:DrawHelper.js

// 这里 if 判断,在其它按钮上,也需要配置
if(options.buttons.indexOf("marker")!=-1){
    addIcon('marker', options.markerIcon, 'Click to start drawing a 2D marker', function () {
        drawHelper.startDrawingMarker({
            callback: function (position) {
                _self.executeListeners({ name: 'markerCreated', position: position });
            }
        });
    })
}
  1. 由于鼠标滑动时,经常滑动到提示窗口,导致有卡顿的感觉(画图不流畅),这个问题需要在 DrawHelper.css 中添加一个 css 样式进行解决 ,设置元素不会触发鼠标事件

    修改:DrawHelper.css

.twipsy {
    // ... 省略内容
    pointer-events:none;
}
  1. 按钮图片 404 的问题,使用本文第三部分的,获取当前JS路径的方法

    修改:DrawHelper.js

// 配置图片路径
var drawroot = getScriptPathByName("DrawHelper", true);
  1. 使用 Extent 画图时,除了返回 extent 数据外,还要返回 左上角 和 右下角 的点坐标

    修改:DrawHelper.js

// 画图监听返回(Extent)
DrawHelper.ExtentPrimitive.prototype.setEditable = function () {
    // ... 省略内容
    dragHandlers: {
    	onDrag: function (index, position) {
        	// ... 省略内容
            //左上角
        	value.firstpoint 
                = ellipsoid.cartesianToCartographic(corner);
            // 右下角
        	value.secondpoint 
                = ellipsoid.cartesianToCartographic(position);
        	extent.setExtent(value);
        	// ... 省略内容
    	}
	}
    // ... 省略内容
}
// 编辑图形监听的返回(Extent)
_.prototype.startDrawingExtent = function (options) {
    // ... 省略内容
    // Now wait for start
    mouseHandler.setInputAction(function (movement) {
        if (movement.position != null) {
            var cartesian 
            = scene.camera.pickEllipsoid(movement.position, ellipsoid);
            if (cartesian) {
                if (extent == null) {
                    // ... 省略内容
                } else {
                    _self.stopDrawing();
                    if (typeof options.callback == 'function') {
                        var secondPoint 
                        = ellipsoid.cartesianToCartographic(cartesian);
                        var value = getExtent(firstPoint, secondPoint);
                        // 左上角
                        value.firstpoint = firstPoint;
                        // 右下角
                        value.secondpoint = secondPoint;
                        options.callback(value);
                    }
                }
            }
        }
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);
    // ... 省略内容
}
  1. 报错后,被注释的代码

    修改:DrawHelper.js

// 注释了 if 判断
// disable edit if pickedobject is different or not an object
//if (!(pickedObject && !pickedObject.isDestroyed() && pickedObject.primitive)) {
    extent.setEditMode(false);
//}

8.计算两个坐标之间的距离

/**
 * 使用cesium api计算两点之间的距离
 * @param slon 开始经度
 * @param slat 开始纬度
 * @param elon 结束经度
 * @param elat 结束纬度
 * */
function distanceBetweenTwoPoint(slon, slat, elon, elat){
    var sCartographic = Cesium.Cartographic.fromDegrees(slon, slat);
    var eCartographic = Cesium.Cartographic.fromDegrees(elon, elat);
    var geodesic = new Cesium.EllipsoidGeodesic();
    geodesic.setEndPoints(sCartographic, eCartographic);
    return geodesic.surfaceDistance;
}

9.添加点集合

/**
 * 创建等高点
 * @param datas 数据列表 
 *        .e.g: [{"lon": 112, "lat": 22}, {"lon": 113, "lat": 23}]
 * @param color 颜色 .e.g: Cesium.Color.RED
 * @param height 高度
 * */
function createContourPoiGeometry(datas, color, height){
    var poiCollection = new Cesium.PointPrimitiveCollection();
    for(var i=0; i<datas.length; i++){
        poiCollection.add({
            position: Cesium.Cartesian3
            			.fromDegrees(datas[i].lon, datas[i].lat, height),
            color: color
        });
    }
    return poiCollection;
};

/**
 * 添加指定的几何图形
 * @param primitive 几何图形集合 .e.g: Cesium.PointPrimitiveCollection()
 * */
function addGeometry(primitive) {
    cesiumViewer.scene.primitives.add(primitive);
}
  • 调用示例
var primitive = createContourPoiGeometry(datas, color, height);
addGeometry(primitive);

10.Primitive加载Geometry

  • BoxGeometry
  • PolygonGeometry(创建 GeometryInstance 时,不需要创建 ModelMatrix)
/**
 * 创建 BoxGeometry
 * @param length 长度
 * @param width 宽度
 * @param height 高度
 * */
function createGeometry(length, width, height){
    return Cesium.BoxGeometry.fromDimensions({
        vertexFormat : Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
        dimensions : new Cesium.Cartesian3(length, width, height)
    });
};

/**
 * 创建 PolygonGeometry
 * @param extent 范围数组 
 *        .e.g: [-120.0, 45.0, -80.0, 45.0, -80.0, 55.0, -120.0, 55.0]
 * @param height geometry高度
 * @param groundHeight geometry距离地面的高度
 * */
function createPolygon(extent, height, groundHeight){
    return new Cesium.PolygonGeometry({
        polygonHierarchy: {
            positions: Cesium.Cartesian3.fromDegreesArray(extent)
        },
        vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
        extrudedHeight: height,
        height: groundHeight
    });
};

/**
 * 创建geometryInstance
 * @param lon 经度
 * @param lat 纬度
 * @param groundHeight 距离地面高度
 * @param geometry
 * @param color 颜色
 * @param instanceId geometryInstance的ID
 * */
function createGeometryInstance(lon, lat, groundHeight, geometry, color, instanceId){
    var modelMatrix;
    if(lon == null || lat == null || groundHeight == null){
        modelMatrix = undefined;
    }else{
        var scale = 5000 * 0.3;
        var position 
        = Cesium.Cartesian3.fromDegrees(lon, lat);
        var point3d 
        = new Cesium.Cartesian3(0.0, 0.0, groundHeight);
        var translation 
        = Cesium.Transforms.eastNorthUpToFixedFrame(position);
        var matrix 
        = Cesium.Matrix4.multiplyByTranslation(translation, point3d, new Cesium.Matrix4());
        var modelMatrix 
        = Cesium.Matrix4.multiplyByUniformScale(matrix, scale, new Cesium.Matrix4());
    }
    // 创建 GeometryInstance
    var geoInstance = new Cesium.GeometryInstance({
        id: instanceId,
        geometry: geometry,
        modelMatrix: modelMatrix,
        attributes: {
            color: Cesium.ColorGeometryInstanceAttribute.fromColor(color),
            show: new Cesium.ShowGeometryInstanceAttribute(true)
        }
    });
    return geoInstance;
}

/**
 * 使用GeometryInstances创建Primitive
 * @param instances geometryInstalce集合或单个geometryInstance
 * */
function createPrimitiveWithInstances(instances){
    return new Cesium.Primitive({
        geometryInstances : instances,
        appearance : new Cesium.PerInstanceColorAppearance({
            translucent : true,
            closed : true
        })
    });
}

/**
 * 添加指定的几何图形
 * @param primitive 几何图形集合 .e.g: Cesium.PointPrimitiveCollection()
 * */
function addGeometry(primitive) {
    cesiumViewer.scene.primitives.add(primitive);
}
  • 调用示例
// color
var color = Cesium.Color.RED.withAlpha(0.5);
// boxGeometry
var boxGeometry = createGeometry(length, width, height);
var boxGeoInstance = createGeometryInstance(lon, lat, groundHeight
                                 , boxGeometry, color, instanceId);
var primitive = createPrimitiveWithInstances(boxGeoInstance);
addGeometry(primitive);

// polygonGeometry
var polygonGeometry = createPolygon(extent, height, groundHeight);
var polygonGeoInstance = createGeometryInstance(null, null, null
                                 , polygonGeometry, color, instanceId);
var primitive = createPrimitiveWithInstances(polygonGeoInstance);
addGeometry(primitive);

11.动态设置Geometry显示隐藏

// 保存 primitive
var polygonGeometry = createPolygon(extent, height, groundHeight);
var polygonGeoInstance = createGeometryInstance(null, null, null
                                 , polygonGeometry, color, instanceId);
var primitive = createPrimitiveWithInstances(polygonGeoInstance);

// 动态设置 primitive
// 创建 GeometryInstance 时,需要设置ID,并且 attributes 添加 show 属性
var attributes = primitive.getGeometryInstanceAttributes(instanceId);
// 隐藏
attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(false);
// 显示
attributes.show = Cesium.ShowGeometryInstanceAttribute.toValue(true);
  • 或者
// 隐藏
cesiumViewer.scene.primitives.get(batchNum).getGeometryInstanceAttributes(instanceId).show = Cesium.ShowGeometryInstanceAttribute.toValue(false);

12.控件与数据模型绑定

范围控件与数据模型绑定:https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/?src=Clustering.html

  • 数据绑定和设置监听
/**
 * 追踪数据模型,并且绑定数据到范围控件
 * @param model 数据模型 e.g. : {x: x, y: y}
 * @param widgetId 控件ID
 * */
function setCutToolTrackAndBind(model, widgetId) {
    Cesium.knockout.track(model);
    var toolbarWidget = document.getElementById(widgetId);
    Cesium.knockout.applyBindings(model, toolbarWidget);
};

/**
 * 订阅数据模型中的某个字段,用于监控数据变化和触发响应
 * @param model 数据模型,e.g. : {x: x, y: y}
 * @param name 模型中的字段
 * @param callback 回调函数
 * */
function subscribeParameter(model, name, callback) {
    Cesium.knockout.getObservable(model, name).subscribe(
        function (newValue) {
            callback(name, newValue);
        }
    );
};
  • 重复绑定错误:

Uncaught Error: You cannot apply bindings multiple times to the same element.

  • 解决:取消之前的绑定
/**
 * 取消范围控件数据绑定
 * @param widgetId 控件ID
 * */
function setCutToolUnbind(widgetId) {
    var toolbarWidget = document.getElementById(widgetId);
    Cesium.knockout.cleanNode(toolbarWidget);
};

13.监听事件

支持的事件: https://cesium.com/docs/cesiumjs-ref-doc/ScreenSpaceEventType.html?classFilter=ScreenSpaceEventType

  • 监听鼠标左击事件
// 监听点击事件
var handle = new Cesium.ScreenSpaceEventHandler(cesiumViewer.scene.canvas)
handle.setInputAction((event)=>{
  var pick = this.viewer.scene.pick(event.position);
  // 判断是否选中对象
  if(pick && pick.id){
    console.log("pick.id",pick.id)
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)

三、其它

1.获取当前JS的路径

/**
 * 根据js文件名,获取页面script标签的地址
 * @param jsFileName js文件名
 * @param isDir true=返回当前目录路径,false=返回完整路径
 * */
function getScriptPathByName(jsFileName, isDir) {
    var allJsNames = document.scripts;
    var path = "";
    // 循环判断列表是否存在JS文件
    for(var i=0; i<allJsNames.length; i++){
        var tPath = allJsNames[i].src;
        if(tPath.lastIndexOf(jsFileName) != -1){
            path = tPath;
            break;
        }
    };
    // 判断是否获取完整路径,还是文件夹路径
    if(isDir){
        var tIdex = path.lastIndexOf(jsFileName);
        return path.substring(0, tIdex);
    }else{
        return path;
    }
}

// 调用
getScriptPathByName('当前js文件名', true);

2.JQuery AJAX获取数据

/**
 * 获取数据
 * @param url 数据链接
 * @param params 参数 e.g. {“x”: x, “y”: y}
 * @param callback 回调函数
 * */
function getDataToJSON(url, params, callback) {
    $.ajax({
        url: url,
        type: "GET",
        async: true,
        data: params,
        datatype: "json",
        success: function (data) {
            // console.log(data);
            callback(data);
        }
    });
};

3.JS代码封装

参考:https://segmentfault.com/a/1190000015843072

  • 随便写的示例:构造函数+原型模式

Person.js

function Person(name, age){
    this.name = name;
    this.age = age;
};
Person.prototype = {
    // 构造函数
    constructor: Person,
    // 属性-国籍
    nationality: "China",
    // 属性-PC
    pc: null,
    // 测试函数
    testFun: function () {
        console.log("name="+this.name+" ; age="+this.age+" ; no this.name="+name
            +" ; nationality="+this.nationality);
    },
    // 改变属性值函数
    changePrototype: function () {
        this.name = "zcheng";
        this.age = "12";
        this.nationality = "zzzzzZ";
    },
    // 测试初始化函数
    testInit: function (num) {
        console.log("num="+num);
        this.pc = new PC("007", "aka-007");
    }
};

PC.js

function PC(num, name) {
    this.num = num;
    this.name = name;
};
PC.prototype = {
    cpu: "i7-4444",
    getCPU: function () {
        console.log("CPU=" + this.cpu);
    },
    getInfo: function () {
        console.log("num=" + this.num + " ;name=" + this.name);
    }
};

test.html


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Testtitle>
    <script type="text/javascript" src="/scalar/Person.js">script>
    <script type="text/javascript" src="/scalar/PC.js">script>
head>
<body>

body>
<script>
    var p = new Person("test", "123");
    p.changePrototype();
    p.testFun();
    p.testInit(123123123);
    console.log(p.nationality);
    p.pc.getCPU();
    p.pc.getInfo();
script>
html>

4.插值算法

  • 克里金插值算法

https://github.com/oeo4b/kriging.js

  • 示例代码
/**
 * 创建 N*N 的点阵,并进行插值计算
 * @param points 点值数据; e.g. [{{"lon":112.19,"lat":23.99,"val":10}}]
 * @param matrixNum 点阵长宽数量
 */
function createDotMatrix(points, matrixNum){
	// 将数据分离
	var lons = [];
	var lats = [];
	var vals = [];
	for(var i=0; i<points.length; i++){
		lons[i] = points[i]["lon"];
		lats[i] = points[i]["lat"];
		vals[i] = points[i]["val"];
	}
	// 计算经纬度最大值和最小值
	var maxLon = lons.max();
	var minLon = lons.min();
	var maxLat = lats.max();
	var minLat = lats.min();
	// 根据点阵长宽数量,切分经纬度
	var distLon = (maxLon - minLon) / matrixNum;
	var distLat = (maxLat - minLat) / matrixNum;
	// 循环计算点位置和插值计算
	var tempLon = minLon;
	for(var i=0; i<matrixNum; i++){
		// 插值经度
		tempLon = tempLon + distLon;
		var tempLat = minLat;
		for(var j=0; j<matrixNum; j++){
			// 插值纬度
			tempLat = tempLat + distLat;
			var kval = getKrigingPredict(vals, lons, lats, tempLon, tempLat);
			console.log(tempLon+","+tempLat+","+kval);
		}
	}
}

/**
 * 使用kriging算法,进行值的预测
 * @param allValue 已知经纬度对应的值
 * @param allLon 已知数据的所有经度
 * @param allLat 已知数据的所有纬度
 * @param predictLon 需要预测值的经度
 * @param predictLat 需要预测值的纬度
*/
function getKrigingPredict(allValue, allLon, allLat, predictLon, predictLat){
	var model = "exponential";
	var sigma2 = 0;
	var alpha = 100;
    var variogram = kriging.train(allValue, allLon, allLat, model, sigma2, alpha);
    return kriging.predict(predictLon, predictLat, variogram);
};
  • 调用示例
//点数据
var points = [{"lon":116.195,"lat":39.997011,"val":10}
	,{"lon":116.325218,"lat":39.949238,"val":50}
	,{"lon":116.215122,"lat":39.983081,"val":150}
	,{"lon":116.25709,"lat":39.983965,"val":86}
	,{"lon":116.314294,"lat":39.990378,"val":200}];
var matrixNum = 30; //点阵长宽数量
createDotMatrix(points, matrixNum);
  • 计算最大值和最小值(kriging.js 已有该计算方法)
Array.prototype.max = function() {
    return Math.max.apply(null, this);
};
Array.prototype.min = function() {
    return Math.min.apply(null, this);
};

你可能感兴趣的:(Cesium)