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

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

WX20210418-190206@2x.png

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容