Cesium指南-自定义原生js组件

Cesium中可操作的模块都是由Widget组成的,比如地图上的首页按钮,点击按钮后地图将恢复到地球状态,看似一个很简单的功能,代码却不少,这是由于使用了组件化的思想,将一些功能抽成组件的方式方便添加和删除。下面就使用原生的javascript来实现一个放大缩小地图的组件,后面再介绍使用用vue来实现其它的组件。主要包括ZoomInOut .js,ZoomInOut .css,ZoomInOutViewModel.js三个文件效果图如下所示:

1.创建ViewModel文件

自定义组件采用的是MVVM的思想,主要借助于knockout这个js库来实现ViewModel,因此在创建自定义组件的时候需要创建一个ViewModel的文件,该文件主要用于定义属性创建事件的实现。

1.1 定义属性

使用Object.defineProperties重写getset方法。如下所示:

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;
}

你可能感兴趣的:(Cesium指南-自定义原生js组件)