本文实现的一种思路如下:
1、通过Cesium.Viewer创建鹰眼地图,获取主地图的当前范围和中心点位置,在鹰眼地图中创建矩形用于定位参考。
2、主地图联动鹰眼图
注册主地图相机的移动前(moveStart)和移动后(moveEnd)事件,来联动鹰眼地图的范围。
3、鹰眼地图联动主地图
通过拖拽矩形框,改变鹰眼地图范围后联动改变主地图范围。
使用鼠标的LEFT_DOWN、LEFT_UP和MOUSE_MOVE事件来实现矩形框实体位置的变化。
直接上代码,有需要的小伙伴可以参考。
JS代码
///
// 模块描述:鹰眼地图,和主地图进行联动
///
define([
'dojo/_base/declare',
'dojo/_base/lang',
'dojo/_base/array',
'dojo/_base/html',
'dojo/topic',
'jimu/BaseWidget'
],
function (declare,
lang,
array,
html,
topic,
BaseWidget
) {
var CesiumViewTool = (function () {//http://blog.sina.com.cn/s/blog_15e866bbe0102y5no.html
function _() {
}
_.GetViewExtent = function (viewer) {
var extent = {};
var scene = viewer.scene;
var ellipsoid = scene.globe.ellipsoid;
var canvas = scene.canvas;
var car3_lt = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(0, 0), ellipsoid);// canvas左上角
var car3_rb = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(canvas.width, canvas.height), ellipsoid); // canvas右下角
// 当canvas左上角和右下角全部在椭球体上
if (car3_lt && car3_rb) {
var carto_lt = ellipsoid.cartesianToCartographic(car3_lt);
var carto_rb = ellipsoid.cartesianToCartographic(car3_rb);
extent.xmin = Cesium.Math.toDegrees(carto_lt.longitude);
extent.ymax = Cesium.Math.toDegrees(carto_lt.latitude);
extent.xmax = Cesium.Math.toDegrees(carto_rb.longitude);
extent.ymin = Cesium.Math.toDegrees(carto_rb.latitude);
} else if (!car3_lt && car3_rb) { // 当canvas左上角不在但右下角在椭球体上
return null;
}
else if (car3_lt && !car3_rb) { // 当canvas左上角在但右下角不在椭球体上
return null;
} else if (!car3_lt && !car3_rb) {
return null;
}
// 获取高度
extent.height = Math.ceil(viewer.camera.positionCartographic.height);
return extent;
}
_.GetViewCenter = function (viewer) {
var result = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.clientWidth / 2, viewer.canvas.clientHeight / 2));
if (result) {
} else {
return null;
}
var curPosition = Cesium.Ellipsoid.WGS84.cartesianToCartographic(result);
var lon = curPosition.longitude * 180 / Math.PI;
var lat = curPosition.latitude * 180 / Math.PI;
var height = viewer.camera.positionCartographic.height;
return {
lgtd: lon,
lttd: lat,
height: height
};
}
return _;
})();
var MoveEntity = (function () {
var leftDownFlag = false;
var pointDraged = null;
var viewer;
var handler,cartesian;
var startPoint;
var polylinePreviousCoordinates;
var polygonPreviousCoordinates;
var rectanglePreviousCoordinates={};
var moveEndCallBack,moveStartCallBack;
function ConstructMoveEntity(options,_moveStartCallBack,_moveEndCallBack) {
viewer = options.viewer;
moveEndCallBack=_moveEndCallBack;
moveStartCallBack=_moveStartCallBack;
handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
Init();
}
function Init() {
// Select plane when mouse down
handler.setInputAction(function (movement) {
pointDraged = viewer.scene.pick(movement.position);//选取当前的entity
leftDownFlag = true;
if (pointDraged) {
if(moveStartCallBack){
moveStartCallBack();
}
//记录按下去的坐标
startPoint = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid)
viewer.scene.screenSpaceCameraController.enableRotate = false;//锁定相机
viewer.scene.screenSpaceCameraController.enableTranslate = false;
if(pointDraged.id.polygon){
// 1.54版本
// polygonPreviousCoordinates = pointDraged.id.polygon.hierarchy.getValue();
// 1.67版本
polygonPreviousCoordinates = pointDraged.id.polygon.hierarchy.getValue().positions;
}
}
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);
// Release plane on mouse up
handler.setInputAction(function () {
if(pointDraged&&moveEndCallBack){
moveEndCallBack(cartesian)
}
leftDownFlag = false;
pointDraged = null;
viewer.scene.screenSpaceCameraController.enableInputs = true;
viewer.scene.screenSpaceCameraController.enableRotate = true;//锁定相机
viewer.scene.screenSpaceCameraController.enableTranslate = true;
// handler.destroy();
}, Cesium.ScreenSpaceEventType.LEFT_UP);
// Update plane on mouse move
handler.setInputAction(function (movement) {
if (leftDownFlag === true && pointDraged != null) {
//记录尾随的坐标
//pickposition改为pickEllipsoid,鹰眼不加入地形
let startPosition = viewer.scene.camera.pickEllipsoid(movement.startPosition, viewer.scene.globe.ellipsoid)
let endPosition = viewer.scene.camera.pickEllipsoid(movement.endPosition, viewer.scene.globe.ellipsoid)
pointDraged.id.position = new Cesium.CallbackProperty(function () {
return endPosition;
}, false);//防止闪烁,在移动的过程console.log(pointDraged.id);
//计算每次的偏差
let changed_x = endPosition.x-startPosition.x;
let changed_y = endPosition.y-startPosition.y;
let changed_z = endPosition.z-startPosition.z;
if(pointDraged.id.polygon){
let currentsPoint=[];
for(let i=0;i<polygonPreviousCoordinates.length;i++){
polygonPreviousCoordinates[i].x=polygonPreviousCoordinates[i].x+changed_x;
polygonPreviousCoordinates[i].y=polygonPreviousCoordinates[i].y+changed_y;
polygonPreviousCoordinates[i].z=polygonPreviousCoordinates[i].z+changed_z;
currentsPoint.push(polygonPreviousCoordinates[i])
}
var holes=pointDraged.id.polygon.hierarchy.getValue().holes;
var hierarchy=new Cesium.PolygonHierarchy(currentsPoint, holes)
// supermap cesium1.67不可用
// pointDraged.id.polygon.hierarchy=new Cesium.CallbackProperty (() => {
// return pointDraged.id.polygon.hierarchy;
// }, false);
pointDraged.id.polygon.hierarchy=hierarchy
// // 1.54版本
// pointDraged.id.polygon.hierarchy=new Cesium.CallbackProperty (() => {
// return currentsPoint;
// }, false);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
}
return ConstructMoveEntity;
})();
return declare([BaseWidget], {
baseClass: 'jimu-widget-EagleEye',
layers:{},
startup: function () {
this.inherited(arguments);
this.initEagleEye();
var self = this;
var updateTimer,updateTimer2;
if (true) {
var camera = window.viewer.camera;
camera.moveStart.addEventListener(function() {
if (!Cesium.defined(updateTimer)) {
updateTimer = window.setInterval(self.extentChange, 1000);
}
});
camera.moveEnd.addEventListener(function() {
if (Cesium.defined(updateTimer)) {
window.clearInterval(updateTimer);
updateTimer = undefined;
}
self.extentChange();
});
}
MoveEntity({ 'viewer': this.eagleEyemap},
function(){
console.log(`开始移动`)
},
function(c){
console.log(`移动完成`)
self.extentChangeEyeMap(self.bound);
});
},
extentChangeEyeMap:function(entity){
if(this.eagleEyemap){
// 获取多边形的positions列表 并计算它的中心点
// 1.54版本
// var polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now());
// 1.67版本
var polyPositions = entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
var polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center;
var ellipsoid=this.eagleEyemap.scene.globe.ellipsoid;
var cartesian3=new Cesium.Cartesian3(polyCenter.x,polyCenter.y,polyCenter.z);
var cartographic=ellipsoid.cartesianToCartographic(cartesian3);
var lat=Cesium.Math.toDegrees(cartographic.latitude);
var lng=Cesium.Math.toDegrees(cartographic.longitude);
// 保留主地图原有相机高度
var height=window.viewer.camera.positionCartographic.height;
window.viewer.camera.setView({
destination : Cesium.Cartesian3.fromDegrees(lng,lat,height)
});
}
},
extentChange:function(){//改变之后
var extent = CesiumViewTool.GetViewExtent(window.viewer);
var center = CesiumViewTool.GetViewCenter(window.viewer);
if(extent&&this.createExtentPolygon){
this.createExtentPolygon([extent.xmin,extent.ymin],[extent.xmax,extent.ymax],center);
}else{
if(!center)return;
if(this.eagleEyemap){
this.eagleEyemap.camera.setView({
destination : Cesium.Cartesian3.fromDegrees(center.lgtd, center.lttd, center.height*4)
});
}
}
},
createExtentPolygon: function (pt1,pt2,center) {
if(!center)return;
var ringsArray = [];
ringsArray.push(pt1[0], pt1[1]);
ringsArray.push(pt2[0], pt1[1]);
ringsArray.push(pt2[0], pt2[1]);
ringsArray.push(pt1[0], pt2[1]);
ringsArray.push(pt1[0], pt1[1]);
if(this.bound){
this.bound.polygon.hierarchy = Cesium.Cartesian3.fromDegreesArray(ringsArray);
this.eagleEyemap.camera.setView({
destination : Cesium.Cartesian3.fromDegrees(center.lgtd, center.lttd, center.height*4)
});
return;
}
this.bound = this.eagleEyemap.entities.add({
name : 'polygon',
position:Cesium.Cartesian3.fromDegrees(center.lgtd, center.lttd),
polygon : {
hierarchy : Cesium.Cartesian3.fromDegreesArray(ringsArray),
material : Cesium.Color.RED.withAlpha(0.5),
outline : true,
outlineColor : Cesium.Color.RED,
outlineWidth:2.0
}
});
this.eagleEyemap.camera.setView({
destination : Cesium.Cartesian3.fromDegrees(center.lgtd, center.lttd, center.height*4)
});
},
initEagleEye:function(){
//添加鹰眼
this.eagleEyemap = new Cesium.Viewer(this.eagleEye,{
"animation":false,
"baseLayerPicker":false,
"fullscreenButton":false,
"geocoder":false,
"homeButton":false,
"infoBox" : false,
"sceneModePicker":false,
"selectionIndicator" : false ,
"timeline":false,
"navigationHelpButton":false,
"scene3DOnly" : false,
"navigationInstructionsInitiallyVisible":false,
"terrainExaggeration":1,
"showRenderLoopErrors":false,
"sceneMode":Cesium.SceneMode.SCENE2D,
"imageryProvider":null
});
//去掉版权
this.eagleEyemap._cesiumWidget._creditContainer.style.display = "none";
this.eagleEyemap.scene.globe.depthTestAgainstTerrain = true;
var layers=this.appConfig.map.overViewLayers;
if(layers&&layers.length>0){
layers.forEach(x=>{
let layer=null;
//公开底图自定义封装库
//天地图
let type=x.type.toLowerCase();
if(type=="tdt"){
layer=new Cesium.TdtImageryProvider(x)
}
// 高德
else if (type=="gd"){
layer=new Cesium.AmapImageryProvider(x)
}
// 腾讯
else if (type=="tx"){
layer=new Cesium.TencentImageryProvider(x)
}
// 百度
else if (type=="bd"){
layer=new Cesium.BaiduImageryProvider(x)
}
// 谷歌
else if (type=="google"){
layer=new Cesium.GoogleImageryProvider(x)
}
// 其他cesium支持的类型
else if (type == "url") {
layer = new Cesium.UrlTemplateImageryProvider(x);
} else if (type == "wmts") {
layer = new Cesium.WebMapTileServiceImageryProvider(x);
} else if (type == "supermap") {
layer = new Cesium.SuperMapImageryProvider(x);
} else if (type == "arcgis") {
layer = new Cesium.ArcGisMapServerImageryProvider(x);
}
if(layer){
this.eagleEyemap.imageryLayers.addImageryProvider(layer)
}
})
}
var extent = {
"xmin": 86.06689524994869,
"ymin": 22.108857182532834,
"xmax": 124.9584857499487,
"ymax": 48.08052948253283};
var west = extent.xmin;
var south = extent.ymin;
var east =extent.xmax;
var north =extent.ymax;
this.eagleEyemap.camera.setView({
destination : Cesium.Rectangle.fromDegrees(west, south, east, north)
});
// this.vis()
},
onOpen: function () {
//面板打开的时候触发 (when open this panel trigger)
},
onClose: function () {
//面板关闭的时候触发 (when this panel is closed trigger)
},
onMinimize: function () {
this.resize();
},
onMaximize: function () {
this.resize();
},
resize: function () {
},
destroy: function () {
//销毁的时候触发
//todo
//do something before this func
this.inherited(arguments);
},
flag:true,
vis:function(){
if(this.flag){
$(this.eagleEye).hide();
this.visNode.innerHTML = "显示鹰眼";
$(this.domNode).height(30);
$(this.domNode).width(74);
}else{
$(this.eagleEye).show();
$(this.domNode).height(this.position.height);
$(this.domNode).width(this.position.width);
this.visNode.innerHTML = "隐藏鹰眼";
}
this.flag = !this.flag;
}
});
});
里面中底图的判断使用了前一篇所讲的在线底图封装
html代码
<div>
<div style="width:100%;height:100%; border: 3px solid #b8b5b5;
border-radius: 5px;" data-dojo-attach-point="eagleEye"></div>
<div style=" position: absolute;cursor: pointer;
bottom: 2px;
left: 2px;
height: 29px;
width: 74px;
padding: 3px;
background-color: #0a001f;"><a style=" color: white;
font-size: 14px;
padding: 5px;" data-dojo-attach-point="visNode" data-dojo-attach-event="click:vis">隐藏鹰眼</a></div>
</div>
结果截图: