cesium-二三维联动优化(ol-cesium)
之前已经实现了ol和cesium联动的效果了,但还是有点问题:cesium和ol平面视角联动还算正常的,但是当cesium为三维视角时联动的效果就出现问题。
这里使用ol-cesium来实现完善的联动效果
ol-cesium
介绍
在 2D 和 3D 之间平滑切换并同步:
- 地图上下文(边界框和缩放级别);
- 栅格数据源;
- 2D 和 3D 的矢量数据源;
- 地图选择(选定项目);
- 地图和地球视图之间的动画过渡。
安装
我这里使用的是vue-cli框架
使用npm安装ol-cesium
npm i ol-cesium
使用例子如下:
import OLCesium from 'ol-cesium';
const ol3d = new OLCesium({map: ol2dMap}); // ol2dMap is the ol.Map instance
ol3d.setEnabled(true);
具体的参考demo可以去官网看看
实现效果
ol-cesium二三维联动
我的这个项目并不需要全部的ol-cesium功能,我只需要其中一部分功能:cesium和ol视角联动的效果
最终效果实现的二三维同步效果如下:
这里我对代码进行来修改,提取了部分功能出来
实现代码
项目结构
lib目录中为从ol-cesium中提取出来的代码
核心代码是Camera.js,其它代码为相关依赖,主要就是修改一下相应代码的依赖
主要代码
testOLCs()
使用camera方法
- new olcsCamera(this._viewer.scene, this.map);这里传入cesium的viewer和ol的map,让camera来管理两个地图的视角
- checkCameraChange();开启viewer和map变化的监听
render_()
用于渲染铯场景
requestAnimationFrame()
请求动画帧回调方法
核心方法
testOlCs() {
this.camera_ = new olcsCamera(this._viewer.scene, this.map);
this.camera_.checkCameraChange();
},
/**
* 渲染铯场景
*/
render_() {
// 如果对 `requestAnimationFrame`(请求动画帧) 的调用处于挂起状态,请取消它
if (this.renderId_ !== undefined) {
cancelAnimationFrame(this.renderId_);
this.renderId_ = undefined;
}
this.renderId_ = requestAnimationFrame(this.onAnimationFrame_.bind(this));
},
/**
* Callback for `requestAnimationFrame`. 请求动画帧回调方法
* @param {number} frameTime The frame time, from `performance.now()`.帧时间
* @private
*/
onAnimationFrame_(frameTime) {
this.renderId_ = undefined;
// 检查帧是否在目标帧速率内渲染
const interval = 1000.0 / this.targetFrameRate_;
const delta = frameTime - this.lastFrameTime_;
if (delta < interval) {
// 太早了,还没渲染
this.render_();
return;
}
// 渲染一帧的时间,节省时间
this.lastFrameTime_ = frameTime;
const julianDate = this.time_();
this.scene_.initializeFrame();
this.scene_.render(julianDate);
this.camera_.checkCameraChange();
// 在这个完成后请求下一个渲染调用,以确保浏览器不会得到备份
this.render_();
}
完整代码
<template>
<div class="home">
<cesiumComponent ref="refCesium"/>
<div id="eye"></div>
</div>
</template>
<script>
import cesiumComponent from '../cesium/cesium.vue'
import olcsCamera from './lib/Camera.js';
export default {
name: "olCesium01",
data() {
return {
_viewer: undefined,
scene_: undefined,
view_: undefined,
camera_: null,
targetFrameRate_: Number.POSITIVE_INFINITY,
lastFrameTime_: 0,
time_: function () {
return Cesium.JulianDate.now()
},
layer: {
tiandituVecLayer: '',
tiandituCvaLayer: '',
tiandituImgLayer: '',
tiandituCiaLayer: '',
},
map: '',
};
},
components: {
cesiumComponent
},
mounted() {
this.init();
this.addTiles();
},
methods: {
init() {
let that=this;
this.$refs.refCesium.initMap();
let viewer = this.$refs.refCesium._viewer;
this._viewer = viewer;
that.scene_ = viewer.scene;
//渲染铯场景
that.render_();
this.addOlMap();
this.testOlCs()
},
addOlMap() {
var that = this;
//普通地图
this.layer.tiandituVecLayer = new ol.layer.Tile({
title: 'generalMap',
source: new ol.source.XYZ({
url: 'http://t3.tianditu.com/DataServer?T=vec_w&x={x}&y={y}&l={z}&tk=token',
crossOrigin: 'anonymous'
}),
// zIndex: 1,
visible: true
});
//普通地图标记
that.layer.tiandituCvaLayer = new ol.layer.Tile({
title: 'generalMapZj',
source: new ol.source.XYZ({
url: 'http://t3.tianditu.com/DataServer?T=cva_w&x={x}&y={y}&l={z}&tk=token',
crossOrigin: 'anonymous'
}),
visible: true
});
//影像地图
that.layer.tiandituImgLayer = new ol.layer.Tile({
title: 'generalMapImg',
source: new ol.source.XYZ({
url: 'http://t3.tianditu.com/DataServer?T=img_w&x={x}&y={y}&l={z}&tk=token',
crossOrigin: 'anonymous'
}),
visible: true
});
//影像地图标注
that.layer.tiandituCiaLayer = new ol.layer.Tile({
title: 'generalMapImgZj',
source: new ol.source.XYZ({
url: 'http://t3.tianditu.com/DataServer?T=cia_w&x={x}&y={y}&l={z}&tk=token',
crossOrigin: 'anonymous'
}),
visible: true
});
this.map = new ol.Map({
target: 'eye',
layers: [
that.layer.tiandituImgLayer,
that.layer.tiandituCiaLayer,
that.layer.tiandituVecLayer,
that.layer.tiandituCvaLayer,
],
view: new ol.View({
center: [13410926.774433982, 3715530.4937355495],
zoom: 12
}),
controls: ol.control.defaults({
attributionOptions: {
collapsible: false
}
})
});
this.view_ = this.map.getView();
},
addTiles() {
// cesium加载代码
let tileSet = this._viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
url: '../res/data/3dtiles/tianjie/tileset.json',
modelMatrix: Cesium.Matrix4.fromArray(
[0.9972458032561666, 0.04372029028528979, 0.05991113506964879, 0,
-0.03623787897545647, 0.9920229449104262, -0.12073646051879428, 0,
-0.06471185374661931, 0.11823287609043515, 0.9908750491338749, 0,
-663.0794944260269, 1211.490494620055, 2974.1003134818748, 1]),
}));
this._viewer.flyTo(tileSet);
},
testOlCs() {
this.camera_ = new olcsCamera(this._viewer.scene, this.map);
this.camera_.checkCameraChange();
},
/**
* Render the Cesium scene
*/
render_() {
// if a call to `requestAnimationFrame` is pending, cancel it
if (this.renderId_ !== undefined) {
cancelAnimationFrame(this.renderId_);
this.renderId_ = undefined;
}
this.renderId_ = requestAnimationFrame(this.onAnimationFrame_.bind(this));
},
/**
* Callback for `requestAnimationFrame`.
* @param {number} frameTime The frame time, from `performance.now()`.
* @private
*/
onAnimationFrame_(frameTime) {
this.renderId_ = undefined;
// check if a frame was rendered within the target frame rate
const interval = 1000.0 / this.targetFrameRate_;
const delta = frameTime - this.lastFrameTime_;
if (delta < interval) {
// too soon, don't render yet
this.render_();
return;
}
// time to render a frame, save the time
this.lastFrameTime_ = frameTime;
const julianDate = this.time_();
this.scene_.initializeFrame();
this.scene_.render(julianDate);
this.camera_.checkCameraChange();
// request the next render call after this one completes to ensure the browser doesn't get backed up
this.render_();
}
},
created() {
},
}
</script>
<style scoped>
.home {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
#eye {
position: absolute;
width: 20%;
height: 20%;
bottom: 0;
right: 0;
z-index: 999;
background: red;
border: solid blue 1px;
}
#cesiumContainer {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>