learning_cesium/湖北流域.html

426 lines
18 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!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>