├── .gitignore
├── README.md
├── babel.config.js
├── jsconfig.json
├── package.json
├── public
├── favicon.ico
├── icons
│ ├── 1.png
│ ├── 2.png
│ └── 3.png
├── index.html
└── model
│ ├── Duck.glb
│ ├── Wood_Tower.glb
│ ├── default.png
│ └── tower.png
├── release.js
├── src
├── App.vue
├── assets
│ ├── css
│ │ ├── demo.css
│ │ ├── iconfont.css
│ │ ├── iconfont.eot
│ │ ├── iconfont.js
│ │ ├── iconfont.json
│ │ ├── iconfont.svg
│ │ ├── iconfont.ttf
│ │ ├── iconfont.woff
│ │ ├── iconfont.woff2
│ │ └── theme
│ │ │ ├── dark.scss
│ │ │ └── default.scss
│ ├── images
│ │ ├── 0.png
│ │ ├── icon
│ │ │ ├── file.png
│ │ │ ├── label.png
│ │ │ ├── marker.png
│ │ │ ├── polygon.png
│ │ │ └── polyline.png
│ │ └── nothmub.jpg
│ ├── js
│ │ └── iconfont.js
│ └── logo.png
├── cdn.js
├── components
│ ├── cesiumDrawViewer.vue
│ ├── layerManager.vue
│ └── markerViewer.vue
├── core
│ ├── Graphic.js
│ ├── GraphicManager.js
│ ├── GraphicType.js
│ └── MarkerManager.js
├── js
│ └── utils.js
└── main.js
├── vue.config.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 |
6 | # local env files
7 | .env.local
8 | .env.*.local
9 |
10 | # Log files
11 | npm-debug.log*
12 | yarn-debug.log*
13 | yarn-error.log*
14 | yarn.lock
15 | pnpm-debug.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Cesium-Draw
3 |
4 | 基于Vue 3.x开发的Cesium基础标绘插件,支持交互式添加BillBoard、Polyline、Polygon、Label和Model
5 |
6 | Vue 2.x请访问 https://github.com/xtfge/cesium-draw/tree/cesium-draw-vue2
7 |
8 | 核心功能:
9 | - 鼠标交互绘图
10 | - 对于Billboard、Label、Model支持图标,名称的编辑,图标可以任意扩展.
11 | - 对于Polyline和Polygon支持顶点、颜色等常见图形属性的编辑.
12 | - 支持导入、导出功能
13 | - 可以通过图层管理器管理通过该插件添加的所有图形.
14 |
15 | 兼容性
16 | - 目前已测试兼容的Cesium最低版本为Cesium@1.88,最高版本为Cesium@1.119
17 | - 版本低于1.88的版本没有经过测试
18 | ### 安装
19 |
20 | ```sh
21 | npm i cesium-draw
22 | ```
23 |
24 | **4.0.0及以上版本为Vue3.x版本,4.0.0以下的版本为Vue2.x的版本**
25 |
26 | ### 使用
27 | ```HTML
28 |
29 |
33 |
34 |
53 | ```
54 | **如果您是在html中通过script引用的Cesium,您需要额外配置webpack**
55 | 您需要修改`vue.config.js`, 添加以下内容
56 | ```js
57 | module.exports = defineConfig({
58 | // ...
59 | configureWebpack: {
60 | externals: {
61 | cesium: 'Cesium'
62 | }
63 | },
64 | // ...
65 | });
66 | ```
67 | 如果您使用的构建工具是`vite`,请了解vite相关配置。
68 | #### 扩展图片标记的图标
69 | ```html
70 |
71 | ```
72 | ```js
73 | data(){
74 | return{
75 | images:["./static/images/markers/1.png",
76 | "./static/images/markers/2.png",
77 | "./static/images/markers/3.png",
78 | "./static/images/markers/4.png",
79 | "./static/images/markers/5.png"
80 | ]
81 | }
82 | }
83 | ```
84 | #### 启用模型标记
85 | **你必须通过`extendMarkerModel`属性定义用于标记的模型,才可以使用模型标记。**
86 |
87 | 比如:
88 | ```html
89 |
90 | ```
91 | ```js
92 | data(){
93 | return{
94 | models:[
95 | { id: "model0",
96 | name: "木塔",
97 | thumb:'thumb.png', // 定义模型的缩略图,如果未定义,则使用默认图片
98 | url: "static/model/Wood_Tower.gltf" },
99 | {
100 | id: "model1",
101 | name: "小人",
102 | url: "static/model/Cesium_Man.gltf" }]
103 | }
104 | }
105 | ```
106 | #### 如何使用喜欢的主题
107 | ```js
108 | import 'cesium-draw/dist/theme/default.css'
109 | ```
110 | 或
111 | ```js
112 | import 'cesium-draw/dist/theme/dark.css'
113 | ```
114 | >更多主题敬请期待。
115 | #### 完整示例
116 | ```HTML
117 |
118 |
122 |
123 |
155 | ```
156 | ### Methods
157 | - `getById(mid)` 根据id返回图形要素
158 | ### Events
159 | 事件|说明|回调
160 | ---|---|---
161 | deleteEvent|要素删除事件|参数为删除要素的id
162 | locateEvent|要素定位事件|定位要素的id
163 | editEvent|要素编辑事件|要素的id
164 | renameEvent|要素重命名事件|两个参数,依次为要素id,要素更新前的名称
165 | selectEvent|checkbox点击事件|两个参数,依次为要素id,checkbox状态
166 | closeEvent|标绘面板关闭事件|无
167 | ### 开发&打包
168 | ```sh
169 | npm install
170 | npm run build
171 | ```
172 | ### 打包成组件
173 | ```sh
174 | npm run lib
175 | ```
176 | ### 效果
177 | 
178 | 
179 | 
180 |
181 | ### Cesium交流群
182 | [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=bgWooLP8IhmlRV-V9ATdqEmq3oXze8uX&authKey=4ce2A9KMcoxJOpiASPIBXTNwc%2B5a3cL7n4P%2BoXD2YyJp4dR4H2BfHfqBQi4RurYP&noverify=0&group_code=107615960) [](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=OPOFzUro3j8kgtFYG1NU3NEammB0bTny&authKey=esRwasLjLPchfAxo6qQjYHsiWGN4%2BT32WKKjOVHyKeMr1HMvfWHl1PRmyo4zGQis&noverify=0&group_code=628262010)
183 |
184 | ### 捐赠
185 | >如果您觉得这个项目帮助到了您,您可以请作者喝一杯咖啡表示鼓励
186 |
187 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ],
5 | plugins: ['@babel/plugin-proposal-class-properties'],
6 | }
7 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2021",
4 | "module": "esnext",
5 | "baseUrl": "./",
6 | "moduleResolution": "node",
7 | "paths": {
8 | "@/*": [
9 | "src/*"
10 | ]
11 | },
12 | "lib": [
13 | "esnext",
14 | "dom",
15 | "dom.iterable",
16 | "scripthost"
17 | ]
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cesium-draw",
3 | "version": "4.1.0",
4 | "description": "add a mark,polyline,polygon base on Cesium and Vue 3.x",
5 | "private": false,
6 | "keyword": "Cesium Polygon Polyline mark interactive",
7 | "main": "./dist/cesiumdrawViewer.umd.min.js",
8 | "files": [
9 | "dist",
10 | "package.json",
11 | "README.md"
12 | ],
13 | "scripts": {
14 | "serve": "vue-cli-service serve",
15 | "build": "vue-cli-service build",
16 | "lint": "vue-cli-service lint",
17 | "lib": "vue-cli-service build --target lib --name cesiumdrawViewer ./src/cdn.js"
18 | },
19 | "dependencies": {
20 | "cesium": "^1.119.0",
21 | "core-js": "^3.8.3",
22 | "element-plus": "^2.3.5",
23 | "file-saver": "^2.0.5",
24 | "jquery": "^3.7.0",
25 | "shapefile": "^0.6.6",
26 | "vue": "^3.2.13"
27 | },
28 | "devDependencies": {
29 | "@babel/core": "^7.21.8",
30 | "@babel/eslint-parser": "^7.12.16",
31 | "@babel/plugin-proposal-class-properties": "^7.18.6",
32 | "@babel/preset-env": "^7.21.5",
33 | "@vue/cli-plugin-babel": "~5.0.0",
34 | "@vue/cli-plugin-eslint": "~5.0.0",
35 | "@vue/cli-service": "~5.0.0",
36 | "cesium-draw": "^4.0.0",
37 | "copy-webpack-plugin": "^12.0.2",
38 | "default-passive-events": "^2.0.0",
39 | "eslint": "^8.41.0",
40 | "eslint-plugin-vue": "^9.14.0",
41 | "mini-css-extract-plugin": "^2.7.6",
42 | "sass": "^1.62.1",
43 | "sass-loader": "^13.2.2",
44 | "vue-cli-plugin-element": "~1.0.1"
45 | },
46 | "eslintConfig": {
47 | "root": true,
48 | "env": {
49 | "node": true
50 | },
51 | "extends": [
52 | "plugin:vue/vue3-essential",
53 | "eslint:recommended"
54 | ],
55 | "parserOptions": {
56 | "parser": "@babel/eslint-parser"
57 | },
58 | "globals": {
59 | "Cesium": "writable"
60 | },
61 | "rules": {}
62 | },
63 | "browserslist": [
64 | "> 1%",
65 | "last 2 versions",
66 | "not dead",
67 | "not ie 11"
68 | ]
69 | }
70 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/favicon.ico
--------------------------------------------------------------------------------
/public/icons/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/icons/1.png
--------------------------------------------------------------------------------
/public/icons/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/icons/2.png
--------------------------------------------------------------------------------
/public/icons/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/icons/3.png
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
10 | <%= htmlWebpackPlugin.options.title %>
11 |
12 |
13 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/public/model/Duck.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/model/Duck.glb
--------------------------------------------------------------------------------
/public/model/Wood_Tower.glb:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/model/Wood_Tower.glb
--------------------------------------------------------------------------------
/public/model/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/model/default.png
--------------------------------------------------------------------------------
/public/model/tower.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/public/model/tower.png
--------------------------------------------------------------------------------
/release.js:
--------------------------------------------------------------------------------
1 | /*
2 | * @Author: zhangb
3 | * @Date: 2023-05-23 14:18:59
4 | * @E-mail: zhangb@geovis.com.cn
5 | * @LastModifiedBy: zhangb
6 | * @LastEditTime: 2023-05-23 15:56:34
7 | * @Desc:
8 | */
9 | const fs = require('fs')
10 | const path = require('path')
11 | const buildDir = path.join(__dirname, 'dist');
12 | const assets = 'theme';
13 | function remove(url) {
14 | // 读取原路径
15 | const STATUS = fs.statSync(url);
16 | // 如果原路径是文件
17 | if (STATUS.isFile()) {
18 | //删除原文件
19 | fs.unlinkSync(url);
20 |
21 | //如果原路径是目录
22 | } else if (STATUS.isDirectory()) {
23 | //如果原路径是非空目录,遍历原路径
24 | //空目录时无法使用forEach
25 | fs.readdirSync(url).forEach(item => {
26 | //递归调用函数,以子文件路径为新参数
27 | remove(`${url}/${item}`);
28 | });
29 | //删除空文件夹
30 | fs.rmdirSync(url);
31 | };
32 | }
33 |
34 | function release() {
35 | fs.stat(buildDir, function(err, stat) {
36 | if (!err) {
37 | remove(buildDir);
38 | }
39 | fs.mkdirSync(buildDir);
40 | fs.mkdirSync(path.join(buildDir, assets));
41 | fs.mkdirSync(path.join(buildDir, assets, 'img'));
42 | // copy(distDir, buildDir);
43 | // walkFiles(cssDir);
44 | });
45 | }
46 | release()
47 |
48 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
Loading...
6 |
7 |
13 |
14 |
15 |
16 |
129 |
130 |
181 |
187 |
--------------------------------------------------------------------------------
/src/assets/css/demo.css:
--------------------------------------------------------------------------------
1 | /* Logo 字体 */
2 | @font-face {
3 | font-family: "iconfont logo";
4 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834');
5 | src: url('https://at.alicdn.com/t/font_985780_km7mi63cihi.eot?t=1545807318834#iefix') format('embedded-opentype'),
6 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.woff?t=1545807318834') format('woff'),
7 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.ttf?t=1545807318834') format('truetype'),
8 | url('https://at.alicdn.com/t/font_985780_km7mi63cihi.svg?t=1545807318834#iconfont') format('svg');
9 | }
10 |
11 | .logo {
12 | font-family: "iconfont logo";
13 | font-size: 160px;
14 | font-style: normal;
15 | -webkit-font-smoothing: antialiased;
16 | -moz-osx-font-smoothing: grayscale;
17 | }
18 |
19 | /* tabs */
20 | .nav-tabs {
21 | position: relative;
22 | }
23 |
24 | .nav-tabs .nav-more {
25 | position: absolute;
26 | right: 0;
27 | bottom: 0;
28 | height: 42px;
29 | line-height: 42px;
30 | color: #666;
31 | }
32 |
33 | #tabs {
34 | border-bottom: 1px solid #eee;
35 | }
36 |
37 | #tabs li {
38 | cursor: pointer;
39 | width: 100px;
40 | height: 40px;
41 | line-height: 40px;
42 | text-align: center;
43 | font-size: 16px;
44 | border-bottom: 2px solid transparent;
45 | position: relative;
46 | z-index: 1;
47 | margin-bottom: -1px;
48 | color: #666;
49 | }
50 |
51 |
52 | #tabs .active {
53 | border-bottom-color: #f00;
54 | color: #222;
55 | }
56 |
57 | .tab-container .content {
58 | display: none;
59 | }
60 |
61 | /* 页面布局 */
62 | .main {
63 | padding: 30px 100px;
64 | width: 960px;
65 | margin: 0 auto;
66 | }
67 |
68 | .main .logo {
69 | color: #333;
70 | text-align: left;
71 | margin-bottom: 30px;
72 | line-height: 1;
73 | height: 110px;
74 | margin-top: -50px;
75 | overflow: hidden;
76 | *zoom: 1;
77 | }
78 |
79 | .main .logo a {
80 | font-size: 160px;
81 | color: #333;
82 | }
83 |
84 | .helps {
85 | margin-top: 40px;
86 | }
87 |
88 | .helps pre {
89 | padding: 20px;
90 | margin: 10px 0;
91 | border: solid 1px #e7e1cd;
92 | background-color: #fffdef;
93 | overflow: auto;
94 | }
95 |
96 | .icon_lists {
97 | width: 100% !important;
98 | overflow: hidden;
99 | *zoom: 1;
100 | }
101 |
102 | .icon_lists li {
103 | width: 100px;
104 | margin-bottom: 10px;
105 | margin-right: 20px;
106 | text-align: center;
107 | list-style: none !important;
108 | cursor: default;
109 | }
110 |
111 | .icon_lists li .code-name {
112 | line-height: 1.2;
113 | }
114 |
115 | .icon_lists .icon {
116 | display: block;
117 | height: 100px;
118 | line-height: 100px;
119 | font-size: 42px;
120 | margin: 10px auto;
121 | color: #333;
122 | -webkit-transition: font-size 0.25s linear, width 0.25s linear;
123 | -moz-transition: font-size 0.25s linear, width 0.25s linear;
124 | transition: font-size 0.25s linear, width 0.25s linear;
125 | }
126 |
127 | .icon_lists .icon:hover {
128 | font-size: 100px;
129 | }
130 |
131 | .icon_lists .svg-icon {
132 | /* 通过设置 font-size 来改变图标大小 */
133 | width: 1em;
134 | /* 图标和文字相邻时,垂直对齐 */
135 | vertical-align: -0.15em;
136 | /* 通过设置 color 来改变 SVG 的颜色/fill */
137 | fill: currentColor;
138 | /* path 和 stroke 溢出 viewBox 部分在 IE 下会显示
139 | normalize.css 中也包含这行 */
140 | overflow: hidden;
141 | }
142 |
143 | .icon_lists li .name,
144 | .icon_lists li .code-name {
145 | color: #666;
146 | }
147 |
148 | /* markdown 样式 */
149 | .markdown {
150 | color: #666;
151 | font-size: 14px;
152 | line-height: 1.8;
153 | }
154 |
155 | .highlight {
156 | line-height: 1.5;
157 | }
158 |
159 | .markdown img {
160 | vertical-align: middle;
161 | max-width: 100%;
162 | }
163 |
164 | .markdown h1 {
165 | color: #404040;
166 | font-weight: 500;
167 | line-height: 40px;
168 | margin-bottom: 24px;
169 | }
170 |
171 | .markdown h2,
172 | .markdown h3,
173 | .markdown h4,
174 | .markdown h5,
175 | .markdown h6 {
176 | color: #404040;
177 | margin: 1.6em 0 0.6em 0;
178 | font-weight: 500;
179 | clear: both;
180 | }
181 |
182 | .markdown h1 {
183 | font-size: 28px;
184 | }
185 |
186 | .markdown h2 {
187 | font-size: 22px;
188 | }
189 |
190 | .markdown h3 {
191 | font-size: 16px;
192 | }
193 |
194 | .markdown h4 {
195 | font-size: 14px;
196 | }
197 |
198 | .markdown h5 {
199 | font-size: 12px;
200 | }
201 |
202 | .markdown h6 {
203 | font-size: 12px;
204 | }
205 |
206 | .markdown hr {
207 | height: 1px;
208 | border: 0;
209 | background: #e9e9e9;
210 | margin: 16px 0;
211 | clear: both;
212 | }
213 |
214 | .markdown p {
215 | margin: 1em 0;
216 | }
217 |
218 | .markdown>p,
219 | .markdown>blockquote,
220 | .markdown>.highlight,
221 | .markdown>ol,
222 | .markdown>ul {
223 | width: 80%;
224 | }
225 |
226 | .markdown ul>li {
227 | list-style: circle;
228 | }
229 |
230 | .markdown>ul li,
231 | .markdown blockquote ul>li {
232 | margin-left: 20px;
233 | padding-left: 4px;
234 | }
235 |
236 | .markdown>ul li p,
237 | .markdown>ol li p {
238 | margin: 0.6em 0;
239 | }
240 |
241 | .markdown ol>li {
242 | list-style: decimal;
243 | }
244 |
245 | .markdown>ol li,
246 | .markdown blockquote ol>li {
247 | margin-left: 20px;
248 | padding-left: 4px;
249 | }
250 |
251 | .markdown code {
252 | margin: 0 3px;
253 | padding: 0 5px;
254 | background: #eee;
255 | border-radius: 3px;
256 | }
257 |
258 | .markdown strong,
259 | .markdown b {
260 | font-weight: 600;
261 | }
262 |
263 | .markdown>table {
264 | border-collapse: collapse;
265 | border-spacing: 0px;
266 | empty-cells: show;
267 | border: 1px solid #e9e9e9;
268 | width: 95%;
269 | margin-bottom: 24px;
270 | }
271 |
272 | .markdown>table th {
273 | white-space: nowrap;
274 | color: #333;
275 | font-weight: 600;
276 | }
277 |
278 | .markdown>table th,
279 | .markdown>table td {
280 | border: 1px solid #e9e9e9;
281 | padding: 8px 16px;
282 | text-align: left;
283 | }
284 |
285 | .markdown>table th {
286 | background: #F7F7F7;
287 | }
288 |
289 | .markdown blockquote {
290 | font-size: 90%;
291 | color: #999;
292 | border-left: 4px solid #e9e9e9;
293 | padding-left: 0.8em;
294 | margin: 1em 0;
295 | }
296 |
297 | .markdown blockquote p {
298 | margin: 0;
299 | }
300 |
301 | .markdown .anchor {
302 | opacity: 0;
303 | transition: opacity 0.3s ease;
304 | margin-left: 8px;
305 | }
306 |
307 | .markdown .waiting {
308 | color: #ccc;
309 | }
310 |
311 | .markdown h1:hover .anchor,
312 | .markdown h2:hover .anchor,
313 | .markdown h3:hover .anchor,
314 | .markdown h4:hover .anchor,
315 | .markdown h5:hover .anchor,
316 | .markdown h6:hover .anchor {
317 | opacity: 1;
318 | display: inline-block;
319 | }
320 |
321 | .markdown>br,
322 | .markdown>p>br {
323 | clear: both;
324 | }
325 |
326 |
327 | .hljs {
328 | display: block;
329 | background: white;
330 | padding: 0.5em;
331 | color: #333333;
332 | overflow-x: auto;
333 | }
334 |
335 | .hljs-comment,
336 | .hljs-meta {
337 | color: #969896;
338 | }
339 |
340 | .hljs-string,
341 | .hljs-variable,
342 | .hljs-template-variable,
343 | .hljs-strong,
344 | .hljs-emphasis,
345 | .hljs-quote {
346 | color: #df5000;
347 | }
348 |
349 | .hljs-keyword,
350 | .hljs-selector-tag,
351 | .hljs-type {
352 | color: #a71d5d;
353 | }
354 |
355 | .hljs-literal,
356 | .hljs-symbol,
357 | .hljs-bullet,
358 | .hljs-attribute {
359 | color: #0086b3;
360 | }
361 |
362 | .hljs-section,
363 | .hljs-name {
364 | color: #63a35c;
365 | }
366 |
367 | .hljs-tag {
368 | color: #333333;
369 | }
370 |
371 | .hljs-title,
372 | .hljs-attr,
373 | .hljs-selector-id,
374 | .hljs-selector-class,
375 | .hljs-selector-attr,
376 | .hljs-selector-pseudo {
377 | color: #795da3;
378 | }
379 |
380 | .hljs-addition {
381 | color: #55a532;
382 | background-color: #eaffea;
383 | }
384 |
385 | .hljs-deletion {
386 | color: #bd2c00;
387 | background-color: #ffecec;
388 | }
389 |
390 | .hljs-link {
391 | text-decoration: underline;
392 | }
393 |
394 | /* 代码高亮 */
395 | /* PrismJS 1.15.0
396 | https://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript */
397 | /**
398 | * prism.js default theme for JavaScript, CSS and HTML
399 | * Based on dabblet (http://dabblet.com)
400 | * @author Lea Verou
401 | */
402 | code[class*="language-"],
403 | pre[class*="language-"] {
404 | color: black;
405 | background: none;
406 | text-shadow: 0 1px white;
407 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
408 | text-align: left;
409 | white-space: pre;
410 | word-spacing: normal;
411 | word-break: normal;
412 | word-wrap: normal;
413 | line-height: 1.5;
414 |
415 | -moz-tab-size: 4;
416 | -o-tab-size: 4;
417 | tab-size: 4;
418 |
419 | -webkit-hyphens: none;
420 | -moz-hyphens: none;
421 | -ms-hyphens: none;
422 | hyphens: none;
423 | }
424 |
425 | pre[class*="language-"]::-moz-selection,
426 | pre[class*="language-"] ::-moz-selection,
427 | code[class*="language-"]::-moz-selection,
428 | code[class*="language-"] ::-moz-selection {
429 | text-shadow: none;
430 | background: #b3d4fc;
431 | }
432 |
433 | pre[class*="language-"]::selection,
434 | pre[class*="language-"] ::selection,
435 | code[class*="language-"]::selection,
436 | code[class*="language-"] ::selection {
437 | text-shadow: none;
438 | background: #b3d4fc;
439 | }
440 |
441 | @media print {
442 |
443 | code[class*="language-"],
444 | pre[class*="language-"] {
445 | text-shadow: none;
446 | }
447 | }
448 |
449 | /* Code blocks */
450 | pre[class*="language-"] {
451 | padding: 1em;
452 | margin: .5em 0;
453 | overflow: auto;
454 | }
455 |
456 | :not(pre)>code[class*="language-"],
457 | pre[class*="language-"] {
458 | background: #f5f2f0;
459 | }
460 |
461 | /* Inline code */
462 | :not(pre)>code[class*="language-"] {
463 | padding: .1em;
464 | border-radius: .3em;
465 | white-space: normal;
466 | }
467 |
468 | .token.comment,
469 | .token.prolog,
470 | .token.doctype,
471 | .token.cdata {
472 | color: slategray;
473 | }
474 |
475 | .token.punctuation {
476 | color: #999;
477 | }
478 |
479 | .namespace {
480 | opacity: .7;
481 | }
482 |
483 | .token.property,
484 | .token.tag,
485 | .token.boolean,
486 | .token.number,
487 | .token.constant,
488 | .token.symbol,
489 | .token.deleted {
490 | color: #905;
491 | }
492 |
493 | .token.selector,
494 | .token.attr-name,
495 | .token.string,
496 | .token.char,
497 | .token.builtin,
498 | .token.inserted {
499 | color: #690;
500 | }
501 |
502 | .token.operator,
503 | .token.entity,
504 | .token.url,
505 | .language-css .token.string,
506 | .style .token.string {
507 | color: #9a6e3a;
508 | background: hsla(0, 0%, 100%, .5);
509 | }
510 |
511 | .token.atrule,
512 | .token.attr-value,
513 | .token.keyword {
514 | color: #07a;
515 | }
516 |
517 | .token.function,
518 | .token.class-name {
519 | color: #DD4A68;
520 | }
521 |
522 | .token.regex,
523 | .token.important,
524 | .token.variable {
525 | color: #e90;
526 | }
527 |
528 | .token.important,
529 | .token.bold {
530 | font-weight: bold;
531 | }
532 |
533 | .token.italic {
534 | font-style: italic;
535 | }
536 |
537 | .token.entity {
538 | cursor: help;
539 | }
540 |
--------------------------------------------------------------------------------
/src/assets/css/iconfont.css:
--------------------------------------------------------------------------------
1 | @font-face {font-family: "cesiumDrawFont";
2 | src: url('iconfont.eot?t=1577957761281'); /* IE9 */
3 | src: url('iconfont.eot?t=1577957761281#iefix') format('embedded-opentype'), /* IE6-IE8 */
4 | url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAxgAAsAAAAAFoAAAAwQAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCESgqdVJZ0ATYCJANECyQABCAFhG0HgTMbMxJRlJBWHNlPTZ6kiFRIBamogCpYK9iXwxX0CRsowKwAAAgCnm318wJQAWsz271K9350p0O4rRsLaqMsPtlXmY2+oJ+YH0ncZlA/ZzTf0fvKZCgvm1kcZlpP5mS/Kin5Jl8tWsdbvMDsCa+ClwqAmf+31urN4c27Dqah0RIhzt+9A+bv7L0bTCyZhAaJkAnJxCOhQiJED6nzCCUCAWsrB7YCxCpO2ezXuTsE4COT9iD9hi45QIJGoaDVtgWsGUhKSegWF4HHYlpW1TnIJAw88igpACfEry++oVZIQGIo1J6mo2k2kPy5/DysPDEPq9RgDtpfBjCaChRQDkCP9L2t1l1BEws3FF9kjGEAJholBTEvIDZqdambZ8olXC/+wTOx8ODFh40fB5cAQYAwUZqD3YvVQcDn0oRAwOcaqQsDiUKYIG3CAkF4QBBeEIQPBGGDIBwQhAuC8IPEIgDiJoIgiBBImwjDIROwrAq5ANYB9Nlg3InS941X9qKQmARB8KEw3jAuJTGL47UK89uTTrY+QibJplQsXuX1+rz5+SQpNHcJKLSKI0k9RVjjF6ltKsbm4qT2CqgZ43aRn0wyPJ5dxuhRxA8yWJWbX+A6mubL3J4ChcmTWJIr5ucV5BfYrq5j/fXI6qvza2+lzP1vGdkw/ngtZ9Fqx5+vr0enmqyFsSvKjYUQZ9Py0wB5oMVEK6E9btmu0acoXQO9nIKxMMloY8ckBgsKTPafShJZCWNlz8jEGahM/3U0CegDz4rg1FtPioSVmEhF4WRUIByegBI6JQR9hrKPjgwonkw7KbJ5Z47KMoUyhI0JkpL7pPgKanwmiuDt/d7I/IP2YIkBXAQDzmmkLuwFjhZZ/9l26FuKoKZXdPipzMDJpUIIujmbP/EMJAQHmQHeVzBEghVoSFySv6NYOu6VFCnGO4Y07CnrJEPCSn2h5GdKZMi1kSh62fyBaHa2Ot22lT1pslox5XBhYZFdeGxMjJ/m79OQwhqGDsZwaLMTYq4cuWOLSUuKZV01fX6mqFAMA1qasaekSAoYCgZocYnSwdZVUrH22vwTm2z19cjGG4urry6svebLNxYf43ukDq2l/Xojb8m64fur2X10G0IuJFiArmwtvKGEC53BmsWaJ5Fut3tHgR3TSQmtOLJPYjJJLkwqSWqMUC1nCEyRxB6QLNitk3njRsW6SEhptrzSlihno3EqT9vn8p3MVU/n6/vdwSTx3sLLBq8c3Gp4+RxJ2l1ofh/JdZ1q8jZ1558eCBpMh7oADkxIlBGP0s85EHD44sbqArsohA9wNEXCOO3Mvf7BkkaYc0pE1hL2pCgcTZbvWxaTFPHGNows8R+9sBfYtxLcA6M9URDJMq8SCGbfh6O3ncYbcDoeJj5OSX5y3hlLp8svVIYI9CsrI4X3cGcYzLv3ZsSUc9g7EL4TObl4CNjG/u1z2UhZ1id3OQjKtNiXlLzHSxJ9a2nRT9zIwpN9tzsQdlzAWUxSaF5NTPlXxCoDuezozJTdPzB/RlvcV6k/66SUYJTGO8n1Vq1+OL8amXLo/gVfz+SPISri1xvfeLFonBLWYqYz904n9HDe35fp3+uD/MknD898KxPWn7F3FKxYh/bNX8pYs4WNHs+DKydwpMda2u9BSW1jx172Z94bvXt5b+IxhCCOwkC2aJbagKPvX1mOk5vHj7/pS69xBZEt17ZOPLm0KsVFwbL+wgG5u/3IG4JuXPgtQ2/BtuEbNxZUcy/4qlPYCB2AAfu0mYoceG/zbJ2egqqD+sVqDs7R6800nLoYzlYbVqaOFUmQajfMMaqgGTAlFSrDitQxOncs1O2DqzaVGi7VU3ZmUclJQMsGk8gxaZId0SxkaT1l5cOZjz+a5+geh6enmwYa03FiyDjQlG58f9teh4Kpaqp368Wtcyh1fdWhXS7iRinw4gcP4kRJwN7W4/Y7kfAujYkyokd0krdDyeS2i3BiTwL54rsHbfF2069BXFgyGSaAD1NRPYlSMbUyRIWMzXxyo4PvYeJMpSRLpN7aqMfx1bhJlIyGLxwOop8nF+D4B0W7g94nJcuJ8w1596Ff+xnV5LlhFGi/f7uwHsOlyXtL6Nr4vr5rUXBv71yp58sDPY3+fLMjg8w99OWNC2SjnZQ35aMb8ZJ7H1x16B4HRMozeCtDJHAaSJAcdt7H+Wg3yD+m/LhKTHUjQKleJUm5ysVlfmLN2aPSYgNrAHLLeQ+2xGyaduJQ+6Pad2n7pQ9TT25yNmz5o2Pu304jAjCQUORInXN9g+TjXTOEG1tSX2W/N6iXKFrHsgPVZU1Lj+9E3x8QGwzcL4LJY5qWNisN0SR2yQixTefjmpYltxa8bASMDh70ZjNFTw28Z8Lh2St2hBUVztaoZrMLi8J2rMh6tjw1+H/5CHTVXbLRLpwwHlIj7b1XoiNk9fLl1X3WYXd/cW4Ojdi5c4RqC/XpbewGueSNNy5WtbV+BqPJZDTi+FDM8kn9alu43ycvaN9XxwLCkv/ikPDa6f9kq/+rNH3HXPdMlU1rglrt/x3nJeOx/ifTQanuPfDAvTrpnjd3bkzm7lWruuWA9ev37j14cPvRvgy5vDt527Y1uj1S6TVZwOsdVjffVEHCEoAueb2+/djffz0k7JdAvGzw6G7QjcekJz3gUYuAyNHTX5ekzHjt069pX2RNKSny1Gya8Zah2GIdmn+h1+Tji40UHq+2Fx2SsuT67V9veyPpIr0yjA5TJmuXnNzn9x03aD455uGRWVLtptuXOJg6sGyzWHFkxywdgb/2xiW2lXfqqRXSZOG1N8LeujaXPW65PUW2bL5+invxTLkYuDJ8lFalHVlbW64tr60ZPplaO6pL5xmHSIE69cRFOfURyQoSpP5or8gR5mci8liyUs4ZEiQ1p55aInhCIF7MW2IgC9WS7O2dfjT/kVQr/+A84Hgdxqx10PlgH9M8Fn1f/UDwexWNJzumGTTr+ZL9yy6/ZOF8p27Xpuhdtn9CqFyJJDeZHgW6ulVqXeCMBCKH0hXpFZUqIXdv0OXjF6Ny6sKjbzwlXqwc6RSoCEo3EXtae4Cf2V12f48fCdOHotT1n9DidE7GR1d4fNzg/ImNzqZeSPx9hhgHhrRAn7Y9+TosWPn58PqNO7VMQN62IyS+/GDzDppF3DJa2qNNyogY/falmlq/h/m/7OleXNE9vVdWj6tyX5ExY9DhoYBM8SJn5jae4ypC93WemDBlZHTst1luwTCHujrPwF1VTVsPNu5ZE9mkFXX3jePv3U3Yg8IUvcP6IGwYK9RGw5iWoWFk4NR+7/P2TZ7/er65IfpSXTQszEzFhiXFP52a9PKLfQs7qY7ybO02kvE2w1oN1wsNFXqQ3FxEL2Qt7S3VFZjPogq91SQYOmVaiJNBXb9natQuIgFil3Q+moXXG/WgSqz3Tx2rRDFV1aPTUY+Ly46ij17T1Wu1jZdHI+ogfsiVdOcMVvtweVle7nVfPaRy+c824nEercZkxP7FPlkQpp7ibNz7J7zVAGX8N4/9j7L07bq3D4rBjdQp5UIPEpUtoBcoDdBi8MYv42RySM9TMGLV8CG3buU+icwfY/9Q9+gTYiyIr5CAT5dCDKi8MPePqyc4m/q8ekJOJRYZVOEhn2i7cmpgU09NPHRRH2UY17aJgwNFaC9QynCPCoJspBI/D1BFkHMMht09apDIO2oSFCj1ERE+m7QpFAWyVA6aeWijLRV0gdXlZPxUXpa0zoJsid3MFeNizzzIFReU0iGBwdVaI3RCbh9LFJeyoTzP0AznctAGb2/QbnfRbs5VCK18YD7Pu2ODghjbkoFWlwPI6IMDYoYPA9ugsVARvQArLpwwY/PIai+fBYSlBDtmuJYeF9HzgHAUUzBxmhACCXYgRs3p1OO5dCymFJZQeFHBQMOMWrpwQGMQGRC7rnJB47bPVAjECk8g+VtUuIklSIzEuGqBx9cdr73Gy9er2l5IiIQSWhjCFJbwCK/wCbuPuWXhFwERRNSIBuDbmisgRzjMXBHkCkezQDvBQYerFIrdLnsF63ISNmiHPCTsLusDq8CgrYBvbeg0OyDucNlR4rKMvcAJiQKH28XxBCyPlsOYAjvErS67ixO7Svg/EwEAAAAA') format('woff2'),
5 | url('iconfont.woff?t=1577957761281') format('woff'),
6 | url('iconfont.ttf?t=1577957761281') format('truetype')
7 | }
8 |
9 | .cesiumDrawFont {
10 | font-family: "cesiumDrawFont" !important;
11 | font-size: 16px;
12 | font-style: normal;
13 | -webkit-font-smoothing: antialiased;
14 | -moz-osx-font-smoothing: grayscale;
15 | }
16 |
17 | .iconlayer:before {
18 | content: "\e602";
19 | }
20 |
21 | .iconmarker:before {
22 | content: "\e604";
23 | }
24 |
25 | .iconlabel:before {
26 | content: "\e605";
27 | }
28 |
29 | .iconremove:before {
30 | content: "\e606";
31 | }
32 |
33 | .iconpolygon:before {
34 | content: "\e607";
35 | }
36 |
37 | .icondelete:before {
38 | content: "\e608";
39 | }
40 |
41 | .iconlocate:before {
42 | content: "\e609";
43 | }
44 |
45 | .iconedit:before {
46 | content: "\e60a";
47 | }
48 |
49 | .iconrename:before {
50 | content: "\e60b";
51 | }
52 |
53 | .iconmodel:before {
54 | content: "\e60c";
55 | }
56 |
57 | .iconpolyline:before {
58 | content: "\e60d";
59 | }
60 |
61 | .iconimport:before {
62 | content: "\e60f";
63 | }
64 |
65 | .iconexport:before {
66 | content: "\e610";
67 | }
68 |
69 | .iconfile:before {
70 | content: "\e60e";
71 | }
72 |
73 | .iconcolor:before {
74 | content: "\e611";
75 | }
76 |
77 | .iconoutline:before {
78 | content: "\e612";
79 | }
80 |
81 |
--------------------------------------------------------------------------------
/src/assets/css/iconfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/css/iconfont.eot
--------------------------------------------------------------------------------
/src/assets/css/iconfont.js:
--------------------------------------------------------------------------------
1 | !function(m){var c,o='',a=(c=document.getElementsByTagName("script"))[c.length-1].getAttribute("data-injectcss");if(a&&!m.__iconfont__svg__cssinject__){m.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(c){console&&console.log(c)}}!function(c){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(c,0);else{var a=function(){document.removeEventListener("DOMContentLoaded",a,!1),c()};document.addEventListener("DOMContentLoaded",a,!1)}else document.attachEvent&&(l=c,e=m.document,h=!1,(o=function(){try{e.documentElement.doScroll("left")}catch(c){return void setTimeout(o,50)}t()})(),e.onreadystatechange=function(){"complete"==e.readyState&&(e.onreadystatechange=null,t())});function t(){h||(h=!0,l())}var l,e,h,o}(function(){var c,a,t,l,e,h;(c=document.createElement("div")).innerHTML=o,o=null,(a=c.getElementsByTagName("svg")[0])&&(a.setAttribute("aria-hidden","true"),a.style.position="absolute",a.style.width=0,a.style.height=0,a.style.overflow="hidden",t=a,(l=document.body).firstChild?(e=t,(h=l.firstChild).parentNode.insertBefore(e,h)):l.appendChild(t))})}(window);
--------------------------------------------------------------------------------
/src/assets/css/iconfont.json:
--------------------------------------------------------------------------------
1 | {
2 | "id": "1590177",
3 | "name": "my-project",
4 | "font_family": "iconfont",
5 | "css_prefix_text": "icon",
6 | "description": "",
7 | "glyphs": [
8 | {
9 | "icon_id": "12597587",
10 | "name": "layer",
11 | "font_class": "layer",
12 | "unicode": "e602",
13 | "unicode_decimal": 58882
14 | },
15 | {
16 | "icon_id": "12597662",
17 | "name": "marker",
18 | "font_class": "marker",
19 | "unicode": "e604",
20 | "unicode_decimal": 58884
21 | },
22 | {
23 | "icon_id": "12597676",
24 | "name": "label",
25 | "font_class": "label",
26 | "unicode": "e605",
27 | "unicode_decimal": 58885
28 | },
29 | {
30 | "icon_id": "12597679",
31 | "name": "remove",
32 | "font_class": "remove",
33 | "unicode": "e606",
34 | "unicode_decimal": 58886
35 | },
36 | {
37 | "icon_id": "12597688",
38 | "name": "polygon",
39 | "font_class": "polygon",
40 | "unicode": "e607",
41 | "unicode_decimal": 58887
42 | },
43 | {
44 | "icon_id": "12597851",
45 | "name": "删除/数字面板编辑态",
46 | "font_class": "delete",
47 | "unicode": "e608",
48 | "unicode_decimal": 58888
49 | },
50 | {
51 | "icon_id": "12597852",
52 | "name": "复位",
53 | "font_class": "locate",
54 | "unicode": "e609",
55 | "unicode_decimal": 58889
56 | },
57 | {
58 | "icon_id": "12597853",
59 | "name": "编辑",
60 | "font_class": "edit",
61 | "unicode": "e60a",
62 | "unicode_decimal": 58890
63 | },
64 | {
65 | "icon_id": "12597854",
66 | "name": "重命名",
67 | "font_class": "rename",
68 | "unicode": "e60b",
69 | "unicode_decimal": 58891
70 | },
71 | {
72 | "icon_id": "12597984",
73 | "name": "model",
74 | "font_class": "model",
75 | "unicode": "e60c",
76 | "unicode_decimal": 58892
77 | },
78 | {
79 | "icon_id": "12597985",
80 | "name": "polyline",
81 | "font_class": "polyline",
82 | "unicode": "e60d",
83 | "unicode_decimal": 58893
84 | },
85 | {
86 | "icon_id": "12598030",
87 | "name": "import",
88 | "font_class": "import",
89 | "unicode": "e60f",
90 | "unicode_decimal": 58895
91 | },
92 | {
93 | "icon_id": "12598051",
94 | "name": "export (1)",
95 | "font_class": "export",
96 | "unicode": "e610",
97 | "unicode_decimal": 58896
98 | },
99 | {
100 | "icon_id": "12598567",
101 | "name": "文件",
102 | "font_class": "file",
103 | "unicode": "e60e",
104 | "unicode_decimal": 58894
105 | },
106 | {
107 | "icon_id": "12598568",
108 | "name": "颜色选择器 (1)",
109 | "font_class": "color",
110 | "unicode": "e611",
111 | "unicode_decimal": 58897
112 | },
113 | {
114 | "icon_id": "12636469",
115 | "name": "边框",
116 | "font_class": "outline",
117 | "unicode": "e612",
118 | "unicode_decimal": 58898
119 | }
120 | ]
121 | }
122 |
--------------------------------------------------------------------------------
/src/assets/css/iconfont.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
75 |
--------------------------------------------------------------------------------
/src/assets/css/iconfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/css/iconfont.ttf
--------------------------------------------------------------------------------
/src/assets/css/iconfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/css/iconfont.woff
--------------------------------------------------------------------------------
/src/assets/css/iconfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/css/iconfont.woff2
--------------------------------------------------------------------------------
/src/assets/css/theme/dark.scss:
--------------------------------------------------------------------------------
1 | $bg-color:#171E26;
2 | $color:#3A89DD;
3 | $color-l:#C7E9FA;
4 | $font-color:$color;
5 | $selected-color:#409EFF;
6 | $border-color:#E4E7ED;
7 | $devision-color:#DCDFE6;
8 | $b-radius:4px;
9 | $draw-panel-width:400px;
10 | $hover-color:#409EFF;
11 | $title-height:32px;
12 | $item-margin:0 5px;
13 | $item-height:40px;
14 | $padding:0 5px;
15 | $font-size:12px;
16 | //跟随鼠标的提示信息
17 | .cursor-tip-class{
18 | position : fixed;
19 | // border : 1px $border-color solid;
20 | height : 30px;
21 | line-height : 30px;
22 | padding-left : 10px;
23 | padding-right : 20px;
24 | background-color : $bg-color;
25 | color : $font-color;
26 | border-radius : $b-radius;
27 | pointer-events : none;
28 | z-index : 999;
29 | min-width: 150px;
30 | font-size: $font-size;
31 | }
32 | //关闭按钮
33 | .closebtn{
34 | text-align: center;
35 | display: inline-block!important;
36 | font-size: $font-size;
37 | color:$color;
38 | // margin-top: 13px!important;
39 | // margin-right: 13px!important;
40 | cursor: pointer;
41 | float: right;
42 | &:hover {
43 | color: #FF0000;
44 | }
45 | }
46 | //滚动条
47 | *{
48 | &::-webkit-scrollbar {
49 | /*滚动条整体样式*/
50 | width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
51 | height: 1px;
52 | }
53 | &::-webkit-scrollbar-thumb {
54 | /*滚动条里面小方块*/
55 | border-radius: 2px;
56 | box-shadow: inset 0 0 2px $color;
57 | background: $color;
58 | }
59 | &::-webkit-scrollbar-track {
60 | /*滚动条里面轨道*/
61 | box-shadow: inset 0 0 2px $bg-color;
62 | border-radius: 2px;
63 | background: $bg-color;
64 | }
65 | }
66 | //气泡
67 | .marker-popWin-class {
68 | min-width: 200px;
69 | height: 73px;
70 | position: fixed;
71 | color: $font-color;
72 | background-color: $bg-color;
73 | text-align: left;
74 | border-radius: $b-radius;
75 | font-size: $font-size;
76 | visibility: visible;
77 | // border: 1px solid $border-color;
78 | box-sizing: border-box;
79 | padding: 0 12px;
80 | span{
81 | margin-top: 12px;
82 | display: block;
83 | }
84 | .arrow {
85 | position: absolute;
86 | top: 73px;
87 | left: 0px;
88 | width: 0px;
89 | height: 0px;
90 | left: 50%;
91 | transform: translate(-50%, 0);
92 | border-width: 10px;
93 | border-style: solid;
94 | border-color: $bg-color transparent transparent transparent;
95 | }
96 | }
97 |
98 |
--------------------------------------------------------------------------------
/src/assets/css/theme/default.scss:
--------------------------------------------------------------------------------
1 | $bg-color:#FFFFFF;
2 | $color:#000000;
3 | $color-l:#C7E9FA;
4 | $font-color:#000000;
5 | $selected-color:#409EFF;
6 | $border-color:#E4E7ED;
7 | $devision-color:#DCDFE6;
8 | $b-radius:4px;
9 | $draw-panel-width:400px;
10 | $hover-color:#409EFF;
11 | $title-height:32px;
12 | $item-margin:0 5px;
13 | $item-height:40px;
14 | $padding:0 5px;
15 | $font-size:12px;
16 | //跟随鼠标的提示信息
17 | .cursor-tip-class{
18 | position : fixed;
19 | // border : 1px $border-color solid;
20 | height : 30px;
21 | line-height : 30px;
22 | padding-left : 10px;
23 | padding-right : 20px;
24 | background-color : $bg-color;
25 | color : $font-color;
26 | border-radius : $b-radius;
27 | pointer-events : none;
28 | z-index : 999;
29 | min-width: 150px;
30 | font-size: $font-size;
31 | }
32 | //关闭按钮
33 | .closebtn{
34 | text-align: center;
35 | display: inline-block!important;
36 | font-size: $font-size;
37 | color:$color;
38 | // margin-top: 13px!important;
39 | // margin-right: 13px!important;
40 | cursor: pointer;
41 | float: right;
42 | &:hover {
43 | color: #FF0000;
44 | }
45 | }
46 | //滚动条
47 | *{
48 | &::-webkit-scrollbar {
49 | /*滚动条整体样式*/
50 | width: 5px; /*高宽分别对应横竖滚动条的尺寸*/
51 | height: 1px;
52 | }
53 | &::-webkit-scrollbar-thumb {
54 | /*滚动条里面小方块*/
55 | border-radius: 2px;
56 | box-shadow: inset 0 0 2px $color;
57 | background: $color;
58 | }
59 | &::-webkit-scrollbar-track {
60 | /*滚动条里面轨道*/
61 | box-shadow: inset 0 0 2px $bg-color;
62 | border-radius: 2px;
63 | background: $bg-color;
64 | }
65 | }
66 | //气泡
67 | .marker-popWin-class {
68 | min-width: 200px;
69 | height: 73px;
70 | position: fixed;
71 | color: $font-color;
72 | background-color: $bg-color;
73 | text-align: left;
74 | border-radius: $b-radius;
75 | font-size: $font-size;
76 | visibility: visible;
77 | // border: 1px solid $border-color;
78 | box-sizing: border-box;
79 | padding: 0 12px;
80 | span{
81 | margin-top: 12px;
82 | display: block;
83 | }
84 | .arrow {
85 | position: absolute;
86 | top: 73px;
87 | left: 0px;
88 | width: 0px;
89 | height: 0px;
90 | left: 50%;
91 | transform: translate(-50%, 0);
92 | border-width: 10px;
93 | border-style: solid;
94 | border-color: $bg-color transparent transparent transparent;
95 | }
96 | }
97 |
--------------------------------------------------------------------------------
/src/assets/images/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/0.png
--------------------------------------------------------------------------------
/src/assets/images/icon/file.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/icon/file.png
--------------------------------------------------------------------------------
/src/assets/images/icon/label.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/icon/label.png
--------------------------------------------------------------------------------
/src/assets/images/icon/marker.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/icon/marker.png
--------------------------------------------------------------------------------
/src/assets/images/icon/polygon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/icon/polygon.png
--------------------------------------------------------------------------------
/src/assets/images/icon/polyline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/icon/polyline.png
--------------------------------------------------------------------------------
/src/assets/images/nothmub.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/images/nothmub.jpg
--------------------------------------------------------------------------------
/src/assets/js/iconfont.js:
--------------------------------------------------------------------------------
1 | !function(d){var l,a='',i=(l=document.getElementsByTagName("script"))[l.length-1].getAttribute("data-injectcss");if(i&&!d.__iconfont__svg__cssinject__){d.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(l){console&&console.log(l)}}!function(l){if(document.addEventListener)if(~["complete","loaded","interactive"].indexOf(document.readyState))setTimeout(l,0);else{var i=function(){document.removeEventListener("DOMContentLoaded",i,!1),l()};document.addEventListener("DOMContentLoaded",i,!1)}else document.attachEvent&&(h=l,o=d.document,e=!1,(a=function(){try{o.documentElement.doScroll("left")}catch(l){return void setTimeout(a,50)}t()})(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,t())});function t(){e||(e=!0,h())}var h,o,e,a}(function(){var l,i,t,h,o,e;(l=document.createElement("div")).innerHTML=a,a=null,(i=l.getElementsByTagName("svg")[0])&&(i.setAttribute("aria-hidden","true"),i.style.position="absolute",i.style.width=0,i.style.height=0,i.style.overflow="hidden",t=i,(h=document.body).firstChild?(o=t,(e=h.firstChild).parentNode.insertBefore(o,e)):h.appendChild(t))})}(window);
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xtfge/cesium-draw/dc5b3d87046b176666bc30eebf93c830e8d2ea33/src/assets/logo.png
--------------------------------------------------------------------------------
/src/cdn.js:
--------------------------------------------------------------------------------
1 | import _Vue from 'vue'
2 | import drawViewer from './components/cesiumDrawViewer'
3 | import "@/assets/css/iconfont.css"
4 |
5 | drawViewer.install = Vue => {
6 | if (!Vue) {
7 | window.Vue = Vue = _Vue;
8 | }
9 | Vue.component(drawViewer.name, drawViewer)
10 | }
11 |
12 | if (typeof window !== 'undefined' && window.Vue) {
13 | drawViewer.install(window.Vue)
14 | }
15 | export default drawViewer
16 |
--------------------------------------------------------------------------------
/src/components/layerManager.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 | 导入
12 |
13 |
14 |
15 |
16 |
17 | 导出
18 |
19 |
20 |
21 |
22 | 标记
24 | 线
26 | 多边形
28 | 书签
30 |
31 |
32 |
33 |
34 | 清空
35 |
36 |
37 |
38 |
41 |
42 |
43 |
44 |
46 | {{ data.text }}
47 |
48 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
238 |
359 |
381 |
--------------------------------------------------------------------------------
/src/components/markerViewer.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
11 |
21 |
22 | 选取文件
23 |
24 | 上传到服务器
31 |
32 |
33 |
34 |
35 |
36 | 添加标记
37 |
44 |
48 |
49 |
50 |
51 |
52 |
60 |
64 |
65 |
66 |
67 |
68 | 更换
69 |
70 |
71 |
72 | 删除
80 | 确定
88 |
89 |
90 |
91 |
92 |
93 |
99 |
100 |
101 |
107 |
112 | 确定
115 |
116 |
123 |
124 |
125 |
126 |
387 |
388 |
703 |
--------------------------------------------------------------------------------
/src/core/Graphic.js:
--------------------------------------------------------------------------------
1 | import GraphicType from "./GraphicType";
2 | import * as Cesium from 'cesium'
3 | const console = window.console;
4 | import {
5 | CVT
6 | } from '@/js/utils';
7 | class BaseGraphic {
8 | constructor(viewer) {
9 | if (viewer instanceof Cesium.Viewer === false) {
10 | throw new Error('viewer不是一个有效的Cesium Viewer对象.')
11 | }
12 | this.viewer = viewer
13 | this._type = undefined
14 | this._gvtype = undefined;
15 | this._gvid = undefined;
16 | this._name = undefined;
17 | this._attachment = []
18 | }
19 | get attachment() {
20 | return this._attachment
21 | }
22 | set attachment(v) {
23 | this._attachment = v
24 | }
25 | get type() {
26 | return this._type;
27 | }
28 | get mtype() {
29 | return this._gvtype
30 | }
31 | set mtype(v) {
32 | this._gvtype = v;
33 | }
34 | get mid() {
35 | return this._gvid;
36 | }
37 | set mid(v) {
38 | this._gvid = v;
39 | if (this.graphic) {
40 | this.graphic.mid = this._gvid
41 | }
42 | }
43 | get mname() {
44 | return this._name
45 | }
46 | set mname(v) {
47 | this._name = v;
48 | if (this.graphic) {
49 | this.graphic.mname = this.mname;
50 | if (this.graphic.label) {
51 | this.graphic.label.text = v;
52 | }
53 | }
54 | }
55 | get show() {
56 | if (this.graphic) {
57 | return this.graphic.show
58 | }
59 | return false
60 | }
61 | set show(v) {
62 | if (this.graphic) {
63 | this.graphic.show = v
64 | }
65 | }
66 | zoomTo() {
67 | if (this.graphic) {
68 | this.viewer.flyTo(this.graphic)
69 | }
70 | }
71 | coordinates() {
72 | if (this.position instanceof Cesium.Cartesian3) {
73 | const coor = CVT.cartesian2Degrees(this.position, this.viewer)
74 | return [coor.lon, coor.lat, coor.height]
75 | } else if (this.positions instanceof Array) {
76 | const pts = []
77 | for (let p of this.positions) {
78 | const c = CVT.cartesian2Degrees(p, this.viewer)
79 | pts.push([c.lon, c.lat, c.height])
80 | }
81 | if (this.type === 'POLYLINE') {
82 | return pts
83 | } else {
84 | return [pts]
85 | }
86 |
87 | }
88 | }
89 | toGeoJson() {
90 | const type = {
91 | 'MARKER': 'Point',
92 | 'POLYLINE': 'LineString',
93 | 'POLYGON': 'POLYGON',
94 | 'LABEL': 'Point'
95 | }
96 | return {
97 | "type": "Feature",
98 | "properties": {
99 | name: this.mname,
100 | mtype: this.mtype
101 | },
102 | "geometry": {
103 | "type": type[this.type],
104 | "coordinates": this.coordinates()
105 | }
106 | }
107 |
108 | }
109 | }
110 | class CesiumBillboard extends BaseGraphic {
111 | /**
112 | * Cesium Marker
113 | * @param {Viewer} viewer Cesium Viewer
114 | * @param {*} options describles a billboard.
115 | * 遵循和Cesium BillboardGraphic相同的方式.
116 | */
117 | constructor(viewer, options, labelOption = CesiumBillboard.defaultLabelStyle) {
118 | super(viewer);
119 | this.viewer = viewer;
120 | this._type = 'MARKER';
121 | this.mtype = GraphicType.MARKER;
122 | this.position = options.position;
123 | options.image = options.image || CesiumBillboard.defaultStyle.image;
124 |
125 | labelOption.text = options.label;
126 | this.labelOptions = labelOption;
127 | const self = this;
128 | this.options = {
129 | mname: this._name,
130 | mtype: this.mtype,
131 | mid: this.mid,
132 | position: self.position,
133 | billboard: options,
134 | label: labelOption
135 | }
136 | this.graphic = undefined;
137 | this.name = '';
138 | this.description = '';
139 | this.create();
140 | }
141 |
142 | get text() {
143 | return this.graphic.label.text
144 | }
145 | set text(v) {
146 | this.graphic.label.text = v
147 | this.mname = v
148 | }
149 |
150 | get font() {
151 | return this.graphic.label.font.getValue(this.viewer.clock.currentTime)
152 | }
153 | set font(font) {
154 | this.graphic.label.font = font
155 | }
156 | get color() {
157 | return this.graphic.label.fillColor
158 | }
159 | set color(color) {
160 | this.graphic.label.fillColor = color
161 | }
162 | /**
163 | *
164 | * @param {*} option 定义一个LabelGraphic
165 | */
166 | setLabel(option) {
167 | if (!this.graphic) {
168 | return
169 | }
170 | const keys = Object.keys(option)
171 | for (let key of keys) {
172 | this.graphic.label[key] = option[key]
173 | }
174 | }
175 | create() {
176 | this.graphic = this.viewer.entities.add(this.options);
177 | }
178 | remove() {
179 | if (this.viewer) {
180 | this.viewer.entities.remove(this.graphic);
181 | }
182 | this.graphic = undefined;
183 | }
184 | updateText(text, description) {
185 | if (this.graphic) {
186 | this.graphic.label.text = text;
187 | this.name = text;
188 | this.description = description;
189 | this.mname = text
190 | }
191 | }
192 | updateImage(img) {
193 | if (this.graphic) {
194 | if (img === undefined) {
195 | this.graphic.label.pixelOffset = undefined
196 | this.graphic.billboard.image = undefined
197 | } else {
198 | this.graphic.label.pixelOffset = this.labelOptions.pixelOffset
199 | this.graphic.billboard.image = img;
200 | }
201 | }
202 | }
203 | updatePosition(position) {
204 | this.position = position;
205 | }
206 | stopEdit() {
207 | if (this.graphic && this.graphic.position) {
208 | this.graphic.position = new Cesium.ConstantProperty(this.position)
209 | }
210 | }
211 | startEdit() {
212 | const self = this;
213 | if (this.graphic) {
214 | this.graphic.position = new Cesium.CallbackProperty(function() {
215 | return self.position;
216 | }, false)
217 | }
218 | }
219 | destroy() {
220 | this.remove();
221 | this.viewer = undefined;
222 | this.options = undefined;
223 | this.position = undefined;
224 | }
225 | static fromDegrees(viewer, position) {
226 | const option = CesiumBillboard.defaultStyle;
227 | option.position = Cesium.Cartesian3.fromDegrees(position.lon, position.lat, position.height)
228 | return new CesiumBillboard(viewer, option);
229 | }
230 | static fromRadians(viewer, position) {
231 | const option = CesiumBillboard.defaultStyle;
232 | option.position = Cesium.Cartesian3.fromRadians(position.lon, position.lat, position.height)
233 | return new CesiumBillboard(viewer, option);
234 | }
235 |
236 | static defaultStyle = {
237 | image: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTQ1IDc5LjE2MzQ5OSwgMjAxOC8wOC8xMy0xNjo0MDoyMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTkgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkJEN0VBRDA0MzJCRTExRUE5MjY2QTg3OUVFNjUyQzhCIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkJEN0VBRDA1MzJCRTExRUE5MjY2QTg3OUVFNjUyQzhCIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QkQ3RUFEMDIzMkJFMTFFQTkyNjZBODc5RUU2NTJDOEIiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QkQ3RUFEMDMzMkJFMTFFQTkyNjZBODc5RUU2NTJDOEIiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz6qzlgwAAADR0lEQVR42uxXTUhUURQ+88aZ93JSZyiDCCkt+0VLtGzRn/QntotMoqBEol1Ui9JVtNCsoKJNSFgQREjRKiXF/mxToIQK2YBZIRKlaE1pb+Y5M33n+dRJfTN3ZoLZdOG7986dc75z5v6cc8YSDAYpkU2iBLeEO5AUpfxy4BCwHVgLLDTWh4B3wEvgPvBBlNAy1x1w3fP89XnkcOoyDJeBA6wTgZMJHwJnwfNpBk/0DkCpFEM9kKL6iR591qixX6OukQB9+x3QZRbNkyjXJdG+DBvtX2ojxaov/wQqwPUgZgegUIHhFss19o9TVYdK/aOBsD8/wyHRxXwFziRN7sZx8NWbOWB6CSFchKGOjZ9/q9KRtrGIxrmxDMuyjnFcdQaX+B3g7QZ6gCWXur1U2+WN6YZX5sp0Lkfm6YBxaT2iO3CKjbcP+elKtzfmJ8a6zMFcwGnRHVB4J/mJFbeM0ptBf1zvvDDdSk/2OCafagagRtqBvWy8c9gft3FuzMFcRswoFjmC3dy1DIybktqhVVugUF9pCn0EeG4PE1NDuHaJOFDA3auv5r/+Qp5CJ1bZyWW3kBPgedV62VQ+hGujiANZ3Lk95g6UZdlmrR1dYTeVD+HKFHHAyd2w+u/SdAiXS8QBXVpJMg/5DX3arLW7vZqpvGyd4lJFHOCsRuuc5reKo1yd20fffUEdPK/pVE3lc1xTXL0i6fgxsKEs02b6DH2IyJXtqg6RdjDTFsodMRAtBvq8AVJ2NP2i9z8CcZ3/6jSJXpTMJ1nSt58v+JdIR8AC1VCg21uSKdVmidk469aDQ56wUj3TeLhkxHvWCmx7jWMoez5GHi0YtfGGomTanK4XB21GENKEkhHyt2ZUP24maC120Mo08fKRZVnHMO5mLoNTvB6AwiCGnZyWs1MlegbC8mx72HqMvzuGgMSyrIPWzRwGV/RVMRQ5j2/laOpAXLi6SaEmZLb8BdZZsrzG310rVMgxEUOesq7BEXdRynG2Bjij66BrQol2o2eiVji5RqYSlGCW6UB2nesR8PjiLkpnEHCqvmM8VTJ5QeXQbzbRnyPuwoEo4QRuAv7gdPMba85o+WJxYBJ5QDPQYsxj4rH8/3OaaAf+CDAAVvn1VEy/MOwAAAAASUVORK5CYII=',
238 | verticalOrigin: Cesium.VerticalOrigin.BASELINE
239 | }
240 | static defaultLabelStyle = {
241 | font: '28px sans-serif',
242 | fillColor: Cesium.Color.WHITE,
243 | showBackground: true,
244 | style: Cesium.LabelStyle.FILL_AND_OUTLINE,
245 | // outlineWidth: 2,
246 | verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
247 | pixelOffset: new Cesium.Cartesian2(0, 40),
248 | heightReference: Cesium.HeightReference.NONE,
249 | horizontalOrigin: Cesium.HorizontalOrigin.CENTER
250 | }
251 | }
252 | class CesiumPoint extends BaseGraphic {
253 | /**
254 | * Cesium PointGraphic
255 | * @param {Viewer} viewer Cesium.Viewer
256 | * @param {Object} options Describes a point. positions定义它的位置信息
257 | * (positions为数组将同时创建多个Point),
258 | * 属性信息的定义和Cesium.PointGraphics相同
259 | */
260 | constructor(viewer, options = CesiumPoint.defaultStyle) {
261 | super(viewer);
262 | this._type = 'POINT';
263 | this.mtype = GraphicType.POINT;
264 | //allow mutiple to be created points at one time
265 | this.positions = options.positions;
266 | //only one point
267 | const self = this;
268 | if (this.positions instanceof Cesium.Cartesian3) {
269 | this.options = {
270 | mname: this._name,
271 | mid: this._gvid,
272 | mtype: this._gvtype,
273 | position: new Cesium.CallbackProperty(function() {
274 | return self.positions;
275 | }, false),
276 | point: options
277 | }
278 | }
279 | //mutiple points
280 | else if (this.positions instanceof Array) {
281 | this.options = [];
282 | for (let i = 0; i < this.positions.length; i++) {
283 | const point = {
284 | mname: this._name,
285 | mid: this._gvid,
286 | mtype: this._gvtype,
287 | position: new Cesium.CallbackProperty(function() {
288 | return self.positions[i];
289 | }, false),
290 | point: options
291 | }
292 | this.options.push(point);
293 | }
294 | } else {
295 | throw new Error('options参数错误.');
296 | }
297 | this.graphic = [];
298 | this.create();
299 |
300 |
301 | }
302 |
303 | create() {
304 | if (this.options instanceof Array) {
305 | this.graphic = this.options.map(_ => {
306 | const entity = this.viewer.entities.add(_);
307 | return entity
308 | })
309 | } else {
310 | this.graphic = this.viewer.entities.add(this.options);
311 | }
312 | }
313 | remove() {
314 | if (this.graphic instanceof Array) {
315 | this.graphic.map(_ => {
316 | this.viewer.entities.remove(_);
317 | })
318 | } else {
319 | this.viewer.entities.remove(this.graphic);
320 | }
321 | this.graphic = undefined;
322 | }
323 | startEdit() {
324 | if (this.graphic instanceof Cesium.Entity) {
325 | this.graphic.position = new Cesium.CallbackProperty(() => {
326 | return this.positions;
327 | }, false)
328 | } else if (this.graphic instanceof Array) {
329 | const count = this.graphic.length
330 | for (let i = 0; i < count; i++) {
331 | this.graphic[i].position = new Cesium.CallbackProperty(() => {
332 | return this.positions[i];
333 | }, false)
334 | }
335 | }
336 | }
337 | /**
338 | * 在确定点的位置之后,将CallBackProperty重置为一个普通对象
339 | * 因为当点足够多时,CallBackProperty会在一定程度上影响系统性能,
340 | * 后面的Polyline,Polygon也是出于同样的考虑
341 | * ps:后来我发现并没有必要,因为Entity会强制转为Property
342 | */
343 | stopEdit() {
344 | if (this.graphic instanceof Cesium.Entity) {
345 | this.graphic.position = this.graphic.position.getValue(this.viewer.clock.currentTime);
346 | } else if (this.graphic instanceof Array) {
347 | this.graphic = this.graphic.map(_ => {
348 | return _.position = _.position.getValue(this.viewer.clock.currentTime);
349 | })
350 | }
351 | }
352 |
353 | /**
354 | * 判断两个点是否在同一位置
355 | * @param {*} node1
356 | * @param {*} node2
357 | */
358 | static equalPosition(node1, node2) {
359 | if (!(node1 instanceof Cesium.Cartesian3 && node2 instanceof Cesium.Cartesian3)) {
360 | throw new Error('node不是一个有效的Cartesian3对象')
361 | }
362 | return (node1.x === node2.x &&
363 | node1.y === node2.y &&
364 | node1.z === node2.z)
365 | }
366 | static setStyle(node, option) {
367 | const keys = Object.keys(option)
368 | for (let key of keys) {
369 | node.point[key] = option[key]
370 | }
371 | }
372 | contain(node) {
373 | if (this.graphic instanceof Cesium.Cartesian3) {
374 | return this.graphic === node
375 | } else if (this.graphic instanceof Array) {
376 | const count = this.graphic.length
377 | for (let i = 0; i < count; i++) {
378 | if (this.graphic[i] === node) {
379 | return i
380 | }
381 | }
382 | }
383 | return -1
384 | }
385 | static defaultStyle = {
386 | color: Cesium.Color.RED,
387 | pixelSize: 5,
388 | outlineColor: Cesium.Color.WHITE,
389 | outlineWidth: 3,
390 | heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
391 | }
392 | static editStyle = {
393 | color: Cesium.Color.RED,
394 | pixelSize: 5,
395 | outlineColor: Cesium.Color.AQUA,
396 | outlineWidth: 3,
397 | heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
398 | }
399 | static selectedStyle = {
400 | color: Cesium.Color.AQUA,
401 | pixelSize: 5,
402 | outlineColor: Cesium.Color.AQUA,
403 | outlineWidth: 3
404 | }
405 | static fromDegrees(viewer, positions) {
406 | const options = CesiumPoint.defaultStyle;
407 | if (positions instanceof Array) {
408 | options.positions = positions.map(_ => {
409 | if (_.lon === undefined || _.lat === undefined) {
410 | throw new Error('参数错误');
411 | }
412 | return Cesium.Cartesian3.fromDegrees(_.lon, _.lat, _.height);
413 | })
414 | } else {
415 | if (positions.lon === undefined || positions.lat === undefined) {
416 | throw new Error('参数错误');
417 | }
418 | options.positions = Cesium.Cartesian3.fromDegrees(
419 | positions.lon,
420 | positions.lat,
421 | positions.height);
422 | }
423 | return new CesiumPoint(viewer, options);
424 | }
425 | static fromRadians(viewer, positions) {
426 | const options = CesiumPoint.defaultStyle;
427 | if (positions instanceof Array) {
428 | options.positions = positions.map(_ => {
429 | if (_.lon === undefined || _.lat === undefined) {
430 | throw new Error('参数错误');
431 | }
432 | return Cesium.Cartesian3.fromRadians(_.lon, _.lat, _.height);
433 | })
434 | } else {
435 | if (positions.lon === undefined || positions.lat === undefined) {
436 | throw new Error('参数错误');
437 | }
438 | options.positions = Cesium.Cartesian3.fromRadians(
439 | options.positions.lon,
440 | options.positions.lat,
441 | options.positions.height);
442 | }
443 | return new CesiumPoint(viewer, options);
444 | }
445 | static isCesiumPoint(obj) {
446 | if (Cesium.defined(obj) && obj.id && obj.id.mtype === GraphicType.POINT) {
447 | return true
448 | }
449 | return false
450 | }
451 | destroy() {
452 | this.remove()
453 | this.viewer = undefined;
454 | this.options = undefined;
455 | this.graphic = undefined;
456 | }
457 | }
458 |
459 | class CesiumPolyline extends BaseGraphic {
460 | /**
461 | * Cesium PolylineGraphic
462 | * @param {Viewer} viewer Cesium.Viewer
463 | * @param {Object} options Describes a polyline. positions定义它的顶点集合,
464 | * 属性定义遵循和Cesium.PolylineGraphic相同的定义方式。
465 | */
466 | constructor(viewer, options = CesiumPolyline.defaultStyle) {
467 | super(viewer);
468 | this._type = 'POLYLINE';
469 | this.mtype = GraphicType.POLYLINE;
470 | this.positions = options.positions || [];
471 | const self = this;
472 | const _update = function() {
473 | return self.positions;
474 | };
475 | this.options = {
476 | mname: this._name,
477 | mid: this._gvid,
478 | mtype: this._gvtype,
479 | polyline: options,
480 | properties: options.properties
481 | };
482 | delete options.properties
483 | this.options.polyline.positions = new Cesium.CallbackProperty(_update, false);
484 | this.graphic = undefined;
485 | this.nodeGraphic = undefined;
486 | this.node = false;
487 | this.create();
488 | }
489 |
490 | get material() {
491 | if (this.graphic) {
492 | return this.graphic.polyline.material //.getValue()
493 | }
494 | return undefined
495 | }
496 | get width() {
497 | if (this.graphic) {
498 | return this.graphic.polyline.width.getValue(this.viewer.clock.currentTime)
499 | }
500 | return undefined
501 |
502 | }
503 | get properties() {
504 | if (this.graphic) {
505 | return this.graphic.properties
506 | }
507 | return false
508 | }
509 | set properties(v) {
510 | if (this.graphic) {
511 | this.graphic.properties = v
512 | }
513 | }
514 | addNode(node) {
515 | if (node instanceof Cesium.Cartesian3) {
516 | this.positions.push(node)
517 | }
518 | }
519 | popNode() {
520 | this.positions.pop()
521 | }
522 | updateNode(index, node) {
523 | if (index < 0 || index > this.positions.length - 1) {
524 | throw new Error('无效的index')
525 | }
526 | if (node instanceof Cesium.Cartesian3 === false) {
527 | throw new Error('无效的node')
528 | }
529 | this.positions[index] = node
530 | }
531 | dropNode(index) {
532 | this.positions.splice(index, 1)
533 | }
534 | create() {
535 | if (this.viewer) {
536 | this.graphic = this.viewer.entities.add(this.options);
537 | // this.graphic.mtype = 'CesiumPolyline'
538 | }
539 | }
540 | /**
541 | *
542 | * @param {Object} options describles a points.
543 | * 遵循和Cesiun.PointGraphic相同的定义方式
544 | */
545 | createNode(options = CesiumPoint.defaultStyle) {
546 | options.positions = this.positions;
547 | options.clampToGround = this.options.polyline.clampToGround
548 | this.nodeGraphic = new CesiumPoint(this.viewer, options);
549 | this.node = true;
550 | }
551 | /**
552 | * 对于Polyline的编辑,需要做下面几件事
553 | * 1.要素的positions要变成CallbackProperty
554 | * 2.创建要素节点
555 | * 3.要素高亮显示
556 | */
557 | startEdit() {
558 | if (!Cesium.defined(this.graphic)) {
559 | return;
560 | }
561 | // this.remove()
562 | // const self = this
563 | // const attrs = Object.keys(CesiumPolyline.selectedStyle)
564 | // for (let attr of attrs) {
565 | // this.graphic.polyline[attr] = CesiumPolyline.selectedStyle[attr]
566 | // }
567 | //this.graphic.polyline.material = CesiumPolyline.selectedStyle.material
568 |
569 | this.graphic.polyline.positions = new Cesium.CallbackProperty(() => {
570 | return this.positions
571 | }, false)
572 | if (this.node === false) {
573 | this.createNode()
574 | }
575 | // const evt = new CustomEvent('startEdit', {
576 | // detail: { graphicType: 'POLYLINE' }
577 | // })
578 | // document.dispatchEvent(evt)
579 |
580 | }
581 | stopEdit() {
582 | if (this.graphic instanceof Cesium.Entity) {
583 | this.graphic.polyline.positions = this.positions;
584 | // this.graphic.polyline.material = this.options.polyline.material
585 | }
586 | this.removeNode()
587 | // const endEvent = new CustomEvent('stopEdit')
588 | // document.dispatchEvent(endEvent)
589 | // window.aa = this.graphic
590 | }
591 | remove() {
592 | if (this.viewer) {
593 | this.viewer.entities.remove(this.graphic);
594 | this.graphic = undefined;
595 | this.removeNode()
596 | }
597 |
598 | }
599 | removeNode() {
600 | if (this.node) {
601 | this.nodeGraphic.remove();
602 | // this.nodeGraphic = undefined
603 | this.node = false;
604 | }
605 | }
606 | setMaterial(material) {
607 | this.graphic.polyline.material = material
608 | }
609 |
610 | static fromDegrees(viewer, positions, properties = {}) {
611 | positions = positions.map(_ => {
612 | return Cesium.Cartesian3.fromDegrees(_.lon, _.lat, _.height);
613 | })
614 | const options = {
615 | positions,
616 | ...CesiumPolyline.defaultStyle,
617 | properties
618 | };
619 |
620 | const pl = new CesiumPolyline(viewer, options);
621 | pl.stopEdit()
622 | return pl;
623 | }
624 | static fromRadians(viewer, positions) {
625 | positions = positions.map(_ => {
626 | return Cesium.Cartesian3.fromRadians(_.lon, _.lat, _.height);
627 | })
628 | const options = {
629 | positions,
630 | ...CesiumPolyline.defaultStyle
631 | };
632 | const pl = new CesiumPolyline(viewer, options);
633 | return pl;
634 | }
635 | static defaultStyle = {
636 | clampToGround: true,
637 | material: Cesium.Color.fromCssColorString('rgba(247,224,32,1)'),
638 | width: 3
639 | }
640 | static selectedStyle = {
641 | clampToGround: true,
642 | material: Cesium.Color.AQUA,
643 | width: 3
644 | }
645 | destroy() {
646 | this.remove();
647 | this.viewer = undefined;
648 | this.options = undefined;
649 | this.positions = undefined;
650 | if (this.nodeGraphic) {
651 | this.nodeGraphic.destroy();
652 | }
653 |
654 | this.nodeGraphic = undefined;
655 | }
656 | }
657 | class CesiumPolygon extends BaseGraphic {
658 | /**
659 | * Cesium PolygonGraphic
660 | * @param {Viewer} viewer Cesium.Viewer
661 | * @param {Object} options describles a polygon.
662 | * positions定义其位置信息, 属性信息遵循和Cesium.PolygonGraphic相同的定义方式
663 | */
664 | constructor(viewer, options = CesiumPolygon.defaultStyle) {
665 | super(viewer);
666 | this._type = 'POLYGON';
667 | this.mtype = GraphicType.POLYGON;
668 | this.positions = options.positions || [];
669 | this.nodePositions = [...this.positions]
670 |
671 | const self = this;
672 | this.options = {
673 | mid: this.mid,
674 | mtype: this.mtype,
675 | polygon: {
676 | hierarchy: new Cesium.CallbackProperty(function() {
677 | return new Cesium.PolygonHierarchy(self.positions)
678 | }, false),
679 | ...options
680 | },
681 | properties: options.properties
682 | };
683 | delete options.properties
684 | this.node = false;
685 | this.graphic = undefined;
686 | this.nodeGraphic = undefined;
687 | this.outlineGraphic = undefined;
688 | this.outline = options.outline;
689 | this.create();
690 | }
691 | get properties() {
692 | if (this.graphic) {
693 | return this.graphic.properties
694 | }
695 | return false
696 | }
697 | set properties(v) {
698 | if (this.graphic) {
699 | this.graphic.properties = v
700 | }
701 | }
702 | get outlineStyle() {
703 | if (this.outlineGraphic) {
704 | return this.outlineGraphic.polyline
705 | }
706 | return undefined
707 | }
708 | set outlineStyle(style) {
709 | const options = {}
710 | if (Cesium.defined(this.outlineGraphic)) {
711 | const pl = this.outlineGraphic.graphic.polyline
712 | options.material = style.outlineColor || pl.material
713 | options.width = style.outlineWidth || pl.width
714 | this.outlineGraphic.graphic.polyline.material = options.material
715 | this.outlineGraphic.graphic.polyline.width = options.width
716 | this.outlineGraphic.options.polyline.material = options.material
717 | this.outlineGraphic.options.polyline.width = options.width
718 | } else {
719 | this.outline && this.createOutline(options)
720 | }
721 |
722 | }
723 | get material() {
724 | if (this.graphic) {
725 | return this.graphic.polygon.material.getValue(this.viewer.clock.currentTime).color
726 | }
727 | return undefined
728 | }
729 | get outlineColor() {
730 | if (this.outlineGraphic) {
731 | return this.outlineGraphic.graphic.polyline.material.getValue(this.viewer.clock.currentTime).color
732 | }
733 | return CesiumPolygon.defaultStyle.outlineColor
734 | }
735 | get outlineWidth() {
736 | if (this.outlineGraphic) {
737 | return this.outlineGraphic.graphic.polyline.width.getValue(this.viewer.clock.currentTime)
738 | }
739 | return CesiumPolygon.defaultStyle.outlineWidth
740 | }
741 | addNode(node) {
742 | if (node instanceof Cesium.Cartesian3) {
743 | this.positions.push(node)
744 | //由于边框实质上是一个首尾相连的Polyline
745 | //因此最后一个点需要永远等于第一个点
746 | const count = this.nodePositions.length
747 | if (count === 0) {
748 | this.nodePositions.push(this.positions[0])
749 | this.nodePositions.push(this.positions[0])
750 | }
751 | if (count >= 2) {
752 | // this.nodePositions.insert(count-1,node)
753 | this.nodePositions[count] = this.nodePositions[count - 1]
754 | this.nodePositions[count - 1] = node
755 | }
756 |
757 | }
758 | }
759 | updateNode(index, node) {
760 | if (index < 0 || index > this.positions.length - 1) {
761 | throw new Error('无效的index')
762 | }
763 | if (node instanceof Cesium.Cartesian3 === false) {
764 | throw new Error('无效的node')
765 | }
766 | this.positions[index] = node
767 | if (index === 0) {
768 | this.nodePositions[0] = node
769 | this.nodePositions[this.nodePositions.length - 1] = node
770 | } else {
771 | this.nodePositions[index] = node
772 | }
773 | }
774 | popNode() {
775 | this.positions.pop()
776 | //nodePositions的最后一个节点是倒数第2个点
777 | this.nodePositions.splice(this.nodePositions.length - 2)
778 | this.nodePositions.push(this.positions[0])
779 | }
780 |
781 | dropNode(index) {
782 | this.positions.splice(index, 1)
783 | this.nodePositions.splice(index, 1)
784 | if (index === 0) {
785 | this.nodePositions[this.nodePositions.length - 1] = this.nodePositions[0]
786 | }
787 | }
788 | create() {
789 | //Not create outline here.
790 | //Create it with createOutline if necessary
791 |
792 | this.options.polygon.outline = false;
793 | if (this.viewer) {
794 | this.graphic = this.viewer.entities.add(this.options);
795 | // this.graphic.mtype = 'CesiumPolygon';
796 | if (this.outline) {
797 | this.createOutline()
798 | }
799 | }
800 | }
801 | /**
802 | *
803 | * @param {Object} options describles a points.
804 | * 遵循和Cesiun.PointGraphic相同的定义方式
805 | */
806 | createNode(options = CesiumPoint.defaultStyle) {
807 | this.node = true;
808 | options.positions = this.positions;
809 | options.clampToGround = this.graphic.polygon.perPositionHeight.getValue(this.viewer.clock.currentTime);
810 |
811 | this.nodeGraphic = new CesiumPoint(this.viewer, options);
812 | }
813 | /**
814 | * 创建多边形边框
815 | * 由于Cesium PolygonGraphic的outlineWidth属性无效(只能为1),
816 | * 这里利用Polyline代替多边形的outline
817 | */
818 | createOutline(options = {}) {
819 | if (this.options.outline === false) {
820 | console.log('如果您想创建多边形边线,请在options中设置outline为true');
821 | return;
822 | }
823 | options.width = this.options.polygon.outlineWidth || CesiumPolyline.defaultStyle.width;
824 | options.material = this.options.polygon.outlineColor || CesiumPolyline.defaultStyle.material;
825 | // options.show=this.options.outline
826 | options.clampToGround = !this.graphic.polygon.perPositionHeight.getValue(this.viewer.clock.currentTime);
827 | options.positions = this.nodePositions;
828 | this.outlineGraphic = new CesiumPolyline(this.viewer, options);
829 | this.outline = true
830 | }
831 | /**
832 | * 对于Polygon的要素编辑,需要做下面几件事:
833 | * 1.hierarchy变为CallbackProperty
834 | * 2.创建多边形顶点
835 | * 3.要素高亮显示
836 | * 4.如果多边形定义了outline,outline也要高亮,outline的positions要变为CallbackProperty
837 | */
838 | startEdit() {
839 | const positions = this.positions
840 | // const nodePositions = this.nodePositions
841 | if (this.graphic instanceof Cesium.Entity) {
842 | this.graphic.polygon.hierarchy = new Cesium.CallbackProperty(function() {
843 | return new Cesium.PolygonHierarchy(positions);
844 | })
845 | //this.graphic.polygon.material = CesiumPolygon.selectedStyle.material;
846 | if (this.outline) {
847 | this.outlineGraphic.startEdit();
848 | this.nodeGraphic = this.outlineGraphic.nodeGraphic;
849 | this.node = true;
850 | } else {
851 | this.createNode()
852 | }
853 | }
854 |
855 | }
856 | stopEdit() {
857 | if (this.graphic instanceof Cesium.Entity) {
858 | this.graphic.polygon.hierarchy = new Cesium.PolygonHierarchy(this.positions);
859 | //this.graphic.polygon.material = this.options.polygon.material
860 | }
861 | this.removeNode()
862 | if (this.nodeGraphic) {
863 | this.nodeGraphic.stopEdit();
864 | }
865 | if (this.outlineGraphic) {
866 | this.outlineGraphic.stopEdit();
867 | }
868 |
869 | }
870 | remove() {
871 | if (this.viewer) {
872 | this.viewer.entities.remove(this.graphic);
873 | this.graphic = undefined;
874 | this.removeNode()
875 | this.removeOutline()
876 | }
877 | }
878 | removeOutline() {
879 | if (this.outline) {
880 | this.outlineGraphic.remove();
881 | this.outline = false
882 | this.outlineGraphic = undefined
883 | }
884 | }
885 | removeNode() {
886 | if (this.node) {
887 | this.nodeGraphic.remove();
888 | this.node = false;
889 | // this.nodePositions=[]
890 | }
891 | }
892 | destroy() {
893 | this.remove()
894 | this.viewer = undefined;
895 | this.positions = undefined;
896 | this.options = undefined;
897 | if (this.nodeGraphic) {
898 | this.nodeGraphic.destroy();
899 | }
900 | if (this.outlineGraphic) {
901 | this.outlineGraphic.destroy();
902 | }
903 | this.outlineGraphic = undefined;
904 | this.nodeGraphic = undefined;
905 | }
906 |
907 | /**
908 | * 多边形默认样式
909 | */
910 | static defaultStyle = {
911 | material: new Cesium.Color.fromCssColorString('rgba(247,224,32,0.5)'),
912 | outline: true,
913 | outlineColor: new Cesium.Color.fromCssColorString('rgba(255,247,145,1)'),
914 | outlineWidth: 2,
915 | perPositionHeight: false
916 | // height:0,
917 | // HeightReference: Cesium.HeightReference.CLAMP_TO_GROUND
918 | //material: new Cesium.ColorMaterialProperty(new Cesium.Color(205, 139, 14, 1)),
919 |
920 | }
921 | static selectedStyle = {
922 | // material: new Cesium.ColorMaterialProperty(Cesium.Color.GREEN.withAlpha(0.4)),
923 | //material: new Cesium.ColorMaterialProperty(new Cesium.Color(205, 139, 14, 1)),
924 | material: new Cesium.ColorMaterialProperty(Cesium.Color.AQUA.withAlpha(0.4)),
925 | outlineColor: Cesium.Color.AQUA.withAlpha(0.4)
926 | //heightReference: Cesium.HeightReference.CLAMP_TO_GROUND
927 | }
928 | static fromDegrees(viewer, positions, properties = {}) {
929 | positions = positions.map(_ => {
930 | return Cesium.Cartesian3.fromDegrees(_.lon, _.lat, _.height);
931 | });
932 | const options = CesiumPolygon.defaultStyle;
933 | options.positions = positions;
934 | options.properties = properties
935 | const pg = new CesiumPolygon(viewer, options);
936 | pg.stopEdit()
937 | return pg
938 |
939 | }
940 | static fromRadians(viewer, positions) {
941 | positions = positions.map(_ => {
942 | return Cesium.Cartesian3.fromRadians(_.lon, _.lat, _.height);
943 | });
944 | const options = CesiumPolygon.defaultStyle;
945 | options.positions = positions;
946 | return new CesiumPolygon(viewer, options);
947 |
948 | }
949 | }
950 | class CesiumLabel extends BaseGraphic {
951 | /**
952 | *
953 | * @param {Viewer} viewer Cesium Viewer
954 | * @param {Object} options describles a label.
955 | * positions定义其空间位置(如果positions为Cartesian3数组将创建多个label),
956 | * label属性的定义遵循Cesium LabelGraphic的定义方式
957 | */
958 | constructor(viewer, options = CesiumLabel.defaultStyle) {
959 | super(viewer);
960 | this._type = 'LABEL';
961 | this._gvtype = GraphicType.LABEL;
962 | this.position = options.position;
963 |
964 | this.options = {
965 | mid: this._gvid,
966 | mtype: this._gvtype,
967 | position: this.position,
968 | label: options
969 | };
970 | this.graphic = undefined;
971 | this.create();
972 |
973 |
974 | }
975 | get color() {
976 | if (this.graphic) {
977 | return this.graphic.label.fillColor.getValue(this.viewer.clock.currentTime)
978 | }
979 | return undefined
980 | }
981 | set color(c) {
982 | if (this.graphic) {
983 | this.graphic.label.fillColor = c
984 | }
985 | }
986 | get font() {
987 | if (this.graphic) {
988 | return this.graphic.label.font.getValue(this.viewer.clock.currentTime)
989 | }
990 | return undefined
991 | }
992 | create() {
993 |
994 | this.graphic = this.viewer.entities.add(this.options);
995 | }
996 | startEdit() {
997 | if (this.graphic) {
998 | this.graphic.label.position = new Cesium.CallbackProperty(() => {
999 | return this.position
1000 | }, false)
1001 | }
1002 | }
1003 | stopEdit() {
1004 | if (this.graphic) {
1005 | this.graphic.label.position = this.position
1006 | }
1007 | }
1008 | remove() {
1009 | this.viewer && this.viewer.entities.remove(this.graphic);
1010 | this.graphic = undefined;
1011 | }
1012 | updateText(text) {
1013 | if (this.graphic) {
1014 | this.graphic.label.text = text;
1015 | this.mname = text
1016 | }
1017 | }
1018 | static defaultStyle = {
1019 | color: Cesium.Color.WHITE,
1020 | font: '28px sans-serif',
1021 | showBackground: true
1022 | }
1023 | destroy() {
1024 | this.remove();
1025 | this.viewer = undefined;
1026 | this.options = undefined;
1027 | this.positions = undefined;
1028 | }
1029 | }
1030 | class CesiumModel extends BaseGraphic {
1031 | constructor(viewer, options) {
1032 | super(viewer);
1033 | this._type = 'MODEL';
1034 | this._gvtype = GraphicType.MODEL;
1035 | this.position = options.position
1036 | // this.mname = '未命名'
1037 | this.options = {
1038 | mid: this._gvid,
1039 | mtype: this._gvtype,
1040 | position: this.position,
1041 | model: options
1042 | }
1043 | this.create()
1044 |
1045 | }
1046 | create() {
1047 | this.graphic = this.viewer.entities.add(this.options)
1048 | }
1049 | startEdit() {
1050 | if (this.graphic) {
1051 | this.graphic.label.position = new Cesium.CallbackProperty(() => {
1052 | return this.position
1053 | }, false)
1054 | }
1055 | }
1056 | stopEdit() {
1057 | if (this.graphic) {
1058 | this.graphic.label.position = this.position
1059 | }
1060 | }
1061 | remove() {
1062 | if (this.viewer) {
1063 | this.viewer.entities.remove(this.graphic)
1064 | this.graphic = undefined
1065 | }
1066 | }
1067 | destroy() {
1068 | this.remove()
1069 | this.options = undefined
1070 | this.position = undefined
1071 | }
1072 | set uri(uri) {
1073 | if (this.graphic) {
1074 | this.graphic.model.uri = uri
1075 | }
1076 | }
1077 | set color(c) {
1078 | if (this.graphic) {
1079 | this.graphic.model.color = c
1080 | }
1081 | }
1082 | set mode(m) {
1083 | if (this.graphic) {
1084 | this.graphic.model.colorBlendMode = m
1085 | }
1086 | }
1087 | set mixed(v) {
1088 | if (this.graphic) {
1089 | this.graphic.model.colorBlendAmount = v
1090 | }
1091 | }
1092 | static defaultStyle = {
1093 | colorBlendMode: Cesium.ColorBlendMode.HIGHLIGHT,
1094 | color: Cesium.Color.WHITE,
1095 | colorBlendAmount: 0.5,
1096 | minimumPixelSize: 64
1097 | }
1098 | }
1099 | export {
1100 | CesiumPoint,
1101 | CesiumPolyline,
1102 | CesiumPolygon,
1103 | CesiumLabel,
1104 | CesiumBillboard,
1105 | CesiumModel
1106 | }
1107 | export default {
1108 | CesiumPoint,
1109 | CesiumPolyline,
1110 | CesiumPolygon,
1111 | CesiumLabel,
1112 | CesiumBillboard,
1113 | CesiumModel
1114 | }
1115 |
--------------------------------------------------------------------------------
/src/core/GraphicManager.js:
--------------------------------------------------------------------------------
1 | import * as Cesium from 'cesium'
2 | import {
3 | CesiumPoint,
4 | CesiumPolyline,
5 | CesiumPolygon
6 | } from './Graphic'
7 | import utils from '@/js/utils'
8 | import {
9 | CVT
10 | } from '@/js/utils'
11 | import GraphicType from './GraphicType'
12 | import {
13 | saveAs
14 | } from 'file-saver'
15 | const console = window.console;
16 | const LEFT_CLICK = Cesium.ScreenSpaceEventType.LEFT_CLICK;
17 | const RIGHT_CLICK = Cesium.ScreenSpaceEventType.RIGHT_CLICK;
18 | const MOUSE_MOVE = Cesium.ScreenSpaceEventType.MOUSE_MOVE;
19 | const MOUSE_DOWN = Cesium.ScreenSpaceEventType.LEFT_DOWN;
20 | const MOUSE_UP = Cesium.ScreenSpaceEventType.LEFT_UP;
21 | class GraphicManager {
22 | /**
23 | * 鼠标交互绘制线和多边形
24 | * @param {Viewer}} viewer Cesium Viewer
25 | * @param {*} options 预留参数,目前不需要关注
26 | */
27 | constructor(viewer, options = {}) {
28 | if (viewer instanceof Cesium.Viewer === false) {
29 | throw new Error('viewer不是一个有效的Cesium Viewer')
30 | }
31 |
32 | this.viewer = viewer
33 | this.options = options
34 | /*heightReference 定义几何图形的高程基准
35 | *CLAMP_TO_GROUND:依附地形
36 | *CLAMP_TO_MODEL:依附模型
37 | *NONE:空间线
38 | */
39 | this._heightReference = 'CLAMP_TO_GROUND'
40 | this._material = undefined
41 | this._style = {}
42 |
43 | this.graphicId = undefined
44 | this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas)
45 | this.graphicType = undefined
46 | this.positions = []
47 | this.tip = new utils.CursorTip('')
48 | this.tip.visible = false
49 | this.mode = 'ready'
50 | this.dragging = false
51 | // this.init()
52 | // this.addEventListener()
53 | //当前正在编辑的graphic
54 | this.editManager = undefined
55 | this.selectedNodeIndex = -1
56 | //Graphic集合
57 | this.manager = new Map()
58 | const self = this
59 | document.onkeydown = function(event) {
60 |
61 | if (self.mode !== 'edit') return;
62 |
63 | const e = event || window.event || arguments.callee.caller.arguments[0];
64 |
65 | if (e && e.keyCode == 46) { // 按 delete
66 | if (self.selectedNodeIndex > -1 && self.editManager) {
67 | self.editManager.dropNode(self.selectedNodeIndex)
68 | self.highlightedNode(undefined, self.editManager.nodeGraphic)
69 | self.selectedNodeIndex = -1
70 | } else if (self.editManager) {
71 | self.editManager.destroy()
72 | self.manager.delete(self.editManager.id)
73 | self.mode = 'end'
74 |
75 | self.tip.visible = false
76 | const evt = new CustomEvent('deleteEvent', {
77 | detail: {
78 | mid: self.editManager ? self.editManager.mid : undefined
79 | }
80 | })
81 | document.dispatchEvent(evt)
82 | self.editManager = undefined
83 | // self.removeEventListener();
84 | }
85 |
86 |
87 | }
88 |
89 | };
90 | // this.tip.style.display='none'
91 |
92 | }
93 | get heightReference() {
94 | return this._heightReference;
95 | }
96 | set heightReference(h) {
97 | this._heightReference = h
98 | if (this.editManager) {
99 | this.editManager.heightReference = h
100 | if (this.editManager.type === 'POLYLINE') {
101 | this.editManager.graphic.polyline.clampToGround = /.*GROUND.*/.test(h);
102 | this.editManager.options.polyline.clampToGround = /.*GROUND.*/.test(h);
103 |
104 | } else if (this.editManager.type === 'POLYGON') {
105 | const graphic = this.editManager.graphic;
106 | const options = this.editManager.options;
107 | if (/.*GROUND.*/.test(h)) {
108 | graphic.polygon.perPositionHeight = false;
109 | if (this.editManager.outline) {
110 | this.editManager.outlineGraphic.graphic.polyline.clampToGround = true
111 | } // polygon.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
112 | // options.polygon.heightReference= Cesium.HeightReference.CLAMP_TO_GROUND
113 | options.polygon.perPositionHeight = false;
114 | } else {
115 | graphic.polygon.perPositionHeight = true;
116 | if (this.editManager.outline) {
117 | this.editManager.outlineGraphic.graphic.polyline.clampToGround = false
118 | }
119 | // polygon.heightReference = Cesium.HeightReference.RELATIVE_TO_GROUND
120 | // options.polygon.heightReference= Cesium.HeightReference.RELATIVE_TO_GROUND
121 | options.polygon.perPositionHeight = true
122 |
123 | }
124 |
125 | }
126 | }
127 | }
128 | get material() {
129 | return this._material;
130 | }
131 | set material(v) {
132 | this._material = v;
133 | if (this.editManager) {
134 | if (this.editManager.type === 'POLYLINE') {
135 | this.editManager.graphic.polyline.material = this._material;
136 | this.editManager.options.polyline.material = this._material;
137 |
138 | } else if (this.editManager.type === 'POLYGON') {
139 | this.editManager.graphic.polygon.material = this._material;
140 | this.editManager.options.polygon.material = this._material;
141 | }
142 | }
143 | }
144 | get style() {
145 | return this._style;
146 | }
147 | set style(option) {
148 | this._style = option;
149 | if (!this.editManager) {
150 | return
151 | }
152 | const keys = Object.keys(option);
153 | for (let key of keys) {
154 | if (this.editManager.type === 'POLYLINE') {
155 | this.editManager.graphic.polyline[key] = option[key];
156 | this.editManager.options.polyline[key] = option[key];
157 | } else if (this.editManager.type === 'POLYGON') {
158 | if (key !== 'outline') {
159 | this.editManager.graphic.polygon[key] = option[key];
160 | }
161 |
162 | this.editManager.options.polygon[key] = option[key];
163 | }
164 | }
165 | if (this.editManager.type === 'POLYGON') {
166 | this.editManager.outlineStyle = option
167 | }
168 | }
169 |
170 |
171 |
172 | /**
173 | *
174 | * @param {Object} options 定义一个CesiumPolyline
175 | */
176 | createPolyline(options = CesiumPolyline.defaultStyle) {
177 | this.graphicType = GraphicType.POLYLINE;
178 | const id = this.generateId();
179 | options.positions = this.positions;
180 | if (/.*GROUND.*/.test(this._heightReference)) {
181 | options.clampToGround = true
182 | } else {
183 | options.clampToGround = false
184 | }
185 | options.material = this.material || options.material
186 | options.width = this.style.width || options.width
187 | const manager = new CesiumPolyline(this.viewer, options);
188 | this.tip.updateText('左键标绘,右键结束.');
189 | this.tip.visible = true;
190 | manager.mid = id
191 | // manager.id = id
192 | // manager.mname = '未命名';
193 | manager.heightReference = this.heightReference
194 | this.manager.set(id, manager);
195 | this.graphicId = id
196 | this.editManager = manager
197 | const evt = new CustomEvent('addEvent', {
198 | detail: {
199 | mid: manager.mid,
200 | mtype: manager.mtype,
201 | mname: manager.mname,
202 | }
203 | })
204 | document.dispatchEvent(evt);
205 | const self = this;
206 | this.handler.setInputAction(e => {
207 | self.tip && self.tip.updatePosition(e.endPosition);
208 | }, MOUSE_MOVE)
209 | this.addEventListener()
210 | return manager
211 |
212 | }
213 |
214 | /**
215 | *
216 | * @param {Object} options 定义一个CesiumPolygon
217 | */
218 | createPolygon(options = CesiumPolygon.defaultStyle) {
219 | this.graphicType = GraphicType.POLYGON;
220 | const id = this.generateId();
221 | this.graphicId = id;
222 | options.positions = this.positions;
223 | if (/.*GROUND.*/.test(this._heightReference)) {
224 | options.perPositionHeight = false
225 | // options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND;
226 | } else {
227 | options.perPositionHeight = true;
228 | // options.heightReference = Cesium.HeightReference.RELATIVE_TO_GROUND;
229 | // options.height = 0
230 | }
231 |
232 | options.material = this.material || options.material;
233 | options.outlineWidth = this.style.outlineWidth || options.outlineWidth;
234 | options.outlineColor = this.style.outlineColor || options.outlineColor;
235 | const manager = new CesiumPolygon(this.viewer, options);
236 | manager.mid = id;
237 | // manager.id = id;
238 | // manager.mname = '未命名';
239 | manager.heightReference = this.heightReference;
240 | this.tip.visible = true;
241 | this.tip.updateText('左键标绘,右键结束.');
242 | this.manager.set(id, manager);
243 | this.editManager = manager;
244 | const evt = new CustomEvent('addEvent', {
245 | detail: {
246 | mid: manager.mid,
247 | mtype: manager.mtype,
248 | mname: manager.mname,
249 | }
250 | })
251 | document.dispatchEvent(evt)
252 | const self = this;
253 | this.handler.setInputAction(e => {
254 | self.tip && self.tip.updatePosition(e.endPosition);
255 | }, MOUSE_MOVE)
256 | this.addEventListener()
257 | return manager;
258 |
259 | }
260 | generateId() {
261 | return (Math.random() * 10000000).toString(16).substr(0, 4) + '-' + (new Date()).getTime() + '-' + Math.random().toString().substr(2, 5);
262 | }
263 | isKnownGraphic(pickedObj) {
264 | if (Cesium.defined(pickedObj) &&
265 | pickedObj.id instanceof Cesium.Entity &&
266 | (pickedObj.id.mtype === GraphicType.POLYLINE ||
267 | pickedObj.id.mtype === GraphicType.POLYGON ||
268 | pickedObj.id.mtype === GraphicType.POINT)) {
269 | return true
270 | }
271 | return false
272 | }
273 | /**
274 | * 将当前选中的点设为高亮
275 | * @param {Cartesian3} node
276 | * @param {CesiumPoint} cp
277 | */
278 | highlightedNode(node, cp) {
279 | const soption = CesiumPoint.selectedStyle
280 | const doption = CesiumPoint.defaultStyle
281 | for (let n of cp.graphic) {
282 | if (n === node) {
283 | CesiumPoint.setStyle(n, soption)
284 | } else {
285 | CesiumPoint.setStyle(n, doption)
286 | }
287 | }
288 |
289 | }
290 | addEventListener() {
291 | const self = this
292 | const viewer = this.viewer
293 | const clickHandler = function(e) {
294 | //编辑要素
295 | if (self.mode === 'edit') {
296 | if (!self.editManager) {
297 | self.removeEventListener();
298 | return
299 | }
300 | const nodeGraphic = self.editManager.nodeGraphic ||
301 | self.editManager.outlineGraphic.nodeGraphic
302 | const pickedObjs = viewer.scene.drillPick(e.position)
303 | let known = false,
304 | pickedObj = undefined
305 | for (let obj of pickedObjs) {
306 | known = self.isKnownGraphic(obj)
307 | if (known && obj.id.mtype === GraphicType.POINT) {
308 | pickedObj = obj
309 | //再事件监听之前移除上次的监听
310 | self.handler.removeInputAction(MOUSE_DOWN);
311 | self.handler.removeInputAction(MOUSE_MOVE);
312 | self.handler.setInputAction(mouseDownHandler, MOUSE_DOWN);
313 | self.handler.setInputAction(moseMoveHandler, MOUSE_MOVE);
314 | break
315 | }
316 | }
317 | // const pickedPosition=CVT.pixel2Cartesian(e.position,viewer)
318 |
319 | if (pickedObj && known) {
320 | if (pickedObj.id.mtype === GraphicType.POINT) {
321 | self.selectedNodeIndex = nodeGraphic.contain(pickedObj.id)
322 | if (self.selectedNodeIndex !== -1) {
323 | self.highlightedNode(pickedObj.id, nodeGraphic)
324 |
325 | }
326 | } else {
327 | self.highlightedNode(pickedObj.id, self.editManager.nodeGraphic)
328 | self.selectedNodeIndex = -1
329 | }
330 |
331 | } else {
332 | self.editManager && self.editManager.stopEdit()
333 | // self.handler.removeInputAction(MOUSE_MOVE);
334 | self.removeEventListener()
335 | self.mode = 'end'
336 | self.selectedNodeIndex = -1
337 | self.editManager = undefined
338 | self.tip.visible = false;
339 | const evt = new CustomEvent('stopEdit')
340 | document.dispatchEvent(evt)
341 | }
342 | return
343 | }
344 | //非法的要素类型
345 | if (self.graphicType != GraphicType.POLYLINE &&
346 | self.graphicType != GraphicType.POLYGON) {
347 | return;
348 | }
349 | let cartesian = CVT.pixel2Cartesian(e.position, self.viewer);
350 | if (/.*MODEL.*/.test(self._heightReference)) {
351 | if (!viewer.scene.pickPositionSupported) {
352 | console.log('This browser does not support pickPosition.')
353 | return
354 | }
355 | cartesian = viewer.scene.pickPosition(e.position)
356 | }
357 | //添加第一个点后再监听鼠标移动事件,绘绘完成后移除监听,以免不必要的事件监听
358 | const target = self.manager.get(self.graphicId);
359 | if (target && target.positions.length === 0) {
360 | self.handler.removeInputAction(MOUSE_MOVE);
361 | self.handler.setInputAction(moseMoveHandler, MOUSE_MOVE);
362 | }
363 | if (Cesium.defined(cartesian) && self.manager.has(self.graphicId) && target) {
364 | target.addNode(cartesian);
365 | }
366 | self.mode = 'create'
367 | }
368 | const rightHandler = function() {
369 | const manager = self.manager.get(self.graphicId);
370 | if ((self.mode === 'create') && manager) {
371 | manager.stopEdit();
372 | self.graphicType = undefined;
373 | self.graphicId = undefined;
374 | self.positions = [];
375 | self.mode = 'end'
376 | self.tip.visible = false
377 | self.editManager = undefined
378 | const evt = new CustomEvent('stopEdit')
379 | document.dispatchEvent(evt)
380 | } else if (self.mode === 'ready') {
381 | self.cancel()
382 | } else if (self.mode === 'edit') {
383 | self.editManager && self.editManager.stopEdit()
384 | // self.handler.removeInputAction(MOUSE_MOVE);
385 | self.removeEventListener()
386 | self.mode = 'end'
387 | self.selectedNodeIndex = -1
388 | self.editManager = undefined
389 | self.tip.visible = false;
390 | }
391 | // self.handler.removeInputAction(MOUSE_MOVE);
392 | const evt = new CustomEvent('stopEdit')
393 | document.dispatchEvent(evt)
394 | self.removeEventListener()
395 | }
396 |
397 | const moseMoveHandler = function(e) {
398 | let cartesian = CVT.pixel2Cartesian(e.endPosition, self.viewer);
399 | if (/.*MODEL.*/.test(self._heightReference)) {
400 | if (!viewer.scene.pickPositionSupported) {
401 | console.log('This browser does not support pickPosition.')
402 | return
403 | }
404 | cartesian = viewer.scene.pickPosition(e.endPosition)
405 | }
406 | if (!Cesium.defined(cartesian)) {
407 | return
408 | }
409 | self.tip.updatePosition(e.endPosition);
410 | if (self.mode === 'create') {
411 | //如果当前是create模式,创建辅助线
412 | if (self.positions.length > 1) {
413 | self.manager.get(self.graphicId).popNode();
414 | }
415 | //添加临时节点
416 | //再添加第一个节点前,不拾取鼠标移动的坐标
417 | if (self.positions.length > 0) {
418 | // self.positions.push(cartesian);
419 | self.manager.get(self.graphicId).addNode(cartesian);
420 | }
421 | } else if (self.mode == 'edit' && self.dragging) {
422 | if (self.selectedNodeIndex !== -1) {
423 | self.editManager.updateNode(self.selectedNodeIndex, cartesian)
424 | }
425 |
426 | }
427 | }
428 | const mouseDownHandler = function(e) {
429 | self.handler.setInputAction(mouseUpHandler, MOUSE_UP)
430 | const objs = viewer.scene.drillPick(e.position);
431 | let isCesiumPoint = false;
432 | for (let obj of objs) {
433 | if (CesiumPoint.isCesiumPoint(obj)) {
434 | isCesiumPoint = true;
435 | }
436 |
437 | }
438 | if (isCesiumPoint == false) {
439 | return;
440 | }
441 | if (self.mode === 'edit' && self.selectedNodeIndex != -1) {
442 | self.dragging = true
443 | viewer.scene.screenSpaceCameraController.enableRotate = false
444 |
445 | }
446 |
447 | }
448 | const mouseUpHandler = function() {
449 | self.dragging = false;
450 | viewer.scene.screenSpaceCameraController.enableRotate = true;
451 | self.handler.removeInputAction(MOUSE_UP);
452 | // self.handler.removeInputAction(MOUSE_DOWN);
453 |
454 |
455 | }
456 | this.handler.setInputAction(clickHandler, LEFT_CLICK);
457 | this.handler.setInputAction(rightHandler, RIGHT_CLICK);
458 | }
459 | rename(id, name) {
460 | const graphic = this.manager.get(id);
461 | if (Cesium.defined(graphic)) {
462 | graphic.mname = name
463 | }
464 | }
465 | has(id) {
466 | if (this.manager) {
467 | return this.manager.has(id)
468 | }
469 | return false
470 | }
471 | get(id) {
472 | if (this.has(id)) {
473 | return this.manager.get(id)
474 | }
475 | }
476 | /**
477 | * 当图形处于ready状态时,不想画了
478 | */
479 | cancel() {
480 |
481 | const manager = this.manager.get(this.graphicId);
482 | manager && manager.stopEdit();
483 | manager && manager.destroy()
484 | this.graphicType = undefined;
485 | this.graphicId = undefined;
486 | this.positions = [];
487 | this.mode = 'end'
488 | this.tip.visible = false
489 | this.editManager = undefined
490 | }
491 | select(type, id, status) {
492 | if (Cesium.defined(id)) {
493 | const manager = this.manager.get(id)
494 | if (manager) {
495 | manager.show = status
496 | }
497 | }
498 | if (Cesium.defined(type)) {
499 | const values = this.manager.values()
500 | for (let v of values) {
501 | if (v.mtype === type) {
502 | v.show = status
503 | }
504 | }
505 | }
506 | }
507 | edit(id) {
508 | const self = this
509 | const manager = self.manager.get(id);
510 | this.handler.setInputAction(e => {
511 | self.tip.updatePosition(e.endPosition);
512 | }, MOUSE_MOVE);
513 | self.graphicId = id;
514 | if (Cesium.defined(manager)) {
515 | // manager.zoomTo()
516 | self.mode = 'edit'
517 | manager.startEdit();
518 | self.tip.visible = true;
519 | self.tip.updateText('拖动节点编辑,按del删除.')
520 | self.editManager = manager;
521 | const evt = new CustomEvent('startEdit', {
522 | detail: {
523 | graphicType: self.editManager.type,
524 | material: self.editManager.material,
525 | width: self.editManager.width,
526 | outline: self.editManager.outline,
527 | outlineColor: self.editManager.outlineColor,
528 | outlineWidth: self.editManager.outlineWidth,
529 | heightReference: self.editManager.heightReference
530 | }
531 | })
532 | document.dispatchEvent(evt)
533 | self.addEventListener()
534 | }
535 | }
536 | export (type) {
537 | const json = {
538 | type: "FeatureCollection",
539 | name: "graphic",
540 | crs: {
541 | type: "name",
542 | properties: {
543 | name: "urn:ogc:def:crs:OGC:1.3:CRS84"
544 | }
545 | },
546 | features: []
547 | };
548 | const managers = this.manager.values()
549 | for (let m of managers) {
550 | if (m.type === type) {
551 | json.features.push(m.toGeoJson())
552 | }
553 | }
554 | const blob = new Blob([JSON.stringify(json)], {
555 | type: ""
556 | });
557 | saveAs(blob, type + parseInt(Cesium.getTimestamp()) + '.geojson');
558 | }
559 | import(feat) {
560 | const id = this.generateId();
561 | let graphic, coordinates, positions = [];
562 | if (feat.geometry.type.toUpperCase() === 'LineString'.toUpperCase()) {
563 | coordinates = feat.geometry.coordinates
564 | for (let c of coordinates) {
565 | positions.push({
566 | lon: c[0],
567 | lat: c[1],
568 | height: c[2]
569 | })
570 | }
571 | try {
572 | graphic = CesiumPolyline.fromDegrees(this.viewer, positions, feat.properties);
573 | } catch (e) {
574 | console.log(e)
575 | }
576 |
577 | } else if (feat.geometry.type.toUpperCase() === "POLYGON") {
578 | coordinates = feat.geometry.coordinates[0]
579 | for (let c of coordinates) {
580 | positions.push({
581 | lon: c[0],
582 | lat: c[1],
583 | height: c[2]
584 | })
585 | }
586 | graphic = CesiumPolygon.fromDegrees(this.viewer, positions, feat.properties);
587 | } else {
588 | throw new Error('不能识别的数据源.')
589 | }
590 | if (graphic) {
591 | graphic.mid = id;
592 | graphic.mname = feat.properties.name
593 | this.manager.set(id, graphic)
594 | const evt = new CustomEvent('addEvent', {
595 | detail: {
596 | mid: graphic.mid,
597 | mtype: graphic.mtype,
598 | mname: graphic.mname || '未命名',
599 | }
600 | })
601 | document.dispatchEvent(evt)
602 | }
603 | return graphic
604 |
605 | }
606 |
607 | removeEventListener() {
608 | this.handler.removeInputAction(LEFT_CLICK);
609 | this.handler.removeInputAction(MOUSE_MOVE);
610 | this.handler.removeInputAction(RIGHT_CLICK);
611 | this.handler.removeInputAction(MOUSE_DOWN)
612 | this.handler.removeInputAction(MOUSE_UP)
613 | }
614 | removeAll() {
615 | const values = this.manager.values();
616 | for (let v of values) {
617 | v.remove();
618 | v.destroy();
619 | }
620 | this.manager.clear();
621 | this.tip.visible = false;
622 | }
623 |
624 | destroy() {
625 | this.activeManager = undefined
626 | this.manager = undefined
627 | this.editManager = undefined
628 | this.removeEventListener()
629 | if (!this.handler.isDestroyed) {
630 | this.handler.destroy()
631 | this.handler = undefined
632 | }
633 | }
634 | destroyManager() {
635 | const manager = this.editManager;
636 | const evt = new CustomEvent('destroyEvent', {
637 | detail: {
638 | mid: manager ? manager.mid : undefined
639 | }
640 | })
641 | if (manager) {
642 | if (this.mode === 'edit') {
643 | manager && manager.stopEdit();
644 | } else {
645 | manager && manager.destroy();
646 | this.manager.delete(this.graphicId)
647 | }
648 | this.editManager = undefined;
649 | }
650 |
651 | this.graphicId = undefined;
652 | this.handler.removeInputAction(MOUSE_MOVE);
653 | this.positions = [];
654 |
655 | document.dispatchEvent(evt);
656 | }
657 | }
658 | export default GraphicManager
659 |
--------------------------------------------------------------------------------
/src/core/GraphicType.js:
--------------------------------------------------------------------------------
1 | const GraphicType = (function() {
2 | function _() {
3 |
4 | }
5 | _.MARKER = 0
6 | _.POINT = 5
7 | _.POLYLINE = 1
8 | _.POLYGON = 2
9 | _.LABEL = 3
10 | _.MODEL = 4
11 | return _
12 | })()
13 | export default GraphicType
14 |
--------------------------------------------------------------------------------
/src/core/MarkerManager.js:
--------------------------------------------------------------------------------
1 | import * as Cesium from 'cesium'
2 | import {
3 | CesiumBillboard,
4 | CesiumLabel,
5 | CesiumModel
6 | } from "../core/Graphic";
7 | import utils from "@/js/utils";
8 | import GraphicType from "../core/GraphicType";
9 | import $ from "jquery";
10 | const cvt = utils.CVT;
11 | const LEFT_CLICK = Cesium.ScreenSpaceEventType.LEFT_CLICK;
12 | const RIGHT_CLICK = Cesium.ScreenSpaceEventType.RIGHT_CLICK;
13 | const MOUSE_MOVE = Cesium.ScreenSpaceEventType.MOUSE_MOVE;
14 |
15 | function setString(str, len) {
16 | var strlen = 0;
17 | var s = "";
18 | for (var i = 0; i < str.length; i++) {
19 | if (str.charCodeAt(i) > 128) {
20 | strlen += 2;
21 | } else {
22 | strlen++;
23 | }
24 | s += str.charAt(i);
25 | if (strlen >= len) {
26 | return s + "...";
27 | }
28 | }
29 | return s;
30 | }
31 | export default class MarkerManager {
32 | constructor(viewer, markerOptions = CesiumBillboard.defaultStyle,
33 | labelOptions = CesiumBillboard.defaultLabelStyle, modelOptions = CesiumModel.defaultStyle) {
34 | if (viewer instanceof Cesium.Viewer) {
35 | this._viewer = viewer
36 | }
37 | if (!Cesium.defined(this._viewer)) {
38 | return
39 | }
40 | /**
41 | * 表示当前添加的标记类型,marker,label,model
42 | */
43 | this.markName = ''
44 | this.markRemark = ''
45 | this.markMode = 'marker'
46 | this.defaultImage = CesiumBillboard.defaultStyle.image
47 | this.selectedImage = undefined
48 | this.popWinPosition = undefined
49 | this.markerid = undefined
50 | this.markerOptions = markerOptions;
51 | this.labelOptions = labelOptions;
52 | this.modelOptions = modelOptions;
53 | this.cursorTip = new utils.CursorTip(
54 | "左键标绘,右键结束.",
55 | "marker-tip",
56 | viewer
57 | );
58 | this.cursorTip.visible = false;
59 |
60 | this.handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
61 | this.manager = new Map();
62 | this.pickHandler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
63 | this.init(this._viewer)
64 |
65 | }
66 | init(viewer) {
67 | if (viewer instanceof Cesium.Viewer === false) {
68 | throw new Error("viewer不是一个有效的Cesium Viewer对象.");
69 | }
70 | this.viewer = viewer;
71 | const handler = this.handler;
72 | const self = this;
73 | const manager = this.manager
74 | //气泡跟随地球移动
75 | viewer.scene.postRender.addEventListener(function() {
76 | if (Cesium.defined(self.popWinPosition)) {
77 | const pos = cvt.cartesian2Pixel(self.popWinPosition, viewer);
78 |
79 | const ele = document.getElementById("popContainer");
80 | if (!ele) {
81 | return;
82 | }
83 | ele.style.left = pos.x - 94 + "px";
84 | ele.style.top = pos.y - 110 + "px";
85 |
86 | const curPos = self.popWinPosition;
87 | //标记转到地球背面隐藏气泡
88 | if (utils.pointVisibilityOnEarth(curPos, self._viewer)) {
89 | ele.style.display = "block";
90 | } else {
91 | ele.style.display = "none";
92 | }
93 |
94 | // ele.style.display = "block";
95 | }
96 | });
97 | const showTip = function(e) {
98 | const obj = viewer.scene.pick(e.position);
99 | if (
100 | Cesium.defined(obj) &&
101 | obj.id instanceof Cesium.Entity &&
102 | obj.id.mtype === GraphicType.MARKER
103 | ) {
104 | // self.popWinPosition = cvt.pixel2Cartesian(e.position, viewer);
105 | self.selectedMarker = manager.get(obj.id.mid);
106 | if (self.popDiv) {
107 | self.destroyPopPanle();
108 | } else {
109 | self.createPopPanel();
110 | }
111 | } else {
112 | self.destroyPopPanle();
113 | }
114 | };
115 |
116 | handler.setInputAction(showTip, LEFT_CLICK);
117 | }
118 | /**
119 | * 开始拾取marker,调用该方法后开始监听鼠标单击,添加标记
120 | * @param {string} type表示何种标记,marker:billboard,label:label,model:model
121 | * @param {string} mode如果mode不是single,将连续添加标记
122 | */
123 | pick(type = "marker", mode = "single") {
124 | this.markMode = type;
125 | const viewer = this._viewer;
126 | this.cursorTip.visible = true;
127 | const handler = this.pickHandler
128 | const self = this;
129 | const id = this.generateId();
130 | self.markerid = id;
131 | const manager = this.manager
132 |
133 | const pick = function(e) {
134 | const cartesian = cvt.pixel2Cartesian(e.position, viewer);
135 | if (Cesium.defined(cartesian)) {
136 | // mp.position = cartesian;
137 | let marker;
138 | if (type === "marker") {
139 | marker = self.createMarker(cartesian);
140 | } else if (type === "label") {
141 | marker = self.createLabel(cartesian);
142 | } else if (type === "model") {
143 | marker = self.createModel(cartesian);
144 | } else {
145 | //默认marker
146 | marker = self.createMarker(cartesian);
147 | }
148 | self.visible = true;
149 | manager.set(id, marker);
150 | marker.mid = id;
151 | // marker.mname = "未命名" + viewer.entities.values.length;
152 |
153 | self.selectedMarker = marker;
154 | self.activeMarker = marker;
155 |
156 | self.cursorTip.visible = false;
157 | if (type === "model") {
158 | self.activeMarker = undefined;
159 | }
160 | if (mode === "single") {
161 | handler.removeInputAction(LEFT_CLICK);
162 | handler.removeInputAction(RIGHT_CLICK);
163 | }
164 | const evt = new CustomEvent('marker-add', {
165 | detail: {
166 | id: marker.mid,
167 | name: marker.mname || '未命名',
168 | description: marker.description,
169 | type: marker.mtype,
170 | position: cvt.toDegrees(cartesian, self._viewer)
171 | }
172 | })
173 | window.dispatchEvent(evt)
174 | marker = undefined
175 | }
176 | };
177 | const cancel = function() {
178 | handler.removeInputAction(LEFT_CLICK);
179 | handler.removeInputAction(RIGHT_CLICK);
180 | // handler.destroy();
181 | self.cursorTip.visible = false;
182 | const id = self.activeMarker ? self.activeMarker.id : undefined
183 | const evt = new CustomEvent('marker-delete', {
184 | detail: {
185 | id: id
186 | }
187 | })
188 | window.dispatchEvent(evt)
189 |
190 | self.activeMarker = undefined;
191 | //handler=undefined
192 | };
193 | const updateTip = function(e) {
194 | self.cursorTip.updatePosition(e.endPosition);
195 | };
196 | handler.setInputAction(cancel, RIGHT_CLICK);
197 |
198 | handler.setInputAction(pick, LEFT_CLICK);
199 | handler.setInputAction(updateTip, MOUSE_MOVE);
200 | }
201 | get(id) {
202 | if (this.has(id)) {
203 | return this.manager.get(id)
204 | }
205 | }
206 | has(id) {
207 | if (this.manager) {
208 | return this.manager.has(id)
209 | }
210 | return false
211 | }
212 | createMarker(cartesian) {
213 |
214 | const mp = this.labelOptions;
215 | const marker = new CesiumBillboard(
216 | this._viewer, {
217 | ...this.markerOptions,
218 | position: cartesian,
219 | image: this.selectedImage
220 | },
221 | mp
222 | );
223 | return marker;
224 | }
225 | changeHandler(img) {
226 | this.selectedImage = img;
227 | this.activeMarker.updateImage(this.selectedImage);
228 | }
229 | panelPosition() {
230 | if (this.activeMarker) {
231 | if (this.markMode === "marker") {
232 | const position = this.activeMarker.graphic.position.getValue(this.viewer.clock.currentTime);
233 | const pixel = cvt.cartesian2Pixel(position, this._viewer);
234 | const x = pixel.x > 170 ? pixel.x - 170 : pixel.x + 10;
235 | const y = pixel.y > 210 ? pixel.y - 240 : pixel.y + 50;
236 | return {
237 | x: x,
238 | y: y
239 | };
240 | } else {
241 | const position = this.activeMarker.graphic.position.getValue(this.viewer.clock.currentTime);
242 | const pixel = cvt.cartesian2Pixel(position, this._viewer);
243 | const x = pixel.x + 10;
244 | const y = pixel.y - 25;
245 | return {
246 | x: x,
247 | y: y
248 | };
249 | }
250 | } else {
251 | return {
252 | x: 0,
253 | y: 0
254 | };
255 | }
256 | }
257 | createLabel(cartesian) {
258 | const options = this.labelOptions;
259 | options.position = cartesian;
260 |
261 | const marker = new CesiumLabel(this._viewer, options);
262 | return marker;
263 | }
264 | createModel(cartesian) {
265 | const options = this.modelOptions;
266 | options.position = cartesian;
267 | const marker = new CesiumModel(this._viewer, options);
268 |
269 | return marker;
270 | }
271 | removeEventListener() {
272 | const pickHandler = this.pickHandler
273 | if (pickHandler) {
274 | if (!pickHandler.isDestroyed()) {
275 | // pickHandler.destroy();
276 | pickHandler.removeInputAction(LEFT_CLICK);
277 | pickHandler.removeInputAction(RIGHT_CLICK);
278 | pickHandler.removeInputAction(MOUSE_MOVE);
279 | }
280 | }
281 | }
282 | stopPick() {
283 | this.removeEventListener();
284 | if (this.activeMarker) {
285 | this.activeMarker.destroy();
286 | const evt = new CustomEvent('marker-delete', {
287 | detail: {
288 | id: this.activeMarker.mid
289 | }
290 | })
291 | window.dispatchEvent(evt)
292 |
293 | }
294 | this.activeMarker = undefined;
295 | this.cursorTip.visible = false;
296 | }
297 | zoomTo(id) {
298 | if (this.manager.has(id)) {
299 | this.manager.get(id).zoomTo();
300 | }
301 | }
302 | edit(id) {
303 | const manager = this.manager
304 | if (manager.has(id)) {
305 | const mm = manager.get(id);
306 | this.activeMarker = mm
307 | mm.startEdit()
308 | if (
309 | mm.mtype === GraphicType.MARKER ||
310 | mm.mtype === GraphicType.LABEL
311 | ) {
312 | this.markName = this.activeMarker.mname;
313 | this.markRemark = this.activeMarker.description;
314 | this.visible = true;
315 | }
316 | // this.activeMarker.zoomTo();
317 | const pixel = this.panelPosition()
318 | const evt = new CustomEvent('marker-edit', {
319 | detail: {
320 | name: this.markName,
321 | remark: this.markRemark,
322 | type: this.activeMarker.type,
323 | pos: pixel
324 | }
325 | })
326 | window.dispatchEvent(evt)
327 | }
328 | }
329 | drop(id) {
330 | const mm = this.manager.get(id);
331 | mm && mm.destroy();
332 | this.manager.delete(id);
333 | }
334 | rename(id, name) {
335 | const mm = this.manager.get(id);
336 | mm.mname = name;
337 | }
338 | select(type, id, status) {
339 | if (Cesium.defined(id)) {
340 | const manager = this.manager.get(id);
341 | if (Cesium.defined(manager)) {
342 | manager.show = status;
343 | }
344 | }
345 | if (Cesium.defined(type)) {
346 | const values = this.manager.values();
347 | for (let v of values) {
348 | if (v.mtype === type) {
349 | v.show = status;
350 | }
351 | }
352 | }
353 | }
354 | destroyPopPanle() {
355 | if (this.popDiv) {
356 | $(this.popDiv).remove()
357 | this.popDiv = undefined;
358 | }
359 | }
360 | destroy() {
361 | this.removeAll()
362 | this.destroyPopPanle()
363 | if (!this.pickHandler.isDestroyed()) {
364 | this.pickHandler.destroy()
365 | }
366 | if (!this.handler.isDestroyed()) {
367 | this.handler.destroy()
368 | }
369 | this._viewer = undefined
370 | this.labelOptions = undefined
371 | this.markerOptions = undefined;
372 | this.modelOptions = undefined
373 | }
374 | createPopPanel() {
375 | if (!Cesium.defined(this.selectedMarker)) {
376 | return;
377 | }
378 | if (this.popDiv) {
379 | this.destroyPopPanle();
380 | }
381 | const popdiv = document.createElement("div");
382 | popdiv.id = "popContainer";
383 | popdiv.className = "marker-popWin-class";
384 | const position = this.selectedMarker.position;
385 | this.popWinPosition = position;
386 | const coord = cvt.cartesian2Degrees(position, this._viewer);
387 | popdiv.style.display = "none";
388 | // const txtdiv = document.createElement("span");
389 | // txtdiv.innerText = "名称:" + (this.selectedMarker.name || "未命名");
390 | let remarkdiv
391 | remarkdiv = document.createElement('span')
392 | remarkdiv.title = this.selectedMarker.description
393 | remarkdiv.innerText = "描述:" +
394 | setString(this.selectedMarker.description || '暂无', 14)
395 | const coordsdiv = document.createElement("span");
396 | coordsdiv.innerText =
397 | "纬度:" + coord.lon.toFixed(2) + " 纬度:" + coord.lat.toFixed(2);
398 | const arrow = document.createElement("div");
399 | arrow.className = "arrow";
400 | const closebtn = document.createElement("span");
401 | closebtn.className = "iconfont iconclose closebtn";
402 | const self = this;
403 | closebtn.onclick = function() {
404 | $(self.popDiv).remove()
405 | self.popDiv = undefined;
406 | };
407 | popdiv.appendChild(closebtn);
408 | // popdiv.appendChild(txtdiv);
409 | if (remarkdiv) {
410 | popdiv.appendChild(remarkdiv)
411 | }
412 | popdiv.appendChild(coordsdiv);
413 | popdiv.appendChild(arrow);
414 | this.popDiv = popdiv;
415 | this._viewer.container.appendChild(this.popDiv);
416 | }
417 |
418 | import(feat) {
419 | if (feat.geometry.type.toUpperCase() !== "POINT") {
420 | throw new Error("无效的数据类型.");
421 | }
422 | const id = this.generateId();
423 | let marker;
424 | if (feat.properties.mtype === GraphicType.LABEL) {
425 | const lopts = CesiumLabel.defaultStyle;
426 | lopts.position = Cesium.Cartesian3.fromDegrees(
427 | ...feat.geometry.coordinates
428 | );
429 | lopts.text = feat.properties.name;
430 | marker = new CesiumLabel(this._viewer, lopts);
431 | } else {
432 | const coord = {
433 | lon: feat.geometry.coordinates[0],
434 | lat: feat.geometry.coordinates[1],
435 | height: feat.geometry.coordinates[2]
436 | };
437 | marker = CesiumBillboard.fromDegrees(this._viewer, coord);
438 | }
439 | marker.mname = feat.properties.name;
440 | marker.mid = id;
441 | this.manager.set(id, marker);
442 | const evt = new CustomEvent('marker-add', {
443 | detail: {
444 | id: marker.mid,
445 | name: marker.mname || '未命名',
446 | type: marker.mtype,
447 | description: marker.description,
448 | properties: feat.properties,
449 | position: {
450 | lon: feat.geometry.coordinates[0],
451 | lat: feat.geometry.coordinates[1],
452 | height: feat.geometry.coordinates[2]
453 | }
454 | }
455 | })
456 | window.dispatchEvent(evt)
457 | }
458 | addMarker(marker) {
459 | this.manager.set(marker.mid, marker)
460 | }
461 | export (type) {
462 | const managers = this.manager.values();
463 | const json = {
464 | type: "FeatureCollection",
465 | name: "graphic",
466 | crs: {
467 | type: "name",
468 | properties: {
469 | name: "urn:ogc:def:crs:OGC:1.3:CRS84"
470 | }
471 | },
472 | features: []
473 | };
474 |
475 | for (let m of managers) {
476 | if (m.type === type) {
477 | json.features.push(m.toGeoJson());
478 | }
479 | }
480 | const blob = new Blob([JSON.stringify(json)], {
481 | type: ""
482 | });
483 |
484 | window.saveAs(blob, type + parseInt(Cesium.getTimestamp()) + ".geojson");
485 | }
486 | set font(font) {
487 | this.labelOptions.font = font
488 | if (this.activeMarker) {
489 | this.activeMarker.font = font;
490 | }
491 | }
492 | get font() {
493 | if (this.activeMarker) {
494 | return this.activeMarker.font;
495 | }
496 | return undefined;
497 | }
498 | set color(color) {
499 | this.labelOptions.fillColor = color;
500 | if (this.activeMarker) {
501 | this.activeMarker.color = color;
502 | }
503 | }
504 | set label(option) {
505 | const keys = Object.keys(option);
506 | for (let key of keys) {
507 | this.labelOptions[key] = option[key];
508 | }
509 | // this.modelAndLabelOptions=[...this.modelAndLabelOptions,...option]
510 | if (this.activeMarker) {
511 | this.activeMarker.setLabel(this.labelOptions);
512 | }
513 | }
514 | set model(options) {
515 | this.modelOptions = {
516 | ...this.modelOptions,
517 | ...options
518 | };
519 | if (this.activeMarker) {
520 | if (options.uri) {
521 | this.activeMarker.uri = options.uri;
522 | }
523 | if (options.color) {
524 | this.activeMarker.color = options.color;
525 | }
526 | if (options.mode != undefined) {
527 | this.activeMarker.model = options.mode;
528 | }
529 | if (options.mixed != undefined) {
530 | this.activeMarker.mixed = options.mixed;
531 | }
532 | }
533 | }
534 | removeAll() {
535 | const values = this.manager.values();
536 | for (let v of values) {
537 | v.remove();
538 | v.destroy();
539 | }
540 | this.manager.clear();
541 | }
542 | cancelMark() {
543 | this.activeMarker && this.activeMarker.destroy();
544 | this.activeMarker = undefined;
545 | this.cursorTip.visible = false;
546 | const evt = new CustomEvent('marker-delete', {
547 | detail: {
548 | id: this.markerid
549 | }
550 | })
551 | window.dispatchEvent(evt)
552 | this.markName = "";
553 | this.markRemark = "";
554 | this.manager.delete(this.markerid);
555 | this.markerid = undefined;
556 | this.removeEventListener();
557 | }
558 | update(name, remark) {
559 | this.markName = name;
560 | this.markRemark = remark
561 | this.activeMarker.updateText(this.markName, this.markRemark);
562 | this.cursorTip.visible = false;
563 | this.activeMarker.stopEdit()
564 | const evt = new CustomEvent('marker-update', {
565 | detail: {
566 | id: this.activeMarker.mid,
567 | name: this.activeMarker.mname,
568 | description: this.activeMarker.description,
569 | position: cvt.toDegrees(this.activeMarker.position, this._viewer)
570 | }
571 | })
572 | window.dispatchEvent(evt)
573 | this.activeMarker = undefined;
574 | this.removeEventListener();
575 | }
576 | generateId() {
577 | return (
578 | (Math.random() * 10000000).toString(16).substr(0, 4) +
579 | "-" +
580 | new Date().getTime() +
581 | "-" +
582 | Math.random()
583 | .toString()
584 | .substr(2, 5)
585 | );
586 | }
587 | }
588 |
--------------------------------------------------------------------------------
/src/js/utils.js:
--------------------------------------------------------------------------------
1 | import $ from "jquery";
2 | import * as Cesium from 'cesium'
3 |
4 | /**
5 | *
6 | Cesium坐标转换工具
7 | */
8 | const CVT = (function() {
9 | function _() {}
10 | _.cartesian2Pixel = function(cartesian, viewer) {
11 | return Cesium.SceneTransforms.wgs84ToWindowCoordinates(
12 | viewer.scene,
13 | cartesian
14 | );
15 | };
16 | _.pixel2Cartesian = function(pixel, viewer) {
17 | if (viewer.terrainProvider instanceof Cesium.EllipsoidTerrainProvider) {
18 | return _.pixel2Cartesian1(pixel, viewer);
19 | } else {
20 | return _.pixel2Cartesian2(pixel, viewer);
21 | }
22 | };
23 | /**
24 | * 二维坐标,没有添加地形数据时调用
25 | */
26 | _.pixel2Cartesian1 = function(pixel, viewer) {
27 | const cartesian = viewer.camera.pickEllipsoid(
28 | pixel,
29 | viewer.scene.globe.ellipsoid
30 | );
31 | return cartesian;
32 | };
33 | /**
34 | * 三维坐标,添加地形数据时调用
35 | */
36 | _.pixel2Cartesian2 = function(pixel, viewer) {
37 | const ray = viewer.camera.getPickRay(pixel);
38 | const cartesian = viewer.scene.globe.pick(ray, viewer.scene);
39 | return cartesian;
40 | };
41 | _.cartesian2Radians = function(cartesian, viewer) {
42 | const ellipsoid = viewer.scene.globe.ellipsoid || Cesium.Ellipsoid.WGS84;
43 | const cartographic = Cesium.Cartographic.fromCartesian(
44 | cartesian,
45 | ellipsoid
46 | );
47 | const lon = cartographic.longitude;
48 | const lat = cartographic.latitude;
49 | const height = cartographic.height;
50 | return {
51 | lon,
52 | lat,
53 | height
54 | };
55 | };
56 | _.cartesian2Degrees = function(cartesian, viewer) {
57 | const coords = _.cartesian2Radians(cartesian, viewer);
58 | const lon = Cesium.Math.toDegrees(coords.lon);
59 | const lat = Cesium.Math.toDegrees(coords.lat);
60 | const height = coords.height;
61 | return {
62 | lon,
63 | lat,
64 | height
65 | };
66 | };
67 | _.degrees2Cartesian = function(position) {
68 | const cartesian = Cesium.Cartesian3.fromDegrees(
69 | position.lon,
70 | position.lat,
71 | position.height
72 | );
73 | return cartesian;
74 | };
75 | _.radians2Cartesian = function(position) {
76 | return Cesium.Cartesian3.fromRadians(
77 | position.lon,
78 | position.lat,
79 | position.height
80 | );
81 | };
82 | _.pixel2Degrees = function(pixel, viewer) {
83 | const cartesian = _.pixel2Cartesian(pixel, viewer);
84 | if (Cesium.defined(cartesian)) {
85 | return _.cartesian2Degrees(cartesian, viewer);
86 | }
87 | return undefined;
88 | };
89 | _.pixel2Radians = function(pixel, viewer) {
90 | const cartesian = _.pixel2Cartesian(pixel, viewer);
91 | if (Cesium.defined(cartesian)) {
92 | return _.cartesian2Radians(cartesian, viewer);
93 | }
94 | return undefined;
95 | };
96 | _.toDegrees = function(position, viewer) {
97 | if (position instanceof Cesium.Cartesian3) {
98 | return _.cartesian2Degrees(position, viewer);
99 | } else if (position instanceof Cesium.Cartesian2) {
100 | return _.pixel2Degrees(position, viewer);
101 | }
102 | };
103 | _.toRadians = function(position, viewer) {
104 | if (position instanceof Cesium.Cartesian3) {
105 | return _.cartesian2Radians(position, viewer);
106 | } else if (position instanceof Cesium.Cartesian2) {
107 | return _.pixel2Radians(position, viewer);
108 | }
109 | };
110 | _.toPixel = function(position, viewer) {
111 | if (position instanceof Cesium.Cartesian3) {
112 | return _.cartesian2Pixel(position, viewer);
113 | }
114 | };
115 | return _;
116 | })();
117 | /**
118 | *
119 | * @param {*} container 要移到的元素
120 | * @param {*} target 监听鼠标事件的元素,一般是标题栏
121 | */
122 | function moveDiv(container, target) {
123 | if (!$("#" + container)) {
124 | throw new Error("请指定要操作的元素");
125 | }
126 | if (!target) {
127 | target = container;
128 | }
129 | $("#" + target).mousedown(function(
130 | e //e鼠标事件
131 | ) {
132 | $("#" + target).css("cursor", "move"); //改变鼠标指针的形状
133 | // let offset = $("#" + container).offset(); //DIV在页面的位置
134 | let offset = $("#" + container).position(); //DIV在页面的位置
135 | let x = e.pageX - offset.left; //获得鼠标指针离DIV元素左边界的距离
136 | let y = e.pageY - offset.top; //获得鼠标指针离DIV元素上边界的距离
137 | $(document).bind("mousemove", function(
138 | ev //绑定鼠标的移动事件,因为光标在DIV元素外面也要有效果,所以要用doucment的事件,而不用DIV元素的事件
139 | ) {
140 | $("#" + target).css("cursor", "move");
141 | $("#" + container).stop(); //加上这个之后
142 | let _x = ev.pageX - x; //获得X轴方向移动的值
143 | let _y = ev.pageY - y; //获得Y轴方向移动的值
144 | $("#" + container).animate({
145 | left: _x + "px",
146 | top: _y + "px"
147 | }, 10);
148 | });
149 | });
150 | $(document).mouseup(function() {
151 | $("#" + target).css("cursor", "default");
152 | $(this).unbind("mousemove");
153 | });
154 | }
155 | /**
156 | * 获得当前视野范围
157 | * @param {Viewer} viewer
158 | */
159 | function currentExtent(viewer) {
160 | // 范围对象
161 | const extent = {};
162 |
163 | // 得到当前三维场景
164 | const scene = viewer.scene;
165 |
166 | // 得到当前三维场景的椭球体
167 | const ellipsoid = scene.globe.ellipsoid;
168 | const canvas = scene.canvas;
169 |
170 | // canvas左上角
171 | const car3_lt = viewer.camera.pickEllipsoid(
172 | new Cesium.Cartesian2(0, 0),
173 | ellipsoid
174 | );
175 |
176 | // canvas右下角
177 | const car3_rb = viewer.camera.pickEllipsoid(
178 | new Cesium.Cartesian2(canvas.width, canvas.height),
179 | ellipsoid
180 | );
181 |
182 | // 当canvas左上角和右下角全部在椭球体上
183 | if (car3_lt && car3_rb) {
184 | const carto_lt = ellipsoid.cartesianToCartographic(car3_lt);
185 | const carto_rb = ellipsoid.cartesianToCartographic(car3_rb);
186 | extent.xmin = Cesium.Math.toDegrees(carto_lt.longitude);
187 | extent.ymax = Cesium.Math.toDegrees(carto_lt.latitude);
188 | extent.xmax = Cesium.Math.toDegrees(carto_rb.longitude);
189 | extent.ymin = Cesium.Math.toDegrees(carto_rb.latitude);
190 | }
191 |
192 | // 当canvas左上角不在但右下角在椭球体上
193 | else if (!car3_lt && car3_rb) {
194 | let car3_lt2 = null;
195 | let yIndex = 0;
196 | do {
197 | // 这里每次10像素递加,一是10像素相差不大,二是为了提高程序运行效率
198 | yIndex <= canvas.height ? (yIndex += 10) : canvas.height;
199 | car3_lt2 = viewer.camera.pickEllipsoid(
200 | new Cesium.Cartesian2(0, yIndex),
201 | ellipsoid
202 | );
203 | } while (!car3_lt2);
204 | const carto_lt2 = ellipsoid.cartesianToCartographic(car3_lt2);
205 | const carto_rb2 = ellipsoid.cartesianToCartographic(car3_rb);
206 | extent.xmin = Cesium.Math.toDegrees(carto_lt2.longitude);
207 | extent.ymax = Cesium.Math.toDegrees(carto_lt2.latitude);
208 | extent.xmax = Cesium.Math.toDegrees(carto_rb2.longitude);
209 | extent.ymin = Cesium.Math.toDegrees(carto_rb2.latitude);
210 | }
211 |
212 | // 获取高度
213 | extent.height = Math.ceil(viewer.camera.positionCartographic.height);
214 | return extent;
215 | }
216 | /**
217 | * 获得当前视野中心
218 | * @param {*} viewer
219 | */
220 | const viewCenter = (
221 | viewer,
222 | inWorldCoordinates = true,
223 | result = new Cesium.Cartesian3()
224 | ) => {
225 | const scene = viewer.scene;
226 | const camera = viewer.camera;
227 | const unprojectedScratch = new Cesium.Cartographic();
228 | const rayScratch = new Cesium.Ray();
229 |
230 | if (scene.mode === Cesium.SceneMode.MORPHING) {
231 | return undefined;
232 | }
233 |
234 | // TODO bug when tracking: if entity moves the current position should be used and not only the one when starting orbiting/rotating
235 | // TODO bug when tracking: reset should reset to default view of tracked entity
236 |
237 | if (Cesium.defined(viewer.trackedEntity)) {
238 | result = viewer.trackedEntity.position.getValue(
239 | viewer.clock.currentTime,
240 | result
241 | );
242 | } else {
243 | rayScratch.origin = camera.positionWC;
244 | rayScratch.direction = camera.directionWC;
245 | result = scene.globe.pick(rayScratch, scene, result);
246 | }
247 |
248 | if (!Cesium.defined(result)) {
249 | return undefined;
250 | }
251 |
252 | if (
253 | scene.mode === Cesium.SceneMode.SCENE2D ||
254 | scene.mode === Cesium.SceneMode.COLUMBUS_VIEW
255 | ) {
256 | result = camera.worldToCameraCoordinatesPoint(result, result);
257 |
258 | if (inWorldCoordinates) {
259 | result = scene.globe.ellipsoid.cartographicToCartesian(
260 | scene.mapProjection.unproject(result, unprojectedScratch),
261 | result
262 | );
263 | }
264 | } else {
265 | if (!inWorldCoordinates) {
266 | result = camera.worldToCameraCoordinatesPoint(result, result);
267 | }
268 | }
269 |
270 | return result;
271 | };
272 | const saveCurViewerImage = (viewer, filename) => {
273 | viewer.render();
274 | if (!filename || filename == "") {
275 | filename = new Date().toLocaleString() + ".png";
276 | }
277 | const ext = filename.split(".")[1];
278 | downloadFile(filename, viewer.scene.canvas.toDataURL("image/%s" % ext));
279 | };
280 | const downloadFile = (fileName, content) => {
281 | //下载文件
282 | let aLink = document.createElement("a");
283 | let blob = base64ToBlob(content); //new Blob([content]);
284 | let evt = document.createEvent("HTMLEvents");
285 | evt.initEvent("click", true, true); //initEvent 不加后两个参数在FF下会报错 事件类型,是否冒泡,是否阻止浏览器的默认行为
286 | aLink.download = fileName;
287 | aLink.href = URL.createObjectURL(blob);
288 | aLink.click();
289 |
290 | function base64ToBlob(code) {
291 | //base64转blob
292 | let parts = code.split(";base64,");
293 | let contentType = parts[0].split(":")[1];
294 | let raw = window.atob(parts[1]);
295 | let rawLength = raw.length;
296 |
297 | let uInt8Array = new Uint8Array(rawLength);
298 |
299 | for (let i = 0; i < rawLength; ++i) {
300 | uInt8Array[i] = raw.charCodeAt(i);
301 | }
302 | return new Blob([uInt8Array], {
303 | type: contentType
304 | });
305 | }
306 | };
307 | const errroCatch = function(e, callback) {
308 | if (e.response) {
309 | callback(e.response.data);
310 | } else if (e.request) {
311 | callback(e.request);
312 | } else {
313 | callback(e.message);
314 | }
315 | };
316 | class CursorTip {
317 | constructor(text, id, viewer) {
318 | const tooltip = document.createElement("div");
319 | tooltip.id = id || "cursor-tip";
320 | tooltip.className = "cursor-tip-class";
321 | tooltip.innerHTML = text;
322 | document.body.appendChild(tooltip);
323 | this.ele = tooltip;
324 | this._visible = true;
325 | const self = this;
326 | if (viewer instanceof Cesium.Viewer) {
327 | viewer.screenSpaceEventHandler.setInputAction(e => {
328 | self.updatePosition(e.endPosition);
329 | }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
330 | }
331 | }
332 | updatePosition(pixel) {
333 | this.ele.style.left = pixel.x + 10 + "px";
334 | this.ele.style.top = pixel.y + 10 + "px";
335 | }
336 | updateText(text) {
337 | this.ele.innerHTML = text;
338 | }
339 | get visible() {
340 | return this._visible;
341 | }
342 | set visible(v) {
343 | this._visible = v;
344 | if (v) {
345 | this.ele.style.display = "block";
346 | } else {
347 | this.ele.style.display = "none";
348 | }
349 | }
350 | }
351 |
352 | function checkViewer(viewer) {
353 | if (viewer instanceof Cesium.Viewer === false) {
354 | throw new CesiumDrawError(viewer + "不是一个有效的Cesium Viewer对象")
355 | }
356 | }
357 |
358 | function checkComponent(component, object) {
359 | if (component && component._viewer instanceof Cesium.Viewer === false) {
360 | throw new CesiumDrawError('组件尚未初始化' + component._uid)
361 | } else if (!component && !Cesium.defined(object)) {
362 | throw new CesiumDrawError('组件尚未初始化')
363 | }
364 | }
365 | class CesiumDrawError extends Error {
366 | constructor(message) {
367 | super(message);
368 | this.name = 'CesiumDrawError'
369 | }
370 | }
371 |
372 | function pointVisibilityOnEarth(point, viewer) {
373 | return new Cesium.EllipsoidalOccluder(Cesium.Ellipsoid.WGS84, viewer.camera.position)
374 | .isPointVisible(point);
375 | }
376 | export {
377 | moveDiv,
378 | errroCatch,
379 | currentExtent,
380 | viewCenter,
381 | saveCurViewerImage,
382 | downloadFile,
383 | pointVisibilityOnEarth,
384 | CVT,
385 | CursorTip,
386 | checkComponent,
387 | checkViewer
388 | };
389 | export default {
390 | moveDiv,
391 | errroCatch,
392 | currentExtent,
393 | viewCenter,
394 | saveCurViewerImage,
395 | downloadFile,
396 | CVT,
397 | CursorTip,
398 | pointVisibilityOnEarth
399 | };
400 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue'
2 | import App from './App.vue'
3 | // import 'default-passive-events'
4 | import "@/assets/css/iconfont.css";
5 | import ElementPlus from 'element-plus'
6 | import 'element-plus/dist/index.css'
7 |
8 | const app = createApp(App);
9 | app.use(ElementPlus);
10 | app.mount('#app')
11 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const { defineConfig } = require("@vue/cli-service");
2 | const { DefinePlugin } = require('webpack');
3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
4 | const CopyWebpackPlugin = require('copy-webpack-plugin');
5 | const theme = "dark";
6 | const plugins = [];
7 | const externals = {
8 | }
9 | if (process.env.NODE_ENV === 'production') {
10 | plugins.push(new MiniCssExtractPlugin({
11 | filename: `theme/${theme}.css`,
12 | // chunkFilename: `css/[name].${conf.version}.css`
13 | }))
14 | externals.cesium = 'Cesium';
15 | } else {
16 | new CopyWebpackPlugin({
17 | patterns: [
18 | { from: 'node_modules/cesium/Build/Cesium/Workers', to: 'Workers' },
19 | { from: 'node_modules/cesium/Build/Cesium/ThirdParty', to: 'ThirdParty' },
20 | { from: 'node_modules/cesium/Build/Cesium/Assets', to: 'Assets' },
21 | { from: 'node_modules/cesium/Build/Cesium/Widgets', to: 'Widgets' },
22 | ]
23 | }),
24 | new DefinePlugin({
25 | CESIUM_BASE_URL: JSON.stringify('')
26 | })
27 | }
28 |
29 | module.exports = defineConfig({
30 | outputDir: "dist",
31 | transpileDependencies: true,
32 | lintOnSave: true,
33 | assetsDir: 'theme',
34 | configureWebpack: {
35 | plugins,
36 | externals
37 |
38 | },
39 | css: {
40 | loaderOptions: {
41 | sass: {
42 | additionalData: `
43 | @import "@/assets/css/theme/${theme}.scss";
44 | `,
45 | },
46 | },
47 | // 启用 CSS modules
48 | // modules: false,
49 | // 是否使用css分离插件
50 | extract: true,
51 | // 开启 CSS source maps,一般不建议开启
52 | sourceMap: false
53 | // css预设器配置项
54 | // 是否使用css分离插件 ExtractTextPlugin
55 | // extract: {
56 | // //一种方式,打包后的css 会带版本号,不改变文件名的。
57 | // filename: 'theme/[name].css'
58 | // }
59 | }
60 | });
--------------------------------------------------------------------------------