基础项目 原生JS版 使用介绍

5/8/2023

# 项目介绍

Mars3D基础项目 是基于Mars3D平台 (opens new window)做的一个应用系统,提供的一个基础项目模版,包含常用基础地图功能,可在该基础项目上快速开发搭建新项目。方便快速搭建三维地图产品,敏捷开发,可复用,支持各种配置,适合各种场景使用。

# 项目特性

  • 原生JS技术栈:基于传统模式下,原生JS技术栈开发的,不依赖框架。
  • 适用于地图场景的widget模块化: 使用widgetm插件进行模块化封装调用各功能(代码在项目的lib\mars3d\thirdParty\es5-widget\es5-widget.js)
  • 成熟稳定: 火星科技在传统技术栈时(vue还没成熟流行时)多年来应用于无数项目,归纳总结的一个基础的项目模版

如果您不熟悉原生JS,也可以阅读:基础项目Vue版基础项目React版

# 视频讲解

建议先看一遍视频讲解,再实际操作,您可以新页面查看高清视频 (opens new window)

视频预览:

# 下载运行项目

# 下载代码

git clone https://github.com/marsgis/mars3d-es5-project.git
1
git clone https://gitee.com/marsgis/mars3d-es5-project.git
1

如果需要所有功能模块的widget和其他一些项目模板,需要联系我们付费购买 (opens new window)

电子沙盘、综合态势等系统代码内部结构和基础项目类同,只是在widget功能数量和样式上有所不同。

# 下载最新lib

建议从http://mars3d.cn/download.html (opens new window)下载最新mars3d类库后覆盖至lib/目录下即可。

# 运行方式1:使用vscode及其插件

在任意开发编辑器(如vscode等)或http服务器(如node、nginx、tomcat、IIS等)下直接运行浏览index.html或对应示例页面即可 ,

建议使用VScode工具打开代码目录(请参考上一章节安装好VScode 及 Live Server插件)。

参考下图通过Live Server访问各页面

image

# 运行方式2:运行npm命令

# 首次运行前安装依赖

npm install

//或使用代理
npm i --registry=http://registry.taobao.org
1
2
3
4

# 启动开发环境

npm run serve
1

# 编译构建

npm run build //编译后生成在dist目录,拷贝出去发布即可
npm run serve:dist  //测试dist运行状态
1
2

# 运行效果

访问基础项目在线 (opens new window)体验效果和功能

image

# 如何反馈问题?

  • 发现您发现项目中存在的问题或者需要优化的地方;
  • 如果您有一些自己全新编写的示例,希望也开源与大家分享。

提交方式:

  • 欢迎在 github 或 gitee 上提交 PR (opens new window)
  • 如果对 git 不熟悉,也可以整理示例代码发送邮件到 wh@marsgis.cn 由我们来整理集成。

# 项目架构

# 主要技术选型

# 基础技术环境

# 主要目录说明

我们通过vscode打开该项目,项目中最重要的是2个点是,json配置文件widget模块化开发,一般开发项目只用修改配置文件和开发新的widget即可。

mars3d-es5-project
│───config           配置文件
│   └─config.json    地图初始化构造参数配置文件
│   └─widget.json    项目widget的模块配置信息文件
│───css              样式文件
│───img              图片资源文件
│───js               首页对应的js入口文件
│───widget           功能相关的widget控件【重要】,也可以按业务分在多个目录中,比如`widgetsTS目录`
│───lib                 示例依赖资源
│   └─include-lib.js    lib资源统一配置文件
└───index.html          首页入口
1
2
3
4
5
6
7
8
9
10
11

# 1. widget模块化架构说明

widget模块化设计方式是我们在2016年设计的一种基于传统JS的模块化设计架构。设计思想主要是借鉴了gis行业的arcgis flexviewer和jsviewer,也借鉴了前端行业的React和Vue。当前最流行和通用的方式是整个项目用Vue、React或angular下开发最佳,用现代化的技术栈来做开发。

# 1.1 使用widget的理由

目前还保留widget模块化的方式,是因为:

  • 实用性,主要考虑到该方式使用多年,已在大量项目中使用, 积累比较多,并且成熟稳定;
  • 并且当前还是有很大一部分公司项目还是传统方式开发的;
  • widget模块也兼容vue、react、 angular下通过静态资源方式来使用。

# 1.2 widget的特点

  • 将每个业务模块设计为独立的widget模块,互相都是独立的,互相解耦,类似vue组件。
  • widget是按需加载和初始化,默认是不加载的,单击激活后才会加载其相关js和html等资源。
  • 有很多可配置的参数,无需代码即可按需配置自动释放激活、界面位置、大小等。

