Cesium
中可操作的模块都是由Widget
组成的,比如地图上的首页
按钮,点击按钮后地图将恢复到地球状态,看似一个很简单的功能,代码却不少,这是由于使用了组件化的思想,将一些功能抽成组件的方式方便添加和删除。下面就使用原生的javascript
来实现一个放大缩小地图的组件,后面再介绍使用用vue
来实现其它的组件。主要包括ZoomInOut .js
,ZoomInOut .css
,ZoomInOutViewModel.js
三个文件效果图如下所示:
1.创建ViewModel文件
自定义组件采用的是MVVM
的思想,主要借助于knockout
这个js
库来实现ViewModel
,因此在创建自定义组件的时候需要创建一个ViewModel
的文件,该文件主要用于定义属性、创建事件的实现。
1.1 定义属性
使用Object.defineProperties
重写get
和set
方法。如下所示:
Object.defineProperties(ZoomInOutViewModel.prototype, {
scene: {
get: function () {
return this._scene;
},
},
zoomIn: {
get: function () {
return this._zoomIn;
},
},
zoomOut: {
get: function () {
return this._zoomOut;
},
},
});
1.2 创建事件
使用createCommand
进行创建事件,
this._zoomIn = createCommand(function () {
});
//ZoomInOutViewModel.js
import defined from "../../Core/defined.js";
import DeveloperError from "../../Core/DeveloperError.js";
import knockout from "../../ThirdParty/knockout.js";
import createCommand from "../createCommand.js";
function ZoomInOutViewModel(scene) {
if (!defined(scene)) {
throw new DeveloperError("scene is required.");
}
this._scene = scene;
var that = this;
this._zoomOut = createCommand(function () {
// 获取当前镜头位置的笛卡尔坐标
let cameraPos = that._scene.camera.position;
// 获取当前坐标系标准
let ellipsoid = that._scene.globe.ellipsoid;
// 根据坐标系标准,将笛卡尔坐标转换为地理坐标
let cartographic = ellipsoid.cartesianToCartographic(cameraPos);
// 获取镜头的高度
let height = cartographic.height;
that._scene.camera.zoomOut(height * 1.2);
});
this._zoomIn = createCommand(function () {
// 获取当前镜头位置的笛卡尔坐标
let cameraPos = that._scene.camera.position;
// 获取当前坐标系标准
let ellipsoid = that._scene.globe.ellipsoid;
// 根据坐标系标准,将笛卡尔坐标转换为地理坐标
let cartographic = ellipsoid.cartesianToCartographic(cameraPos);
// 获取镜头的高度
let height = cartographic.height;
that._scene.camera.zoomIn(height/3);
});
this.zoomInTooltip = "放大";
this.zoomOutTooltip = "缩小";
knockout.track(this, ["zoomInTooltip"]);
knockout.track(this, ["zoomOutTooltip"]);
}
Object.defineProperties(ZoomInOutViewModel.prototype, {
scene: {
get: function () {
return this._scene;
},
},
zoomIn: {
get: function () {
return this._zoomIn;
},
},
zoomOut: {
get: function () {
return this._zoomOut;
},
},
});
export default ZoomInOutViewModel;
2.创建元素
创建元素跟平时我们使用js
创建元素的方式是一样的,主要不同点在于事件的绑定不一样,这里绑定事件是直接在setAttribute
中使用click
进行事件绑定,click
指定的函数名为ViewModel
中创建的事件函数,如下所示:
var zoomOut = document.createElement("button");
zoomOut.style.marginTop = '5px';
zoomOut.style.fontWeight = 'bold';
zoomOut.type = "button";
zoomOut.className = "cesium-button cesium-toolbar-button cesium-home-button";
zoomOut.setAttribute(
"data-bind",
"\
attr: { title: zoomOutTooltip },\
click: zoomOut"
);
zoomOut.innerText = "-";
element.appendChild(zoomOut);
3.绑定元素
创建好ViewModel
后,需要将ViewModel
与元素进行绑定,采用knockout
中的applyBindings
进行元素的绑定,如下所示:
knockout.applyBindings(viewModel, element);
4.添加元素到地图上
创建好元素并绑定后,需要将其显示在地图上,首先找到Viewer.js
文件,在/Cesium/Source/Widgets/Viewer/Viewer.js
目录下,然后将ZoomInOut.js
引入进行再进行实例化,将新的元素添加到viewerContainer
上,如下所示:
import ZoomInOut from "../ZoomInOut/ZoomInOut.js";
//ZoomInOut
var zoomInOutContainer = document.createElement("div");
zoomInOutContainer.className = "cesium-viewer-zoomInOutContainer";
viewerContainer.appendChild(zoomInOutContainer);
var zoomInOut = new ZoomInOut(zoomInOutContainer,scene);
//ZoomInOut.js
import defined from "../../Core/defined.js";
import destroyObject from "../../Core/destroyObject.js";
import DeveloperError from "../../Core/DeveloperError.js";
import knockout from "../../ThirdParty/knockout.js";
import getElement from "../getElement.js";
import ZoomInOutViewModel from "./ZoomInOutViewModel.js";
/**
* 放大缩小组件
* @param container
* @param scene
* @constructor
*/
function ZoomInOut(container, scene) {
if (!defined(container)) {
throw new DeveloperError("container is required.");
}
container = getElement(container);
var viewModel = new ZoomInOutViewModel(scene);
var element = document.createElement("div");
var zoomIn = document.createElement("button");
zoomIn.type = "button";
zoomIn.className = "cesium-button cesium-toolbar-button cesium-home-button";
zoomIn.setAttribute(
"data-bind",
"\
attr: { title: zoomInTooltip },\
click: zoomIn"
);
zoomIn.innerText = "+";
element.appendChild(zoomIn);
var zoomOut = document.createElement("button");
zoomOut.style.marginTop = '5px';
zoomOut.style.fontWeight = 'bold';
zoomOut.type = "button";
zoomOut.className = "cesium-button cesium-toolbar-button cesium-home-button";
zoomOut.setAttribute(
"data-bind",
"\
attr: { title: zoomOutTooltip },\
click: zoomOut"
);
zoomOut.innerText = "-";
element.appendChild(zoomOut);
container.appendChild(element);
knockout.applyBindings(viewModel, element);
this._container = container;
this._viewModel = viewModel;
this._element = element;
}
Object.defineProperties(ZoomInOut.prototype, {
container: {
get: function () {
return this._container;
},
},
viewModel: {
get: function () {
return this._viewModel;
},
},
});
/**
* 判断是否销毁组件,由于能调用该方法,所以一定是没销毁的,因此直接返回false
* @returns {boolean}
*/
ZoomInOut.prototype.isDestroyed = function () {
return false;
};
/**
* 销毁组件
*/
ZoomInOut.prototype.destroy = function () {
knockout.cleanNode(this._element);
this._container.removeChild(this._element);
return destroyObject(this);
};
export default ZoomInOut;
5.引入样式文件
如果有创建css
文件,需要引入到项目中,首先找到widgets.css
文件,目录在/Cesium/Source/Widgets/widgets.css
,然后使用@import url(./ZoomInOut/ZoomInOut.css);
引入样式文件。
.cesium-viewer-zoomInOutContainer{
display: block;
width: 30px;
height: 100px;
margin: 0;
border-radius: 0;
position: absolute;
right:12px;
top: 40px;
}