learning_cesium/湖北流域.html

426 lines
18 KiB
HTML
Raw Normal View History

2024-03-19 18:06:25 +08:00
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8" />
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta
name="viewport"
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
/>
<title>Learning Cesium!</title>
<script src="./Build/Cesium/Cesium.js"></script>
<style>
@import url(./Build/Cesium/Widgets/widgets.css);
html,
body,
#app,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.fly-path-box{
position: absolute;
top: 100px;
left: 80px;
}
</style>
<!-- 引入样式 -->
<link rel="stylesheet" href="./js/elementui/index.css" />
<!-- import Vue before Element -->
<script src="./js/vue2710.js"></script>
<!-- import JavaScript -->
<script src="./js/elementui/index.js"></script>
</head>
<body>
<div id="app">
<div id="cesiumContainer"></div>
<div class="fly-path-box">
<el-row>
<el-button @click="flyPath">开始</el-button>
<el-button @click="pauseFly" type="primary">暂停</el-button>
<!-- <el-button type="success">成功按钮</el-button>
<el-button type="info">信息按钮</el-button>
<el-button type="warning">警告按钮</el-button>
<el-button type="danger">危险按钮</el-button> -->
</el-row>
</div>
</div>
<script type="module">
import viewUtil from "./js/utils/viewUtil.js";
import {getRiverLevel1,getRiverLevel2,getHanjiangFeature} from "/js/api/hubei.js"
import {
cesiumToken,
geoserverConfig,
geoqConfig,
} from "./js/mapConfig.js";
Cesium.Ion.defaultAccessToken = cesiumToken;
let flyHeight = 13177;
new Vue({
el: "#app",
data: {
regions:[
{ name:"长江干流流域",level:"一级流域",coord:[114.721069,30.855776]},
{ name:"汉江流域",level:"一级流域",coord:[111.319383,32.038113]},
{ name:"清江流域",level:"一级流域",coord:[109.483509,30.107393]},
{ name:"乌江片区",level:"二级流域",coord:[108.870317,29.909681]},
{ name:"清江片区",level:"二级流域",coord:[110.050511,29.912557]},
{ name:"沅江片区",level:"二级流域",coord:[110.210396,30.451736]},
{ name:"三峡库区",level:"二级流域",coord:[110.548268,31.133949]},
{ name:"黄柏河片区",level:"二级流域",coord:[111.337632,30.918915]},
{ name:"荆南四河片区",level:"二级流域",coord:[111.927106,30.038710]},
{ name:"沮漳河片区",level:"二级流域",coord:[111.835033,31.079421]},
{ name:"四湖片区",level:"二级流域",coord:[112.833908,30.004803]},
{ name:"鄂东南片区",level:"二级流域",coord:[114.246797,29.964106]},
{ name:"富水片区",level:"二级流域",coord:[114.794233,29.674242]},
{ name:"鄂东五河片区",level:"二级流域",coord:[115.316260,30.830389]},
{ name:"府澴河片区",level:"二级流域",coord:[113.740907,31.576125]},
{ name:"汉江下游片区",level:"二级流域",coord:[113.321659,30.668325]},
{ name:"唐白河片区",level:"二级流域",coord:[112.329638,32.207771]},
{ name:"汉江中游片区",level:"二级流域",coord:[111.721511,31.839883]},
{ name:"汉江丹库以上片区",level:"二级流域",coord:[110.071016,32.370220]},
],
level1Color:"rgba(65, 110, 255, 0.5)",
level2Color:"rgba(44, 239, 243, 0.5)",
path:[
[106.506124,33.116968,flyHeight],//发源地
[109.852000,33.070824,flyHeight],
[110.615992,32.828365,flyHeight],
[111.069476,32.622887,flyHeight],//中游
[111.710542,32.231320,flyHeight],
[112.143726,31.848392,flyHeight],
[112.447286,31.399614,flyHeight],
[112.565470,31.005892,flyHeight],
[112.825239,30.784890,flyHeight],
[113.651361,30.865274,flyHeight],
[114.282617,30.568286,flyHeight],// 入江口
]
},
computed:{
regionLevel1: function () {
return this.regions.filter(region=>region.level == "一级流域")
},
regionLevel2: function () {
return this.regions.filter(region=>region.level == "二级流域")
},
},
methods: {
initViewer() {
var viewer = new Cesium.Viewer("cesiumContainer", {
geocoder: false, //位置查找
homeButton: false, //视图返回初始位置
sceneModePicker: false, //视角选择器
baseLayerPicker:false,//底图选择器
navigationHelpButton: false, //导航帮助按钮
animation: false, //动画控制器
creditContainer:document.createElement("div"),//版权显示
timeline: true, //时间线
fullscreenButton: false, //全屏控件
vrButton: false,
infoBox: false,
selectionIndicator: false,
terrainProvider: Cesium.createWorldTerrain({
requestVertexNormal: true, //添加地形光照
requestWaterMask: true, //添加水面波浪效果
}),
});
window.viewer = viewer;
this._viewer = viewer;
let imageryLayers = viewer.imageryLayers;
imageryLayers.removeAll();
viewUtil.addGeoVisImagerLayer(viewer,"yingxiang");
// 将三维球定位到汉江
viewer.camera.flyTo({
destination: new Cesium.Cartesian3(
-2568409.0296040955, 6087054.075714171, 3869940.8638977357
),
orientation: {
heading: 0.1017466880023612,
pitch: -1.5281789831506378,
roll: 0,
},
});
this.initEvent(viewer);
// 创建自定义数据源
this.level1DataSource = new Cesium.CustomDataSource("level1");
viewer.dataSources.add(this.level1DataSource);
// 创建自定义数据源
this.level2DataSource = new Cesium.CustomDataSource("level2");
viewer.dataSources.add(this.level2DataSource);
// 用于存储汉江图元的集合
this.riverPrimitives = viewer.scene.primitives.add(new Cesium.PrimitiveCollection());
this.drawShap();
// 创建轨迹实体数据源
window.pathSource = new Cesium.CustomDataSource("pathSource");
viewer.dataSources.add(window.pathSource);
},
async drawShap(){
// 添加一级、二级流域面和注记
let level1 = await getRiverLevel1();
level1.features.forEach(feature=>{
feature.properties.layerName = "riverLevel";
feature.properties.selectedColor = this.level1Color;
viewUtil.createOutlinePolygon(this.level1DataSource,feature,"rgba(255,255,255,0)","rgba(255,255,255)",2,true)
})
let level2 = await getRiverLevel2();
level2.features.forEach(feature=>{
feature.properties.layerName = "riverLevel";
feature.properties.selectedColor = this.level2Color;
viewUtil.createOutlinePolygon(this.level2DataSource,feature,"rgba(255,255,255,0)","#2CEFF3",2,true)
})
this.addPoiData(this.level1DataSource,this.regionLevel1);
this.addPoiData(this.level2DataSource,this.regionLevel2);
this.level2DataSource.show = false;//默认显示一级
// 添加汉江水面动态效果
let hanjiang = await getHanjiangFeature();
hanjiang.features.forEach(feature=>{
viewUtil.addWaterFeature(this.riverPrimitives,feature)
})
},
initEvent(viewer){
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction((evt) => {
//捕获椭球体,将笛卡尔二维平面坐标转为椭球体的笛卡尔三维坐标,返回球体表面的点
var cartesian3 = viewer.camera.pickEllipsoid(evt.position);
// let cartesian3 = viewer.scene.pickPosition(evt.position);
if (cartesian3) {
//将笛卡尔三维坐标转为地图坐标(弧度)
var cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesian3);
//将地图坐标(弧度)转为十进制的度数
var lat_String = Cesium.Math.toDegrees(cartographic.latitude).toFixed(6);
var log_String = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
var alti_String = (viewer.camera.positionCartographic.height / 1000).toFixed(2);
console.log(log_String+","+lat_String)
}
var picks = viewer.scene.drillPick(evt.position);
console.log(picks)
if(picks.length){
picks.forEach(item=>{
let attr = JSON.parse(item.id.id);
if(attr.layerName == "riverLevel"){
item.id.polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString(attr.selectedColor)) ;
if(this.selectedEntity ){
this.selectedEntity.polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString("rgba(0,0,0,0)")) ;
}
this.selectedEntity = item.id;
}
})
}else{
if(this.selectedEntity ){
this.selectedEntity.polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.fromCssColorString("rgba(0,0,0,0)")) ;
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK)
// 监听地图缩放控制实体的显示,另一种方案是使用 DistanceDisplayCondition 参数配置
viewer.scene.camera.moveEnd.addEventListener(()=>{
//获取当前相机高度
let height = Math.ceil(viewer.camera.positionCartographic.height);
console.log('height' + height);
// 获取相机位置的大小
var currentMagnitude = viewer.camera.getMagnitude();
console.log('currentMagnitude' + currentMagnitude);
if(height>1200000){
this.level1DataSource.show = true;
this.level2DataSource.show = false;
}else{
this.level1DataSource.show = false;
this.level2DataSource.show = true;
}
})
},
async createRiverLabel(text){
// 创建画布对象
let canvas = document.createElement("canvas");
let url1 = "/images/hanjiang/river_location.png";
const image = await new Cesium.Resource.fetchImage(url1);
let padding = 8;
let len = text.split("").length;
let ww = 14*len+padding*2;
canvas.width = ww>image.width?ww:image.width;
canvas.height = image.height;
let ctx = canvas.getContext("2d");
ctx.drawImage(image, 0, 0, ww>image.width?ww:image.width, image.height);
ctx.font = 'bold 14px Arial';
ctx.textAlign = 'left';
ctx.textBaseline = 'middle';
ctx.fillStyle = 'rgba(255, 255, 255, 1)';
ctx.fillText(text, ww>image.width?8:(image.width-ww+2*padding)/2, image.height/4);
return canvas;
},
addPoiData(source,data,option){
data.forEach(item=>{
let image = this.createRiverLabel(item.name)
let opt = {
id: JSON.stringify({ ...item, layerName: "poi" }),
position: Cesium.Cartesian3.fromDegrees(item.coord[0], item.coord[1], 0),
billboard: {
eyeOffset: new Cesium.Cartesian3(0.0, 1.0, 0.0),
image:image, // default: undefined
show: true, // default
// pixelOffset:new Cesium.Cartesian2(-60, 0),
// width: 120, // default: undefined
// height: 80, // default: undefined
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// distanceDisplayCondition: new Cesium.DistanceDisplayCondition(
// 10.0,
// 30000.0
// ), //根据到相机的距离确定可见性。
scaleByDistance: new Cesium.NearFarScalar(10, 1, 60000000, 0.0),
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
}
source.entities.add(opt)
})
},
initTimeline(len){
var start = Cesium.JulianDate.fromDate(new Date("2023-2-13"));
var stop = Cesium.JulianDate.addSeconds( start, len, new Cesium.JulianDate() );
this.start = start;
this.stop = stop;
//Make sure viewer is at the desired time.
this._viewer.clock.startTime = start.clone();
this._viewer.clock.stopTime = stop.clone();
this._viewer.clock.currentTime = start.clone();
this._viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
this._viewer.clock.multiplier = 0.1;
//Set timeline to simulation bounds
this._viewer.timeline.zoomTo(start, stop);
this._viewer.clock.shouldAnimate = false
},
flyPath(){
// 设置时间
this.initTimeline(this.path.length - 1);
// 设置坐标的时间,使用 SampledPositionProperty进行插值
let positions = this.getPositionProperty(this.path);
let orientation = new Cesium.VelocityOrientationProperty( positions );
// 创建轨迹实体
let flyEntity = window.pathSource.entities.add({
show: true,
//Set the entity availability to the same interval as the simulation time.
availability: new Cesium.TimeIntervalCollection([
new Cesium.TimeInterval({
start: this.start,
stop: this.stop,
}),
]),
//使用计算的位置
position: positions,
//Automatically compute orientation based on position movement.
orientation: orientation,
//Load the Cesium plane model to represent the entity
model: {
show: false,
uri:"./SampleData/models/CesiumAir/Cesium_Air.glb",
minimumPixelSize: 64,
},
path: {
show:true,
resolution: 1,
material: new Cesium.PolylineGlowMaterialProperty({
glowPower: 0.1,
color: Cesium.Color.YELLOW,
}),
width: 10,
},
});
flyEntity.position.setInterpolationOptions({
interpolationDegree: 5,
interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
});
//监听时间变化,【关键代码】。保存返回值,是一个移除事件的回调函数
this.tickCallBack&&this.tickCallBack();
this.tickCallBack = viewer.clock.onTick.addEventListener( (e)=> {
if (viewer.clock.shouldAnimate === true) {
let ori = orientation.getValue(viewer.clock.currentTime); //获取偏向角
let center = positions.getValue(viewer.clock.currentTime); //获取位置
let transform = Cesium.Matrix4.fromRotationTranslation(
Cesium.Matrix3.fromQuaternion(ori),
center
); //将偏向角转为3*3矩阵利用实时点位转为4*4矩阵
viewer.camera.lookAtTransform(
transform,
new Cesium.Cartesian3(-10, 0, 3)
); //将相机向后面放一点, 第二个参数可以调整相机的姿态 [前后,左右,上下]
}
});
// 修改飞行状态
// path.playing = true;
// 飞行的时候隐藏轨迹相关的实体
window.pathSource.show = false;
this._viewer.trackedEntity = flyEntity;
this._viewer.clock.shouldAnimate = true;
},
getPositionProperty(coords){
// 给轨迹点关联时间和插值
const property = new Cesium.SampledPositionProperty();
for (var i = 0; i < coords.length; i++) {
var time = Cesium.JulianDate.addSeconds( this.start, i, new Cesium.JulianDate() );
var position = Cesium.Cartesian3.fromDegrees( coords[i][0], coords[i][1], coords[i][2] );
property.addSample(time, position);
window.pathSource.entities.add({
position: position,
point: {
color: Cesium.Color.SKYBLUE,
pixelSize: 10,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 3,
disableDepthTestDistance: Number.POSITIVE_INFINITY,
// heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
},
});
}
return property;
},
pauseFly(){
window.pathSource.show = true;
this._viewer.trackedEntity = null;
this._viewer.clock.shouldAnimate = false;
}
},
mounted() {
this.initViewer();
},
});
</script>
</body>
</html>