保留使用 widget模块化 方式,并不是指我们不用vue等现代化技术栈,而是具体按公司人员研发水平和技术栈情况按需选择,适合自己的才是最好的。

# 1.3 es5-widget插件源码

为了更容易理解内部逻辑,您可以参考项目内lib\mars3d\thirdParty\es5-widget\es5-widget.js进行查阅。

# 2. include-lib.js文件说明

我们当前项目内的第三方类库及我们的sdk类库都存放在lib目录下,每个目录均有README.md文件说明该类库的github地址、官网和用途等信息。

image

为了方便切换和引入第3方lib,我们编写了一个独立的js文件include-lib.js (opens new window)来统一调用使用第3方lib,在需要的页面按下面方式引入lib:

<!--第三方lib-->
<script type="text/javascript" src="../lib/include-lib.js" libpath="../lib/"
    include="font-awesome,turf,mars3d"></script>
1
2
3

该方式等价于(如不习惯include-lib.js,也可以改为下面演示的直接引入方式):

<!--对应font-awesome-->
<link rel="stylesheet" href="../lib/fonts/font-awesome/css/font-awesome.min.css">

<!--对应turf-->
<script type="text/javascript" src="../lib/turf/turf.min.js"></script>

<!--对应mars3d-->
<link rel="stylesheet" href="../lib/Cesium/Widgets/widgets.css">
<script type="text/javascript" src="../lib/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="../lib/mars3d/mars3d.css">
<script type="text/javascript" src="../lib/mars3d/mars3d.js"></script>
1
2
3
4
5
6
7
8
9
10
11

# 3. widget初始化及管理

目前平台示例和项目中使用到的widget.json (opens new window) 是静态json文件方式 文件中配置参数与es5widget.init方法API的方法参数是完成相同一致的,代码中加载json后传入到init方法中。

widget初始化方法:

//初始化widget管理器
es5widget.init(map, widgetCfg, './') //tip: 第3个参数支持定义widget目录的相对路径。
1
2

# 3.1 widget的管理

在外部调用widget功能,都是通过 es5widget静态类来统一管理的,更多方法可以参阅该类的API文档。

比如激活widet:在需要外部使用的地方通过 es5widget.activate(options) 来激活widget模块, 参数支持多种模式可多样化兼容使用, 比如:

//常用,直接使用uri
es5widget.activate("widgets/bookmark/widget.js"); 

//支持所有可配参数和自定义参数,在widget.js内部通过this.config可获取传入的参数
es5widget.activate({name:"书签", uri: "widgets/bookmark/widget.js "}); 
1
2
3
4
5

# 4. 单个widget模块组成

每个widget模块必须存在 widget.js 文件,该文件内部定义了一个继承了 BaseWidget类 的子类。

类内最重要的几个属性和方法如下:

分类 名称 功能
get属性 resources 需要预先加载到主页面的js、css资源文件
get属性 view 存在弹窗或界面时配置,具体详见后节说明
内部变量 config 对应widget定义的或传入的配置信息
内部变量 path 当前widget所在目录的相对于网页的路径
内部变量 map 当前Map地图对象
方法 create 插件初始化触发,仅执行1次
方法 winCreateOK view属性定义的界面每次初始化后调用
方法 activate 打开激活插件 触发
方法 disable 关闭释放插件 触发

# 4.1 view属性

默认每个插件是无界面或弹窗的, 如果需要有对应的弹窗或界面(如弹窗、输入栏、菜单等)请定义view属性。

请参考贝widgets\_example*命名的示例widget来新建widget模块,建议直接复制后改下目录名称即可。

view配置中必须存在2个属性:type标识类型,url为html地址。 目前view有下面3种模式供使用:

type属性 功能 对应的示例 说明
window iframe模式弹窗 _example 独立的html子页面,比较自由,简单粗暴、无任何限制;可以每个页面用不同的UI和第三方插件不用考虑冲突问题;任何水平的开发人员均容易快速开发。
divwindow div元素模式弹窗 _example_divwin 可直接互相访问,这种模式弊端是易引起模块间id命名冲突,在css和html中命名时需注意。
append 任意html元素 _example_append 任意div节点,比较自由.

# window时:

view.html页面(或引入的view.js中)必须定义一个initWidgetView方法,框架会自动调用进行传入当前widget对象,用于页面中调用widget中的方法属性。 可以配置windowOptions参数来定义弹窗的大小、位置等。

get view() {
  return {
     type: 'window',
     url: 'view.html',
     windowOptions: { width: 250 },
  }
}
1
2
3
4
5
6
7

此时的view.html和view.js是iframe的子页面,与地图所在的index.html是父子关系,相关js代码时需要注意这个层次才能更好的编码。

# divwindow时:

此模式不用单独的js, view界面相关js逻辑全部写在widget.js中 同样支持windowOptions参数配置。

