426 lines
18 KiB
HTML
426 lines
18 KiB
HTML
<!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>
|