Cesium 初始化一个三维场景
提示
确定node_modules中安装的 Cesium 版本,太新的版本可能有破坏性改变,暂时推荐安装1.93以及之前版本
完整代码,直接复制到html文件中,在浏览器打开即可查看效果。这里的代码可以当作模板使用
code/Cesium初始化一个三维场景.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Lebarba - WebGL Volume Rendering made easy</title>
<style>
body {
margin: 0;
}
body,
#map-container {
width: 100vw;
height: 100vh;
}
</style>
<script src="https://cesium.com/downloads/cesiumjs/releases/1.93/Build/Cesium/Cesium.js"></script>
<link
href="https://cesium.com/downloads/cesiumjs/releases/1.93/Build/Cesium/Widgets/widgets.css"
rel="stylesheet"
/>
</head>
<body>
<div id="map-container"></div>
<script type="module">
const viewer = new Cesium.Viewer("map-container", {
// 设置为 [] 以便去除 401 (Unauthorized) 控制台报错
imageryProviderViewModels: [],
// 旧版本cesium添加图层
imageryProvider: new Cesium.TileMapServiceImageryProvider({
url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
}),
});
</script>
</body>
</html>
效果如下:
Cesium.Viewer常见属性说明
const viewer = new Cesium.Viewer("cesiumContainer", {
projectionPicker: false,
// terrainExaggeration: 5, //地形夸张
// shouldAnimate: true,
// requestRenderMode : true, // true 启用请求渲染模式,更新实体需拖动地图,视图才会更新
// maximumRenderTimeChange: Infinity,
// sceneMode: Cesium.SceneMode.SCENE3D,//初始场景模式 为2.5维
// sceneModePicker:false, // 隐藏二三维转换
// baseLayerPicker:false, // 隐藏图层选择控件
// terrainProvider: new Cesium.EllipsoidTerrainProvider({}),
// 可供BaseLayerPicker选择的图像图层ProviderViewModel数组
// imageryProviderViewModels,
// mapProjection: new Cesium.WebMercatorProjection(),
// 当前图像图层的显示模型,仅baseLayerPicker设为true有意义
// selectedImageryProviderViewModel: imageryProviderViewModels[0],
animation: false, // 隐藏时钟(值为false是隐藏,这里需要用到,不能隐藏,所以使用js隐藏它)
baseLayerPicker: false,
fullscreenButton: false, // 隐藏全屏
geocoder: false, // 隐藏搜索
homeButton: false, // 隐藏主页
infoBox: false, // 隐藏点击 entity 信息框
sceneModePicker: false,
selectionIndicator: false, // 隐藏点击 entity 绿框
timeline: false, // 隐藏时间轴
scene3DOnly: false,
navigationHelpButton: false, // 隐藏帮助按钮
vrButton: false, // 隐藏双屏模式
shouldAnimate: true,
// 影像地图
imageryProvider: null,
}
Cesium.Viewer内置地图
加载内置地图,在初始化时,可以加载默认的内置图层,效果一般,但是方便
code/Cesium加载内置地图.html
<body>
<div id="map-container"></div>
<script type="module">
const viewer = new Cesium.Viewer("map-container", {
// 设置为 [] 以便去除 401 (Unauthorized) 控制台报错
imageryProviderViewModels: [],
// 旧版本cesium添加图层
imageryProvider: new Cesium.TileMapServiceImageryProvider({
url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
}),
});
</script>
</body>
Cesium 加载各种外置地图
加载天地图
提示
需要先去天地图官网申请token。官网地址
code/Cesium加载天地图外置地图.html
<body>
<div id="map-container"></div>
<script type="module">
const tdtUrl = 'https://t{s}.tianditu.gov.cn/'
// 记得换为自己的token,可以先去天地图官网申请,
const token = 'f49da160453153xxxxxxxxxxxxxxxxxxxxx'
const subdomains = [ '7', '6', '5', '4', '3', '2', '1', '0', ]
// 影像地图-球面墨卡托投影
let img_w = new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}img_w/wmts?tk=${token}`,
}),
layer: 'img',
format: 'tiles',
style: 'default',
tileMatrixSetID: 'w',
subdomains,
maximumLevel: 18,
})
// 影像注记-球面墨卡托投影
let cia_w = new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}cia_w/wmts?tk=${token}`,
}),
layer: 'cia',
format: 'tiles',
style: 'default',
tileMatrixSetID: 'w',
subdomains,
maximumLevel: 18,
})
// 地形注记-球面墨卡托投影
let ter_w = new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}ter_w/wmts?tk=${token}`,
}),
layer: 'ter',
format: 'tiles',
style: 'default',
tileMatrixSetID: 'w',
subdomains,
maximumLevel: 18,
})
// 地形注记-球面墨卡托投影
let cta_w = new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}cta_w/wmts?tk=${token}`,
}),
layer: 'cta',
format: 'tiles',
style: 'default',
tileMatrixSetID: 'w',
subdomains,
maximumLevel: 18,
})
// 矢量注记-球面墨卡托投影
let vec_w = new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}vec_w/wmts?tk=${token}`,
}),
layer: 'vec',
format: 'tiles',
style: 'default',
tileMatrixSetID: 'w',
subdomains,
maximumLevel: 18,
})
// 矢量注记-球面墨卡托投影
let cva_w = new Cesium.WebMapTileServiceImageryProvider({
url: new Cesium.Resource({
url: `${tdtUrl}cva_w/wmts?tk=${token}`,
}),
layer: 'cva',
format: 'tiles',
style: 'default',
tileMatrixSetID: 'w',
subdomains,
maximumLevel: 18,
})
const viewer = new Cesium.Viewer("map-container", {
// 设置为 [] 以便去除 401 (Unauthorized) 控制台报错
imageryProviderViewModels: [],
// 旧版本cesium添加图层
// imageryProvider: img_w,
});
// 影像图
viewer.imageryLayers.addImageryProvider(img_w);
viewer.imageryLayers.addImageryProvider(cia_w);
// // 地形图
// viewer.imageryLayers.addImageryProvider(ter_w);
// viewer.imageryLayers.addImageryProvider(cta_w);
// // 矢量图
// viewer.imageryLayers.addImageryProvider(vec_w);
// viewer.imageryLayers.addImageryProvider(cva_w);
</script>
</body>
加载 arcgisonline 地图
code/Cesium加载arcgisonline外置地图.html
<body>
<div id="map-container"></div>
<script type="module">
let viewer = new Cesium.Viewer("map-container", {
// 设置为 [] 以便去除 401 (Unauthorized) 控制台报错
imageryProviderViewModels: [],
// 旧版本cesium添加图层
imageryProvider: new Cesium.UrlTemplateImageryProvider({
url: "https://services.arcgisonline.com/arcgis/rest/services/Elevation/World_Hillshade/MapServer/tile/{z}/{y}/{x}",
})
});
</script>
</body>
加载离线地图
<body>
<div id="map-container"></div>
<script type="module">
const viewer = new Cesium.Viewer("map-container", {
// 设置为 [] 以便去除 401 (Unauthorized) 控制台报错
imageryProviderViewModels: [],
// 旧版本cesium添加图层
imageryProvider: new Cesium.UrlTemplateImageryProvider({
// 使用地图瓦片下载器下载离线的地图瓦片,用nginx做代理,注意图片后缀 png/jpg
url: "http://localhost:8082/satellite/{z}/{x}/{y}.jpg"
}),
});
</script>
</body>
离线地图对应的nginx配置
location /satellite {
# add_header Access-Control-Allow-Origin "*";
# add_header 'Access-Control-Allow-Origin' *;
#允许带上cookie请求
# add_header 'Access-Control-Allow-Credentials' 'true';
#允许请求的方法,比如 GET/POST/PUT/DELETE
# add_header 'Access-Control-Allow-Methods' *;
#允许请求的header
add_header 'Access-Control-Allow-Origin' "$http_origin" always;
add_header 'Access-Control-Allow-Credentials' 'true' always;
add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS' always;
add_header 'Access-Control-Allow-Headers' 'Accept,Authorization,Cache-Control,Content-Type,DNT,If-Modified- Since,Keep-Alive,Origin,User-Agent,X-Requested-With' always;
add_header 'Access-Control-Allow-Headers' *;
alias D:\\software\\study\\satellite;
}
加载单张图片到地图上指定四至位置
import * as Cesium from 'cesium';
/**
* 图片图层
* @param {string} url 底图对应的类型
* @param {[number, number, number, number]} extent 四至[最小经度, 最小纬度, 最大经度, 最大纬度]
*/
export default class ImageLayer extends Cesium.SingleTileImageryProvider {
constructor(url, extent, callback) {
const rectangle = Cesium.Rectangle.fromDegrees(...extent);
super({
url,
rectangle,
});
this.readyPromise.then(() => {
const image = new Image();
image.src = url;
image.onload = (): void => callback && callback();
});
}
}
import ImageLayer from './ImageLayer';
/**
* 添加图片图层
* @param {string} url 图片路径
* @param {[number, number, number, number]} extent 四至[最小经度, 最小纬度, 最大经度, 最大纬度]
* @param {any | undefined} callback 数据ImageryLayer
* @returns {any} 添加图片图层
*/
addImageLayer(url, extent, callback) {
const imageLayer = new ImageLayer(url, extent, callback);
const imageryLayer = viewer.imageryLayers.addImageryProvider(imageLayer);
return imageryLayer;
}
...
// 在组件中调用-参数:图片地址、图片要加载到的四至、回调函数
const tempLayer = viewer.addImageLayer(`${ipPath}`,[72, 17, 136, 55],() => {
viewer.imageryLayers.remove(temp);
},
);
加载加载地质图
全国地质资料馆-首页
全国地质资料馆网-1:50万地质图
全国地质资料馆网-文档
加载下图服务到Cesuim中
地址:http://www.ngac.org.cn/Map/Document?guid=EC7E1A7A76901954E0430100007F182E
loadPic() {
// 添加ArcGIS WMTS服务
var provider = new Cesium.WebMapTileServiceImageryProvider({
// url: 'http://www.ngac.org.cn/igserver/ogc/kvp/TAS10B520000SN/WMTSServer/1.0.0/TAS10B520000SN/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png', // 复制 2.5 中的地址
url: 'http://219.142.81.86:80/igs/rest/ogc/TAS10B520000SN/WMTSServer/1.0.0/TAS10B520000SN/{Style}/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}.png', // 复制 2.5 中的地址
layer: 'TAS10B520000SN',
style: 'default',
tileMatrixSetID: 'EPSG:4326_TAS10B520000SN_dpi96_GB',
format: 'image/png',
tilingScheme: new Cesium.GeographicTilingScheme(),
maximumLevel: 21,
// tileMatrixLabels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21'] // 对应2.4中的tileMatrix Identifier属性
tileMatrixLabels: ['0','1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21']
});
// 添加服务图层到视图中
viewer.imageryLayers.addImageryProvider(provider);
}
地质图解读:暂不显示
Cesium 加载WMS服务
imageryProvider: new Cesium.WebMapServiceImageryProvider({
url: 'http://192.168.132.10:8080/geoserver/mapStudy/wms', // EPSG:4326
// layers: 'mapStudy:CHN_sheng_Color', // EPSG:4326
layers: 'mapStudy:chinaCityColorShp100%', // EPSG:4326
// url: 'http://192.168.132.10:8080/geoserver/maps/wms', // EPSG:3857
// layers: 'maps:chinaTestMapColor', // EPSG:3857
parameters : {
transparent : true, //是否透明.false的话,会导致其余地方,地图全白
format : 'image/png',
attribution: "myattribution", // 不要也行?
version: '1.1.0',
srs:'EPSG:4326',
service: 'WMS',
request: 'GetMap',
style: 'default',
// styles: '' 应该是没有 style参数,有styles参数 ,其值为 ''
}
})
提示
当使用全能电子地图下载器下载完tif数据后,在【存储仓库】【添加新的存储仓库】【 GeoTIFF 】 ,添加栅格数据源后,发现下载的tif是EPSG:3857的,不管是3857还是4326 ,都使用自身的坐标系去发布,发布完成后,使用cesium加载EPSG:3857的tif时,在代码的参数中把srs指定成4326或4490也能正常加载。如图:
下图代码中this指代viewer
提示
如果tif本身是4326的,直接发布,然后使用下面代码加载,也是正常加载(4326可能需要投影相关文件)。 没有投影文件报错解决:参考文章
注意url就是下图这里的
url就是使用openlayers 预览时的url 如果加载后有黑边如下
则参考这篇文章,设置
Cesium 加载倾斜摄影(并调节高度)
import * as Cesium from 'cesium';
// 加载模型(别墅)
iniModelRED(viewer) {
const tilesets = new Cesium.Cesium3DTileset({
// url: 'http://localhost:8082/red/',
// url: './gltf/red/tileset.json',
url: 'http://172.20.254.160:8064/tileset.json',
skipLevelOfDetail: true,
preferLeaves: true,
maximumScreenSpaceError: 2, //最大的屏幕空间误差
maximumNumberOfLoadedTiles: 1000 //最大加载瓦片个数
});
//调节高度
tilesets.readyPromise.then((tileset) => {
viewer.scene.primitives.add(tileset);
viewer.zoomTo(tileset);
// 将3d tiles离地高度降低 12 米
let cartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
let surface = Cesium.Cartesian3.fromRadians(cartographic.longitude,cartographic.latitude,0.0);
let offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, -12);
let translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
// viewer.scene.globe.depthTestAgainstTerrain = true
})
},
拾取的模型经纬度位置
import * as Cesium from 'cesium';
// 初始化左击事件
getModelInfoByClick(viewer) {
const eventHandlerArr = []
const eventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
eventHandler.setInputAction((click) => {
const pick = viewer.scene.pick(click.position);
const cartesian3 = viewer.scene.pickPosition(click.position);
console.log('拾取的坐标,', cartesian3)
console.log('拾取的模型,', pick)
const ellipsoid = viewer.scene.globe.ellipsoid;
const cartographic = ellipsoid.cartesianToCartographic(cartesian3);
const lng = Cesium.Math.toDegrees(cartographic.longitude);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
const height = cartographic.height;
console.log('拾取的模型经纬度位置:', lng, lat, height)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
eventHandlerArr.push(eventHandler);
}
Cesium 中启用点击事件,如图标点击事件(有多种点击事件,这里先写一种)TODO
import * as Cesium from 'cesium';
// 加载相机点击事件并获取相机图标对应的属性
addClickEvent() {
const eventHandler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
eventHandler.setInputAction((click) => {
const pick = viewer.scene.pick(click.position);
//选中某实体,pick选中的对象
if (pick && pick.id && pick.id._name === "xxxxxxLayerName") {
const {properties,} = pick.id
const temp = {};
Object.keys(properties).forEach((key) => {
const k = key.split('_')[1];
if (properties[k] && (properties[k]._value !== null || properties[k]._value !== '')) {
temp[k] = properties[k]._value;
}
});
// 获取相机图标点击返回的数据
console.log('获取相机图标点击返回的数据: ', temp);
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
eventHandlerArr.push(eventHandler);
},
移除对应的点击事件
$$ // 移除所有点击事件 removeClickEvent() { eventHandlerArr.forEach((item) => { if (!item.isDestroyed()) { item.destroy(); } }); }, $$
Cesium 常用功能罗列
添加地形
/**
* 添加地形
* @returns {void}
*/
addTerrain () {
const terrainProvider = new Cesium.CesiumTerrainProvider({
// url: 'http://localhost:9000/terrain/f60385cadasdasdasda9ac6faf',
url: 'http://112.190.54.204:8089/ganyuProcessed',
});
viewer.terrainProvider = terrainProvider;
}
/**
* 移除地形
* @returns {void}
*/
removeTerrain () {
viewer.terrainProvider = new Cesium.EllipsoidTerrainProvider({});
}
全球视角
/**
* 全球视角
* @param {boolean} value 标志符
* @returns {void}
*/
goHome (value) {
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(20, -40, 180.0, 80),
});
}
放大&缩小
/**
* 放大
* @returns {void}
*/
zoomIn () {
const { height, longitude, latitude, } = viewer.camera.positionCartographic;
if (height > 300000) {
viewer.camera.zoomIn(300000);
} else if (height > 1100 && height <= 300000) {
viewer.camera.zoomIn(height / 2);
} else {
// viewer.camera.zoomIn(height - 1);
viewer.flyto([
Cesium.Math.toDegrees(longitude),
Cesium.Math.toDegrees(latitude),
1100,
], 1);
}
}
/**
* 缩小
* @returns {void}
*/
zoomOut () {
const { height, } = viewer.camera.positionCartographic;
if (height < 15772269) {
viewer.camera.zoomOut(300000);
}
}
动画至视角
/**
* 动画至视角
* @param {[number, number, number]} position 视角位置[经度, 纬度, 高度]
* @param {number} duration 时间
* @returns {void}
*/
flyto (position, duration = 0) {
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(...position),
duration,
});
}
复位
/**
* 复位
* @param {number} duration 复位所需时间
* @returns {void}
*/
reset (original, duration = 1) {
// original --> 0:115.11 1:26.11 2:117.22 3:28.22
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(...original),
duration,
});
}
二三维切换
/**
* 二三维切换
* @returns {void}
*/
switchDimensional () {
viewer.scene.mode = 5 - viewer.scene.mode;
}
图层切换
/**
* 图层切换-这种切换方式需要在初始化Viewer时指定imageryProviderViewModels和selectedImageryProviderViewModel
* @param {string} mapType 图层类型
* @returns {void}
*/
switchMap (mapType) {
viewer.baseLayerPicker.viewModel.selectedImagery = imageryProviderViewModels[Object.keys(layers).indexOf(mapType)];
}
定位视角
/**
* 定位视角
* @param {[number, number, number]} position 视角位置[经度, 纬度, 高度]
* @returns {void}
*/
setView (position) {
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(...position),
});
}
测量面积
/**
* 测量面积
* @return {void}
*/
measureArea () {
viewer.measure.drawAreaMeasureGraphics({
width: 3,
clampToGround: true,
});
}
计算两点之间的距离
/**
* 计算两点之间的距离
* @returns {void}
*/
getDistance (positionStart, positionEnd) {
const satrt = Cesium.Cartographic.fromDegrees(positionStart[0], positionStart[1]);
const end = Cesium.Cartographic.fromDegrees(positionEnd[0], positionEnd[1]);
// 计算两点之间的距离
const geodesic = new Cesium.EllipsoidGeodesic();
geodesic.setEndPoints(satrt, end);
let s = geodesic.surfaceDistance;
s = Math.sqrt(s ** 2 + (satrt.height - end.height) ** 2);
return s || viewer;
}
获取屏幕坐标
/**
* 获取屏幕坐标
* @param {any} longitude 经度
* @param {any} latitude 纬度
* @param {any} height 高度
* @returns {any} 屏幕坐标
*/
toScreen = (longitude, latitude, height = 0) => {
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
return Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, position);
}
屏幕坐标转经纬度
/**
* 屏幕坐标转经纬度
* @param {any | undefined} event 屏幕坐标
* @returns {number[]} 经纬度
*/
toLonLat = (event) => {
const { ellipsoid, } = viewer.scene.globe;
const cartesian = viewer.camera.pickEllipsoid(event.position, ellipsoid);
if (cartesian) {
// 将笛卡尔坐标转换为地理坐标
const cartographic = ellipsoid.cartesianToCartographic(cartesian);
// 将弧度转为度的十进制度表示
const lon = Cesium.Math.toDegrees(cartographic.longitude);
const lat = Cesium.Math.toDegrees(cartographic.latitude);
return [lon, lat,];
}
}
坐标是否在屏幕内
/**
* 坐标是否在屏幕内
* @param {any} longitude 经度
* @param {any} latitude 纬度
* @param {any} height 高度
* @returns {any} 是否在屏幕内
*/
screenContains = (longitude, latitude, height = 0) => {
const position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
const viewRectangle = viewer.camera.computeViewRectangle();
if (viewRectangle) {
return Cesium.Rectangle.contains(
viewRectangle,
Cesium.Cartographic.fromCartesian(position)
);
}
return false;
}
获取鼠标坐标,一般用来显示鼠标的位置
/**
* 获取鼠标坐标
* @param {any} calback 回调函数
* @returns {void}
*/
getLocation = (calback) => {
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
let cartesian = null;
let latitudeString = null;
let longitudeString = null;
handler.setInputAction((movement) => {
// 得到当前三维场景的椭球体
const { ellipsoid, } = viewer.scene.globe;
cartesian = viewer.camera.pickEllipsoid(movement.endPosition, ellipsoid);
if (cartesian) {
// 将笛卡尔坐标转换为地理坐标
const cartographic = ellipsoid.cartesianToCartographic(cartesian);
// 将弧度转为度的十进制度表示
longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
return calback && calback(longitudeString, latitudeString);
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
组件中调用
mapViewer.getLocation((lon, lat) => {
mouseLongitude.value = lon.toFixed(6);
mouseLatitude.value = lat.toFixed(6);
});