get view() {
  return {
     type: 'divwindow',
     url: 'view.html',
     windowOptions: { width: 210, height: 210 },
  }
}
1
2
3
4
5
6
7

# append时:

将view的html直接添加至主页面中指定id的DOM节点下,通过parent属性配置指定,默认是body

get view() {
  return { type: 'append', url: 'view.html', parent: '#centerDiv' }
}
1
2
3

# 4.2 widget被激活后执行流程

widget激活后页面执行流程:

    1. 引入加载widget.js到index.html页面上
    1. (如果有resources配置)引入加载resources资源到index.html页面上
    1. (如果有view配置)打开view弹窗或构造view界面

widget激活后执行方法顺序: create => winCreateOK => activate => view中的 initWidgetView

# 4.3 测试开发好的widget

当还没有菜单时,需要测试widget功能,可以2种方式:

一是在url中传入widget参数方式激活对应widget来测试.比如:

http://mars3d.cn/project/es5/jcxm.html?widget=widgets/plot/widget.js (opens new window)

二是在widget.json中可以加配置"debugger": true, 打开 widget测试栏 功能,方便测试及触发激活widget,发布的正式版本记得改回 false 或删除。

{
  "debugger":true,
  "version": "20170825",
  "defaultOptions": {
    "style": "dark",
    "windowOptions": {
      "skin": "layer-mars-dialog animation-scale-up",
      "position": { "top": 50,  "right": 10 },
      "maxmin": true,
      "resize": true
    },
    "autoReset": false,
    "autoDisable": true,
    "disableOther": true
  },
  "openAtStart": [],
  "widgets": []
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

运行后效果: image

# 4.4 向widget传值示例

在qyPoint模块中(widgetsTS\qyPoint\widget.js)单击地图上的点后,激活弹出详情窗口qyDetailsView模块

showDetails(item) { 
    es5widget.activate({
       uri: 'widgetsTS/qyDetailsView/widget.js',
       dataQy: item,
    })
}
1
2
3
4
5
6

qyDetailsView模块(widgetsTS\qyDetailsView\widget.js)中通过this.config获取传过来的值

getData() {
   var item = this.config.dataQy //传入过来的参数
   return item
}
1
2
3
4

# 4.5 不同widget之间的通信交互示例

可以利用es5widget作为桥梁,通过事件的方式交互,这种比较自由方便,注意项目内事件名称唯一即可。

//演示:抛出事件,在其他widget或vue中监听使用  widgets\centerXY\widget.js
es5widget.fire("centerXY",{position:position })

//演示:接收的widget内抛出的事件  js、vue或其他widget.js中
es5widget.on('centerXY', function (event) {
   console.log('在widget进行了坐标定位1', event)
})

//如果在弹窗的view.js中
parent.es5widget.on('centerXY', function (event) {
   console.log('在widget进行了坐标定位2', event)
})

1
2
3
4
5
6
7
8
9
10
11
12
13

下面演示在【POI查询栏】单击查询按钮后勾选【图层控制】面板中的文庙图层。

image

# A模块 持续更新B模块

在roamFly模块中,动态去更新已打开的roamChars模块,更新显示数据

//持续更新
updateCharsWidgeFlyOk(alllen) { 
   //抛出事件
   es5widget.fire("updateRoamChars",{ data:alllen })
}
1
2
3
4
5

roamChars模块中监听事件

create() {
   //接收roamFly的widget内抛出的事件
   es5widget.on('updateRoamChars', function (event) {
      console.log('接收到了数据', data)
   })
}
1
2
3
4
5
6

# 2个iframe弹窗时,A的view内调用B的view内

A、B两个都是iframe弹窗模式的widget模块时,在A模块中的view.html中需要调用B模块的view.html

【主页面】widget.js都在index.html主页面; 【iframe子页面】 2个view.html(含view.js)是iframe子页面。

如果不用事件时,其调用流程是下图过程: image

如果通过事件方式可以下面的方式:

//演示:在A模块中的view.html中抛出事件
parent.es5widget.fire("widget2widget",{ data: position })

//演示:如果在弹窗的view.js中
parent.es5widget.on('widget2widget', function (event) {
   console.log('接收到了A模块抛出的事件', event)
})

1
2
3
4
5
6
7
8

# 5. 学习路线

以上介绍的这么只是让大家对Mars3D基础项目的基本情况和架构做了概览了解。下一步就需要大家静下心来阅读代码了,学习没有捷径,可以按下面路线一步步来学习。

查看已有的3个 “example示例”空白模版的代码、配置信息、运行效果。熟悉widget机制。

_example模块 => 已有的widgets模块 => 编写全新的widget

image

最后更新: 3/19/2024, 11:31:46 AM