├── .browserslistrc ├── .eslintignore ├── .github ├── FUNDING.yml └── workflows │ ├── publish.yml │ └── build.yml ├── .prettierrc ├── src ├── core │ ├── images │ │ ├── circle_blue.png │ │ ├── circle_red.png │ │ └── circle_yellow.png │ ├── edit │ │ ├── EditPoint.js │ │ ├── EditBillboard.js │ │ ├── EditRectangle.js │ │ ├── EditFineArrow.js │ │ ├── EditAttackArrow.js │ │ ├── EditDoubleArrow.js │ │ ├── EditGatheringPlace.js │ │ ├── EditTailedAttackArrow.js │ │ ├── Edit.js │ │ ├── EditCircle.js │ │ ├── EditPolyline.js │ │ └── EditPolygon.js │ ├── draw │ │ ├── DrawPoint.js │ │ ├── DrawBillboard.js │ │ ├── DrawPolyline.js │ │ ├── DrawPolygon.js │ │ ├── DrawRectangle.js │ │ ├── Draw.js │ │ ├── DrawFineArrow.js │ │ ├── DrawAttackArrow.js │ │ ├── DrawDoubleArrow.js │ │ ├── DrawGatheringPlace.js │ │ ├── DrawTailedAttackArrow.js │ │ └── DrawCircle.js │ ├── graphics │ │ ├── GatheringPlaceGraphics.js │ │ ├── FineArrowGraphics.js │ │ ├── TailedAttackArrowGraphics.js │ │ ├── AttackArrowGraphics.js │ │ └── DoubleArrowGraphics.js │ └── Plot.js ├── Plot.Loader.js └── index.js ├── .gitignore ├── .editorconfig ├── .babelrc ├── CHANGES.md ├── .eslintrc ├── package.json ├── webpack.config.js ├── README_zh.md ├── README.md └── LICENSE.MD /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | /libs/ 2 | /web/ 3 | /pack/ 4 | 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | custom: ["https://www.dvgis.cn","https://www.cavencj.cn"] 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "eslintIntegration": true, 3 | "singleQuote": true, 4 | "semi": false 5 | } 6 | -------------------------------------------------------------------------------- /src/core/images/circle_blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvt3d/dc-plot/HEAD/src/core/images/circle_blue.png -------------------------------------------------------------------------------- /src/core/images/circle_red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvt3d/dc-plot/HEAD/src/core/images/circle_red.png -------------------------------------------------------------------------------- /src/core/images/circle_yellow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dvt3d/dc-plot/HEAD/src/core/images/circle_yellow.png -------------------------------------------------------------------------------- /src/Plot.Loader.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-07-01 14:25:28 4 | */ 5 | 6 | import Plot from './core/Plot' 7 | 8 | DC.mixin({ Plot }) 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log* 3 | yarn-debug.log* 4 | yarn-error.log* 5 | web/ 6 | pack/ 7 | # Editor directories and files 8 | .idea 9 | .vscode 10 | *.suo 11 | *.ntvs* 12 | *.njsproj 13 | package-lock.json 14 | .DS_Store 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- / .babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": ["> 1%", "last 2 versions", "ie >= 10"] 9 | } 10 | } 11 | ] 12 | ], 13 | "plugins": ["@babel/plugin-transform-runtime","@babel/plugin-proposal-class-properties"] 14 | } 15 | -------------------------------------------------------------------------------- /CHANGES.md: -------------------------------------------------------------------------------- 1 | # Change log 2 | 3 | ### 1.2.0 - 2020-12-29 4 | 5 | > 1.添加支持是否贴地选择 6 | > 2.重构部分标绘 7 | 8 | ### 1.1.2 - 2020-10-03 9 | 10 | > 1. 修改圆编辑的问题 11 | > 2. 修改dc-sdk的版本依赖 12 | 13 | ### 1.1.1 - 2020-10-30 14 | 15 | > 1. 修改对DC-Overlay版本的依赖 16 | 17 | ### 1.1.0 - 2020-09-19 18 | 19 | > 1. 修改框架包node下导入的方式 20 | 21 | ### 1.0.1 - 2020-09-12 22 | 23 | > 1. 解决在2D场景中无法使用的问题 24 | 25 | ### 1.0.0 - 2020-08-30 26 | 27 | > 1. 第一个版本发布 28 | 29 | ### 0.1.0 - 2020-05-12 30 | 31 | > 1. 初始化 32 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-04-03 19:13:42 4 | */ 5 | 6 | const install = function(DC) { 7 | if (!DC || !DC.init) { 8 | throw new Error('Plot: Missing DC Base') 9 | } 10 | 11 | if (!DC.ready) { 12 | throw new Error('Plot: Missing DC Core') 13 | } 14 | 15 | DC.init(() => { 16 | require('./Plot.Loader') 17 | }) 18 | } 19 | 20 | /* istanbul ignore if */ 21 | if (typeof window !== 'undefined' && window.DC) { 22 | install(window.DC) 23 | } 24 | 25 | export default { 26 | version: __VERSION__, 27 | compile_time: __TIME__, 28 | install 29 | } 30 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "babel-eslint", 4 | "parserOptions": { 5 | "sourceType": "module" 6 | }, 7 | "env": { 8 | "es6": true, 9 | "node": true, 10 | "browser": true 11 | }, 12 | "plugins": ["prettier"], 13 | "extends": ["eslint:recommended", "plugin:prettier/recommended"], 14 | "globals": { 15 | "__VERSION__": false, 16 | "__TIME__": false, 17 | "Cesium": false, 18 | "DC": false 19 | }, 20 | "rules": { 21 | "global-require": 0, 22 | "indent": 0, 23 | "no-new": 0, 24 | "camelcase": 0, 25 | "padded-blocks": 0, 26 | "no-unused-vars": 0, 27 | "no-trailing-spaces": 0, 28 | "no-mixed-spaces-and-tabs": 0, 29 | "space-before-function-paren": [0, "always"], 30 | "no-multiple-empty-lines": 0 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: publish 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | node-version: [10.x, 12.x] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Use Node.js ${{ matrix.node-version }} 24 | uses: actions/setup-node@v1 25 | with: 26 | node-version: ${{ matrix.node-version }} 27 | - name: Publish project 28 | run: yarn && yarn run publish 29 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: build 5 | 6 | on: 7 | push: 8 | branches: [master] 9 | pull_request: 10 | branches: [master] 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | strategy: 17 | matrix: 18 | node-version: [10.x, 12.x] 19 | 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Use Node.js ${{ matrix.node-version }} 23 | uses: actions/setup-node@v1 24 | with: 25 | node-version: ${{ matrix.node-version }} 26 | - name: Build project 27 | run: yarn && yarn build 28 | 29 | -------------------------------------------------------------------------------- /src/core/edit/EditPoint.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 22:04:36 4 | */ 5 | 6 | import Edit from './Edit' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class EditPoint extends Edit { 13 | constructor(overlay) { 14 | super() 15 | this._overlay = overlay 16 | this._position = undefined 17 | } 18 | 19 | _mountEntity() { 20 | this._delegate = new Cesium.Entity() 21 | this._delegate.merge(this._overlay.delegate) 22 | this._overlay.show = false 23 | this._position = this._delegate.position.getValue(Cesium.JulianDate.now()) 24 | this._delegate.position = new Cesium.CallbackProperty(() => { 25 | return this._position 26 | }) 27 | this._layer.add(this._delegate) 28 | } 29 | 30 | _onMouseMove(e) { 31 | this._tooltip.showAt(e.windowPosition, '右击结束编辑') 32 | this._position = this._clampToGround ? e.surfacePosition : e.position 33 | } 34 | 35 | _onRightClick(e) { 36 | this.unbindEvent() 37 | this._overlay.position = Transform.transformCartesianToWGS84(this._position) 38 | this._overlay.show = true 39 | this._plotEvent.raiseEvent(this._overlay) 40 | } 41 | } 42 | 43 | export default EditPoint 44 | -------------------------------------------------------------------------------- /src/core/edit/EditBillboard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 22:04:36 4 | */ 5 | 6 | import Edit from './Edit' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class EditBillboard extends Edit { 13 | constructor(overlay) { 14 | super() 15 | this._overlay = overlay 16 | this._position = undefined 17 | } 18 | 19 | _mountEntity() { 20 | this._delegate = new Cesium.Entity() 21 | this._delegate.merge(this._overlay.delegate) 22 | this._overlay.show = false 23 | this._position = this._delegate.position.getValue(Cesium.JulianDate.now()) 24 | this._delegate.position = new Cesium.CallbackProperty(() => { 25 | return this._position 26 | }) 27 | this._layer.add(this._delegate) 28 | } 29 | 30 | _onMouseMove(e) { 31 | this._tooltip.showAt(e.windowPosition, '右击结束编辑') 32 | this._position = this._clampToGround ? e.surfacePosition : e.position 33 | } 34 | 35 | _onRightClick(e) { 36 | this.unbindEvent() 37 | this._overlay.position = Transform.transformCartesianToWGS84(this._position) 38 | this._overlay.show = true 39 | this._plotEvent.raiseEvent(this._overlay) 40 | } 41 | } 42 | 43 | export default EditBillboard 44 | -------------------------------------------------------------------------------- /src/core/draw/DrawPoint.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-01-31 16:25:29 4 | */ 5 | 6 | import Draw from './Draw' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | const DEF_STYLE = { 13 | pixelSize: 10, 14 | outlineColor: Cesium.Color.BLUE, 15 | outlineWidth: 5 16 | } 17 | 18 | class DrawPoint extends Draw { 19 | constructor(style) { 20 | super() 21 | this._position = Cesium.Cartesian3.ZERO 22 | this._style = { 23 | ...DEF_STYLE, 24 | ...style 25 | } 26 | } 27 | 28 | _mountEntity() { 29 | this._delegate = new Cesium.Entity({ 30 | position: new Cesium.CallbackProperty(() => { 31 | return this._position 32 | }, false), 33 | point: { 34 | ...this._style 35 | } 36 | }) 37 | this._layer.add(this._delegate) 38 | } 39 | 40 | _onClick(e) { 41 | this._position = this._clampToGround ? e.surfacePosition : e.position 42 | this.unbindEvent() 43 | let point = new DC.Point( 44 | Transform.transformCartesianToWGS84(this._position) 45 | ) 46 | point.setStyle(this._style) 47 | this._plotEvent.raiseEvent(point) 48 | } 49 | 50 | _onMouseMove(e) { 51 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 52 | this._position = this._clampToGround ? e.surfacePosition : e.position 53 | } 54 | } 55 | 56 | export default DrawPoint 57 | -------------------------------------------------------------------------------- /src/core/draw/DrawBillboard.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-29 20:29:59 4 | */ 5 | 6 | import Draw from './Draw' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | const DEF_STYLE = {} 13 | 14 | const IMG_CIRCLE_RED = require('../images/circle_red.png') 15 | 16 | class DrawPoint extends Draw { 17 | constructor(style) { 18 | super() 19 | this._position = Cesium.Cartesian3.ZERO 20 | this._style = { 21 | image: IMG_CIRCLE_RED, 22 | ...DEF_STYLE, 23 | ...style 24 | } 25 | } 26 | 27 | _mountEntity() { 28 | this._delegate = new Cesium.Entity({ 29 | position: new Cesium.CallbackProperty(() => { 30 | return this._position 31 | }, false), 32 | billboard: { 33 | ...this._style 34 | } 35 | }) 36 | this._layer.add(this._delegate) 37 | } 38 | 39 | _onClick(e) { 40 | this._position = this._clampToGround ? e.surfacePosition : e.position 41 | this.unbindEvent() 42 | let billboard = new DC.Billboard( 43 | Transform.transformCartesianToWGS84(this._position), 44 | this._style.image 45 | ) 46 | billboard.setStyle(this._style) 47 | this._plotEvent.raiseEvent(billboard) 48 | } 49 | 50 | _onMouseMove(e) { 51 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 52 | this._position = this._clampToGround ? e.surfacePosition : e.position 53 | } 54 | } 55 | 56 | export default DrawPoint 57 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@dvgis/dc-plot", 3 | "version": "1.2.0", 4 | "description": "DC-SDK plotting tools, such as point, line, surface drawing and some military object drawing.", 5 | "main": "index.js", 6 | "repository": "https://github.com/dvgis/dc-plot.git", 7 | "author": "Caven Chen ", 8 | "license": "Apache 2.0", 9 | "homepage": "https://www.dvgis.cn", 10 | "keywords": [ 11 | "3D", 12 | "webgl", 13 | "map", 14 | "globe", 15 | "cesium", 16 | "dc-sdk", 17 | "plot" 18 | ], 19 | "scripts": { 20 | "test": "echo \"Error: no test specified\" && exit 1", 21 | "build": "yarn run clean && webpack --mode development", 22 | "publish": "yarn run clean && webpack --mode production --env.production", 23 | "clean": "rimraf dist/" 24 | }, 25 | "devDependencies": { 26 | "@babel/core": "^7.4.0", 27 | "@babel/plugin-proposal-class-properties": "^7.12.1", 28 | "@babel/plugin-transform-runtime": "^7.4.0", 29 | "@babel/polyfill": "^7.4.0", 30 | "@babel/preset-env": "^7.4.2", 31 | "babel-eslint": "^10.0.1", 32 | "babel-loader": "^8.0.5", 33 | "eslint": "^5.15.3", 34 | "eslint-config-prettier": "^4.1.0", 35 | "eslint-plugin-import": "^2.16.0", 36 | "eslint-plugin-node": "^8.0.1", 37 | "eslint-plugin-prettier": "^3.0.1", 38 | "eslint-plugin-promise": "^4.0.1", 39 | "prettier": "^1.16.4", 40 | "rimraf": "^2.6.3", 41 | "url-loader": "^1.1.2", 42 | "webpack": "^4.29.6", 43 | "webpack-cli": "^3.3.0", 44 | "webpack-glsl-loader": "^1.0.1", 45 | "webpack-obfuscator": "^1.8.0" 46 | }, 47 | "peerDependencies": { 48 | "@dvgis/dc-overlay": ">=1.3.0", 49 | "@dvgis/dc-sdk": ">=1.11.2" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/core/draw/DrawPolyline.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-29 20:54:37 4 | */ 5 | 6 | import Draw from './Draw' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | const DEF_STYLE = { 13 | width: 3, 14 | material: Cesium.Color.YELLOW.withAlpha(0.6) 15 | } 16 | 17 | class DrawPolyline extends Draw { 18 | constructor(style) { 19 | super() 20 | this._positions = [] 21 | this._style = { 22 | ...DEF_STYLE, 23 | ...style 24 | } 25 | } 26 | 27 | _mountEntity() { 28 | this._delegate = new Cesium.Entity({ 29 | polyline: { 30 | ...this._style, 31 | positions: new Cesium.CallbackProperty(() => { 32 | return this._positions 33 | }, false) 34 | } 35 | }) 36 | this._layer.add(this._delegate) 37 | } 38 | 39 | _onClick(e) { 40 | let position = this._clampToGround ? e.surfacePosition : e.position 41 | let len = this._positions.length 42 | if (len === 0) { 43 | this._positions.push(position) 44 | this.createAnchor(position) 45 | this._floatingAnchor = this.createAnchor(position) 46 | } 47 | this._positions.push(position) 48 | this.createAnchor(position) 49 | } 50 | 51 | _onMouseMove(e) { 52 | this._tooltip.showAt(e.windowPosition, '单击选择点位,右击结束') 53 | if (this._floatingAnchor) { 54 | let position = this._clampToGround ? e.surfacePosition : e.position 55 | this._floatingAnchor.position.setValue(position) 56 | this._positions.pop() 57 | this._positions.push(position) 58 | } 59 | } 60 | 61 | _onRightClick(e) { 62 | this.unbindEvent() 63 | let polyline = new DC.Polyline( 64 | Transform.transformCartesianArrayToWGS84Array(this._positions) 65 | ) 66 | polyline.setStyle(this._style) 67 | this._plotEvent.raiseEvent(polyline) 68 | } 69 | } 70 | 71 | export default DrawPolyline 72 | -------------------------------------------------------------------------------- /src/core/draw/DrawPolygon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-29 20:55:14 4 | */ 5 | 6 | import Draw from './Draw' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | const DEF_STYLE = { 13 | material: Cesium.Color.YELLOW.withAlpha(0.6), 14 | fill: true 15 | } 16 | 17 | class DrawPolygon extends Draw { 18 | constructor(style) { 19 | super() 20 | this._positions = [] 21 | this._style = { 22 | ...DEF_STYLE, 23 | ...style 24 | } 25 | } 26 | 27 | _mountEntity() { 28 | this._delegate = new Cesium.Entity({ 29 | polygon: { 30 | ...this._style, 31 | hierarchy: new Cesium.CallbackProperty(() => { 32 | if (this._positions.length > 2) { 33 | return new Cesium.PolygonHierarchy(this._positions) 34 | } else { 35 | return null 36 | } 37 | }, false) 38 | } 39 | }) 40 | this._layer.add(this._delegate) 41 | } 42 | 43 | _onClick(e) { 44 | let position = this._clampToGround ? e.surfacePosition : e.position 45 | let len = this._positions.length 46 | if (len === 0) { 47 | this._positions.push(position) 48 | this.createAnchor(position) 49 | this._floatingAnchor = this.createAnchor(position) 50 | } 51 | this._positions.push(position) 52 | this.createAnchor(position) 53 | } 54 | 55 | _onMouseMove(e) { 56 | this._tooltip.showAt(e.windowPosition, '左击选择点位,右击结束') 57 | if (this._floatingAnchor) { 58 | let position = this._clampToGround ? e.surfacePosition : e.position 59 | this._floatingAnchor.position.setValue(position) 60 | this._positions.pop() 61 | this._positions.push(position) 62 | } 63 | } 64 | 65 | _onRightClick(e) { 66 | this.unbindEvent() 67 | let polygon = new DC.Polygon( 68 | Transform.transformCartesianArrayToWGS84Array(this._positions) 69 | ) 70 | polygon.setStyle(this._style) 71 | this._plotEvent.raiseEvent(polygon) 72 | } 73 | } 74 | 75 | export default DrawPolygon 76 | -------------------------------------------------------------------------------- /src/core/draw/DrawRectangle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-29 21:30:41 4 | */ 5 | 6 | import Draw from './Draw' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | const DEF_STYLE = { 13 | material: Cesium.Color.YELLOW.withAlpha(0.6) 14 | } 15 | 16 | class DrawRectangle extends Draw { 17 | constructor(style) { 18 | super() 19 | this._positions = [] 20 | this._style = { 21 | ...DEF_STYLE, 22 | ...style 23 | } 24 | } 25 | 26 | _mountEntity() { 27 | this._delegate = new Cesium.Entity({ 28 | rectangle: { 29 | ...this._style, 30 | coordinates: new Cesium.CallbackProperty(time => { 31 | if (this._positions.length > 1) { 32 | return Cesium.Rectangle.fromCartesianArray(this._positions) 33 | } else { 34 | return null 35 | } 36 | }, false) 37 | } 38 | }) 39 | this._layer.add(this._delegate) 40 | } 41 | 42 | _onClick(e) { 43 | let position = this._clampToGround ? e.surfacePosition : e.position 44 | let len = this._positions.length 45 | if (len === 0) { 46 | this._positions.push(position) 47 | this.createAnchor(position) 48 | this._floatingAnchor = this.createAnchor(position) 49 | } 50 | this._positions.push(position) 51 | this.createAnchor(position) 52 | if (len > 1) { 53 | this._positions.pop() 54 | this.unbindEvent() 55 | let rectangle = new DC.Rectangle( 56 | Transform.transformCartesianArrayToWGS84Array(this._positions) 57 | ) 58 | rectangle.setStyle(this._style) 59 | this._plotEvent.raiseEvent(rectangle) 60 | } 61 | } 62 | 63 | _onMouseMove(e) { 64 | this._tooltip.showAt(e.windowPosition, '左击选择点位') 65 | if (this._floatingAnchor) { 66 | let position = this._clampToGround ? e.surfacePosition : e.position 67 | this._floatingAnchor.position.setValue(position) 68 | this._positions.pop() 69 | this._positions.push(position) 70 | } 71 | } 72 | } 73 | 74 | export default DrawRectangle 75 | -------------------------------------------------------------------------------- /src/core/draw/Draw.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-01-31 19:45:32 4 | */ 5 | 6 | const { MouseEventType } = DC 7 | const { Cesium } = DC.Namespace 8 | 9 | class Draw { 10 | constructor() { 11 | this._viewer = undefined 12 | this._delegate = undefined 13 | this._floatingAnchor = undefined 14 | this._clampToGround = true 15 | this._tooltip = undefined 16 | this._layer = undefined 17 | this._plotEvent = undefined 18 | this._options = {} 19 | } 20 | 21 | _mountEntity() {} 22 | 23 | _onClick(e) {} 24 | 25 | _onMouseMove(e) {} 26 | 27 | _onRightClick(e) {} 28 | 29 | bindEvent() { 30 | this._viewer.on(MouseEventType.CLICK, this._onClick, this) 31 | this._viewer.on(MouseEventType.MOUSE_MOVE, this._onMouseMove, this) 32 | this._viewer.on(MouseEventType.RIGHT_CLICK, this._onRightClick, this) 33 | } 34 | 35 | unbindEvent() { 36 | this._viewer.off(MouseEventType.CLICK, this._onClick, this) 37 | this._viewer.off(MouseEventType.MOUSE_MOVE, this._onMouseMove, this) 38 | this._viewer.off(MouseEventType.RIGHT_CLICK, this._onRightClick, this) 39 | } 40 | 41 | createAnchor(position, isCenter = false) { 42 | return this._layer.add({ 43 | position: position, 44 | billboard: { 45 | image: isCenter ? this._options.icon_center : this._options.icon_anchor, 46 | width: this._options.icon_size[0], 47 | height: this._options.icon_size[1], 48 | eyeOffset: new Cesium.Cartesian3(0, 0, -500), 49 | heightReference: 50 | this._viewer.scene.mode === Cesium.SceneMode.SCENE3D && 51 | this._clampToGround 52 | ? Cesium.HeightReference.CLAMP_TO_GROUND 53 | : Cesium.HeightReference.NONE 54 | } 55 | }) 56 | } 57 | 58 | start(plot) { 59 | this._viewer = plot.viewer 60 | this._tooltip = plot.viewer.tooltip 61 | this._layer = plot.overlayLayer 62 | this._plotEvent = plot.plotEvent 63 | this._options = plot.options 64 | this._clampToGround = plot.options.clampToGround ?? true 65 | this._mountEntity() 66 | this.bindEvent() 67 | } 68 | } 69 | 70 | export default Draw 71 | -------------------------------------------------------------------------------- /src/core/graphics/GatheringPlaceGraphics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 17:17:52 4 | */ 5 | 6 | const { Transform, Parse, PlotUtil } = DC 7 | 8 | const { Cesium } = DC.Namespace 9 | 10 | const HALF_PI = Math.PI / 2 11 | 12 | const FITTING_COUNT = 100 13 | 14 | class GatheringPlaceGraphics { 15 | constructor(options) { 16 | this._positions = options?.positions || [] 17 | this.t = 0.4 18 | } 19 | 20 | set positions(positions) { 21 | this._positions = positions 22 | } 23 | 24 | get positions() { 25 | return this._positions 26 | } 27 | 28 | get hierarchy() { 29 | return this._createHierarchy() 30 | } 31 | 32 | _createHierarchy() { 33 | let pnts = Parse.parsePolygonCoordToArray( 34 | Transform.transformCartesianArrayToWGS84Array(this._positions) 35 | )[0] 36 | if (this._positions.length === 2) { 37 | let mid = PlotUtil.mid(pnts[0], pnts[1]) 38 | let d = PlotUtil.distance(pnts[0], mid) / 0.9 39 | let pnt = PlotUtil.getThirdPoint(pnts[0], mid, HALF_PI, d, true) 40 | pnts = [pnts[0], pnt, pnts[1]] 41 | } 42 | let mid = PlotUtil.mid(pnts[0], pnts[2]) 43 | pnts.push(mid, pnts[0], pnts[1]) 44 | let normals = [] 45 | for (let i = 0; i < pnts.length - 2; i++) { 46 | let pnt1 = pnts[i] 47 | let pnt2 = pnts[i + 1] 48 | let pnt3 = pnts[i + 2] 49 | let normalPoints = PlotUtil.getBisectorNormals(this.t, pnt1, pnt2, pnt3) 50 | normals = normals.concat(normalPoints) 51 | } 52 | let count = normals.length 53 | normals = [normals[count - 1]].concat(normals.slice(0, count - 1)) 54 | let pList = [] 55 | for (let i = 0; i < pnts.length - 2; i++) { 56 | let pnt1 = pnts[i] 57 | let pnt2 = pnts[i + 1] 58 | pList.push(pnt1) 59 | for (let t = 0; t <= FITTING_COUNT; t++) { 60 | let pnt = PlotUtil.getCubicValue( 61 | t / FITTING_COUNT, 62 | pnt1, 63 | normals[i * 2], 64 | normals[i * 2 + 1], 65 | pnt2 66 | ) 67 | pList.push(pnt) 68 | } 69 | pList.push(pnt2) 70 | } 71 | return new Cesium.PolygonHierarchy( 72 | Transform.transformWGS84ArrayToCartesianArray(Parse.parsePositions(pList)) 73 | ) 74 | } 75 | } 76 | 77 | export default GatheringPlaceGraphics 78 | -------------------------------------------------------------------------------- /src/core/draw/DrawFineArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 16:43:12 4 | */ 5 | 6 | import Draw from './Draw' 7 | import FineArrowGraphics from '../graphics/FineArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | const DEF_STYLE = { 14 | material: Cesium.Color.YELLOW.withAlpha(0.6), 15 | fill: true 16 | } 17 | 18 | class DrawFineArrow extends Draw { 19 | constructor(style) { 20 | super() 21 | this._positions = [] 22 | this._floatingAnchor = undefined 23 | this._style = { 24 | ...DEF_STYLE, 25 | ...style 26 | } 27 | this._graphics = new FineArrowGraphics() 28 | } 29 | 30 | _mountEntity() { 31 | this._delegate = new Cesium.Entity({ 32 | polygon: { 33 | ...this._style, 34 | hierarchy: new Cesium.CallbackProperty(() => { 35 | if (this._positions.length > 1) { 36 | this._graphics.positions = this._positions 37 | return this._graphics.hierarchy 38 | } else { 39 | return null 40 | } 41 | }, false) 42 | } 43 | }) 44 | this._layer.add(this._delegate) 45 | } 46 | 47 | _onClick(e) { 48 | let position = this._clampToGround ? e.surfacePosition : e.position 49 | let len = this._positions.length 50 | if (len === 0) { 51 | this._positions.push(position) 52 | this.createAnchor(position) 53 | this._floatingAnchor = this.createAnchor(position) 54 | } 55 | this._positions.push(position) 56 | this._graphics.positions = this._positions 57 | this.createAnchor(position) 58 | if (len > 1) { 59 | this._positions.pop() 60 | this.unbindEvent() 61 | let fineArrow = new DC.FineArrow( 62 | Transform.transformCartesianArrayToWGS84Array(this._positions) 63 | ) 64 | fineArrow.setStyle(this._style) 65 | this._plotEvent.raiseEvent(fineArrow) 66 | } 67 | } 68 | 69 | _onMouseMove(e) { 70 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 71 | if (this._floatingAnchor) { 72 | let position = this._clampToGround ? e.surfacePosition : e.position 73 | this._floatingAnchor.position.setValue(position) 74 | this._positions.pop() 75 | this._positions.push(position) 76 | } 77 | } 78 | } 79 | 80 | export default DrawFineArrow 81 | -------------------------------------------------------------------------------- /src/core/draw/DrawAttackArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 16:43:12 4 | */ 5 | 6 | import Draw from './Draw' 7 | import AttackArrowGraphics from '../graphics/AttackArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | const DEF_STYLE = { 14 | material: Cesium.Color.YELLOW.withAlpha(0.6), 15 | fill: true 16 | } 17 | 18 | class DrawAttackArrow extends Draw { 19 | constructor(style) { 20 | super() 21 | this._positions = [] 22 | this._floatingAnchor = undefined 23 | this._style = { 24 | ...DEF_STYLE, 25 | ...style 26 | } 27 | this._graphics = new AttackArrowGraphics() 28 | } 29 | 30 | _mountEntity() { 31 | this._delegate = new Cesium.Entity({ 32 | polygon: { 33 | ...this._style, 34 | hierarchy: new Cesium.CallbackProperty(() => { 35 | if (this._positions.length > 2) { 36 | this._graphics.positions = this._positions 37 | return this._graphics.hierarchy 38 | } else { 39 | return null 40 | } 41 | }, false) 42 | } 43 | }) 44 | this._layer.add(this._delegate) 45 | } 46 | 47 | _onClick(e) { 48 | let len = this._positions.length 49 | let position = this._clampToGround ? e.surfacePosition : e.position 50 | if (len === 0) { 51 | this._positions.push(position) 52 | this.createAnchor(position) 53 | this._floatingAnchor = this.createAnchor(position) 54 | } 55 | this._positions.push(position) 56 | this._graphics.positions = this._positions 57 | this.createAnchor(position) 58 | if (len > 2) { 59 | this._positions.pop() 60 | this.unbindEvent() 61 | let attackArrow = new DC.AttackArrow( 62 | Transform.transformCartesianArrayToWGS84Array(this._positions) 63 | ) 64 | attackArrow.setStyle(this._style) 65 | this._plotEvent.raiseEvent(attackArrow) 66 | } 67 | } 68 | 69 | _onMouseMove(e) { 70 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 71 | if (this._floatingAnchor) { 72 | let position = this._clampToGround ? e.surfacePosition : e.position 73 | this._floatingAnchor.position.setValue(position) 74 | this._positions.pop() 75 | this._positions.push(position) 76 | } 77 | } 78 | } 79 | 80 | export default DrawAttackArrow 81 | -------------------------------------------------------------------------------- /src/core/draw/DrawDoubleArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 16:43:12 4 | */ 5 | 6 | import Draw from './Draw' 7 | import DoubleArrowGraphics from '../graphics/DoubleArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | const DEF_STYLE = { 14 | material: Cesium.Color.YELLOW.withAlpha(0.6), 15 | fill: true 16 | } 17 | 18 | class DrawDoubleArrow extends Draw { 19 | constructor(style) { 20 | super() 21 | this._positions = [] 22 | this._floatingAnchor = undefined 23 | this._style = { 24 | ...DEF_STYLE, 25 | ...style 26 | } 27 | this._graphics = new DoubleArrowGraphics() 28 | } 29 | 30 | _mountEntity() { 31 | this._delegate = new Cesium.Entity({ 32 | polygon: { 33 | ...this._style, 34 | hierarchy: new Cesium.CallbackProperty(() => { 35 | if (this._positions.length > 2) { 36 | this._graphics.positions = this._positions 37 | return this._graphics.hierarchy 38 | } else { 39 | return null 40 | } 41 | }, false) 42 | } 43 | }) 44 | this._layer.add(this._delegate) 45 | } 46 | 47 | _onClick(e) { 48 | let len = this._positions.length 49 | let position = this._clampToGround ? e.surfacePosition : e.position 50 | if (len === 0) { 51 | this._positions.push(position) 52 | this.createAnchor(position) 53 | this._floatingAnchor = this.createAnchor(position) 54 | } 55 | this._positions.push(position) 56 | this._graphics.positions = this._positions 57 | this.createAnchor(position) 58 | if (len > 3) { 59 | this._positions.pop() 60 | this.unbindEvent() 61 | let doubleArrow = new DC.DoubleArrow( 62 | Transform.transformCartesianArrayToWGS84Array(this._positions) 63 | ) 64 | doubleArrow.setStyle(this._style) 65 | this._plotEvent.raiseEvent(doubleArrow) 66 | } 67 | } 68 | 69 | _onMouseMove(e) { 70 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 71 | if (this._floatingAnchor) { 72 | let position = this._clampToGround ? e.surfacePosition : e.position 73 | this._floatingAnchor.position.setValue(position) 74 | this._positions.pop() 75 | this._positions.push(position) 76 | } 77 | } 78 | } 79 | 80 | export default DrawDoubleArrow 81 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 09:15:33 4 | */ 5 | 6 | const path = require('path') 7 | const webpack = require('webpack') 8 | const packageInfo = require('./package.json') 9 | const JavaScriptObfuscator = require('webpack-obfuscator') 10 | 11 | function getTime() { 12 | let now = new Date() 13 | let m = now.getMonth() + 1 14 | m = m < 10 ? '0' + m : m 15 | let d = now.getDate() 16 | d = d < 10 ? '0' + d : d 17 | return `${now.getFullYear()}-${m}-${d}` 18 | } 19 | 20 | function resolve(dir) { 21 | return path.join(__dirname, '.', dir) 22 | } 23 | 24 | module.exports = env => { 25 | const IS_PROD = (env && env.production) || false 26 | const publicPath = IS_PROD ? '/' : '/' 27 | let plugins = [ 28 | new webpack.DefinePlugin({ 29 | __VERSION__: JSON.stringify(packageInfo.version), 30 | __TIME__: JSON.stringify(getTime()) 31 | }) 32 | ] 33 | if (IS_PROD) { 34 | plugins.push(new webpack.NoEmitOnErrorsPlugin()) 35 | plugins.push( 36 | new JavaScriptObfuscator( 37 | { 38 | rotateStringArray: true 39 | }, 40 | [] 41 | ) 42 | ) 43 | } 44 | return { 45 | entry: { 46 | 'dc.plot': ['entry'] 47 | }, 48 | devtool: IS_PROD ? false : 'source-map', 49 | output: { 50 | filename: IS_PROD ? '[name].min.js' : '[name].js', 51 | path: path.resolve(__dirname, 'dist'), 52 | publicPath: publicPath, 53 | library: 'DcPlot', 54 | libraryTarget: 'umd', 55 | umdNamedDefine: true 56 | }, 57 | module: { 58 | unknownContextCritical: false, 59 | rules: [ 60 | { 61 | test: /\.js$/, 62 | exclude: /node_modules/, 63 | loader: 'babel-loader', 64 | options: { 65 | presets: ['@babel/preset-env'], 66 | compact: false, 67 | ignore: ['checkTree'] 68 | } 69 | }, 70 | { 71 | test: /\.(png|jpg|gif|svg|eot|ttf|woff|woff2)$/, 72 | loader: 'url-loader', 73 | options: { 74 | limit: 20000 75 | } 76 | } 77 | ] 78 | }, 79 | resolve: { 80 | extensions: ['.js', '.json', '.css'], 81 | alias: { 82 | '@': resolve('src'), 83 | entry: './src/index.js' 84 | } 85 | }, 86 | plugins 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/core/draw/DrawGatheringPlace.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 17:22:21 4 | */ 5 | 6 | import Draw from './Draw' 7 | import GatheringPlaceGraphics from '../graphics/GatheringPlaceGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | const DEF_STYLE = { 14 | material: Cesium.Color.YELLOW.withAlpha(0.6), 15 | fill: true 16 | } 17 | 18 | class DrawGatheringPlace extends Draw { 19 | constructor(style) { 20 | super() 21 | this._positions = [] 22 | this._floatingAnchor = undefined 23 | this._style = { 24 | ...DEF_STYLE, 25 | ...style 26 | } 27 | this._graphics = new GatheringPlaceGraphics() 28 | } 29 | 30 | _mountEntity() { 31 | this._delegate = new Cesium.Entity({ 32 | polygon: { 33 | ...this._style, 34 | hierarchy: new Cesium.CallbackProperty(() => { 35 | if (this._positions.length > 1) { 36 | this._graphics.positions = this._positions 37 | return this._graphics.hierarchy 38 | } else { 39 | return null 40 | } 41 | }, false) 42 | } 43 | }) 44 | this._layer.add(this._delegate) 45 | } 46 | 47 | _onClick(e) { 48 | let position = this._clampToGround ? e.surfacePosition : e.position 49 | let len = this._positions.length 50 | if (len === 0) { 51 | this._positions.push(position) 52 | this.createAnchor(position) 53 | this._floatingAnchor = this.createAnchor(position) 54 | } 55 | this._positions.push(position) 56 | this._graphics.positions = this._positions 57 | this.createAnchor(position) 58 | if (len > 2) { 59 | this._positions.pop() 60 | this.unbindEvent() 61 | let gatheringPlace = new DC.GatheringPlace( 62 | Transform.transformCartesianArrayToWGS84Array(this._positions) 63 | ) 64 | gatheringPlace.setStyle(this._style) 65 | this._plotEvent.raiseEvent(gatheringPlace) 66 | } 67 | } 68 | 69 | _onMouseMove(e) { 70 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 71 | if (this._floatingAnchor) { 72 | let position = this._clampToGround ? e.surfacePosition : e.position 73 | this._floatingAnchor.position.setValue(position) 74 | this._positions.pop() 75 | this._positions.push(position) 76 | } 77 | } 78 | } 79 | 80 | export default DrawGatheringPlace 81 | -------------------------------------------------------------------------------- /src/core/draw/DrawTailedAttackArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 16:43:12 4 | */ 5 | 6 | import Draw from './Draw' 7 | import TailedAttackArrowGraphics from '../graphics/TailedAttackArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | const DEF_STYLE = { 14 | material: Cesium.Color.YELLOW.withAlpha(0.6), 15 | fill: true 16 | } 17 | 18 | class DrawTailedAttackArrow extends Draw { 19 | constructor(style) { 20 | super() 21 | this._positions = [] 22 | this._floatingAnchor = undefined 23 | this._style = { 24 | ...DEF_STYLE, 25 | ...style 26 | } 27 | this._graphics = new TailedAttackArrowGraphics() 28 | } 29 | 30 | _mountEntity() { 31 | this._delegate = new Cesium.Entity({ 32 | polygon: { 33 | ...this._style, 34 | hierarchy: new Cesium.CallbackProperty(() => { 35 | if (this._positions.length > 2) { 36 | this._graphics.positions = this._positions 37 | return this._graphics.hierarchy 38 | } else { 39 | return null 40 | } 41 | }, false) 42 | } 43 | }) 44 | this._layer.add(this._delegate) 45 | } 46 | 47 | _onClick(e) { 48 | let position = this._clampToGround ? e.surfacePosition : e.position 49 | let len = this._positions.length 50 | if (len === 0) { 51 | this._positions.push(position) 52 | this.createAnchor(position) 53 | this._floatingAnchor = this.createAnchor(position) 54 | } 55 | this._positions.push(position) 56 | this._graphics.positions = this._positions 57 | this.createAnchor(position) 58 | if (len > 2) { 59 | this._positions.pop() 60 | this.unbindEvent() 61 | let tailedAttackArrow = new DC.TailedAttackArrow( 62 | Transform.transformCartesianArrayToWGS84Array(this._positions) 63 | ) 64 | tailedAttackArrow.setStyle(this._style) 65 | this._plotEvent.raiseEvent(tailedAttackArrow) 66 | } 67 | } 68 | 69 | _onMouseMove(e) { 70 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 71 | if (this._floatingAnchor) { 72 | let position = this._clampToGround ? e.surfacePosition : e.position 73 | this._floatingAnchor.position.setValue(position) 74 | this._positions.pop() 75 | this._positions.push(position) 76 | } 77 | } 78 | } 79 | 80 | export default DrawTailedAttackArrow 81 | -------------------------------------------------------------------------------- /src/core/graphics/FineArrowGraphics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 17:10:33 4 | */ 5 | 6 | const { Transform, Parse, PlotUtil } = DC 7 | 8 | const { Cesium } = DC.Namespace 9 | 10 | const HALF_PI = Math.PI / 2 11 | 12 | class FineArrowGraphics { 13 | constructor(options) { 14 | this._positions = options?.positions || [] 15 | this.tailWidthFactor = 0.15 16 | this.neckWidthFactor = 0.2 17 | this.headWidthFactor = 0.25 18 | this.headAngle = Math.PI / 8.5 19 | this.neckAngle = Math.PI / 13 20 | } 21 | 22 | set positions(positions) { 23 | this._positions = positions 24 | } 25 | 26 | get positions() { 27 | return this._positions 28 | } 29 | 30 | get hierarchy() { 31 | return this._createHierarchy() 32 | } 33 | 34 | _createHierarchy() { 35 | let pnts = Parse.parsePolygonCoordToArray( 36 | Transform.transformCartesianArrayToWGS84Array(this._positions) 37 | )[0] 38 | let pnt1 = pnts[0] 39 | let pnt2 = pnts[1] 40 | let len = PlotUtil.getBaseLength(pnts) 41 | let tailWidth = len * this.tailWidthFactor 42 | let neckWidth = len * this.neckWidthFactor 43 | let headWidth = len * this.headWidthFactor 44 | let tailLeft = PlotUtil.getThirdPoint(pnt2, pnt1, HALF_PI, tailWidth, true) 45 | let tailRight = PlotUtil.getThirdPoint( 46 | pnt2, 47 | pnt1, 48 | HALF_PI, 49 | tailWidth, 50 | false 51 | ) 52 | let headLeft = PlotUtil.getThirdPoint( 53 | pnt1, 54 | pnt2, 55 | this.headAngle, 56 | headWidth, 57 | false 58 | ) 59 | let headRight = PlotUtil.getThirdPoint( 60 | pnt1, 61 | pnt2, 62 | this.headAngle, 63 | headWidth, 64 | true 65 | ) 66 | let neckLeft = PlotUtil.getThirdPoint( 67 | pnt1, 68 | pnt2, 69 | this.neckAngle, 70 | neckWidth, 71 | false 72 | ) 73 | let neckRight = PlotUtil.getThirdPoint( 74 | pnt1, 75 | pnt2, 76 | this.neckAngle, 77 | neckWidth, 78 | true 79 | ) 80 | return new Cesium.PolygonHierarchy( 81 | Transform.transformWGS84ArrayToCartesianArray( 82 | Parse.parsePositions([ 83 | tailLeft, 84 | neckLeft, 85 | headLeft, 86 | pnt2, 87 | headRight, 88 | neckRight, 89 | tailRight 90 | ]) 91 | ) 92 | ) 93 | } 94 | } 95 | 96 | export default FineArrowGraphics 97 | -------------------------------------------------------------------------------- /src/core/graphics/TailedAttackArrowGraphics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 17:26:34 4 | */ 5 | 6 | import AttackArrowGraphics from './AttackArrowGraphics' 7 | 8 | const { Transform, Parse, PlotUtil } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class TailedAttackArrowGraphics extends AttackArrowGraphics { 13 | constructor(options) { 14 | super(options) 15 | this.headHeightFactor = 0.18 16 | this.headWidthFactor = 0.3 17 | this.neckHeightFactor = 0.85 18 | this.neckWidthFactor = 0.15 19 | this.tailWidthFactor = 0.1 20 | this.headTailFactor = 0.8 21 | this.swallowTailFactor = 1 22 | } 23 | 24 | _createHierarchy() { 25 | let pnts = Parse.parsePolygonCoordToArray( 26 | Transform.transformCartesianArrayToWGS84Array(this._positions) 27 | )[0] 28 | let tailLeft = pnts[0] 29 | let tailRight = pnts[1] 30 | if (PlotUtil.isClockWise(pnts[0], pnts[1], pnts[2])) { 31 | tailLeft = pnts[1] 32 | tailRight = pnts[0] 33 | } 34 | let midTail = PlotUtil.mid(tailLeft, tailRight) 35 | let bonePnts = [midTail].concat(pnts.slice(2)) 36 | let headPnts = this._getArrowHeadPoints(bonePnts, tailLeft, tailRight) 37 | let neckLeft = headPnts[0] 38 | let neckRight = headPnts[4] 39 | let tailWidth = PlotUtil.distance(tailLeft, tailRight) 40 | let allLen = PlotUtil.getBaseLength(bonePnts) 41 | let len = allLen * this.tailWidthFactor * this.swallowTailFactor 42 | let swallowTailPnt = PlotUtil.getThirdPoint( 43 | bonePnts[1], 44 | bonePnts[0], 45 | 0, 46 | len, 47 | true 48 | ) 49 | let factor = tailWidth / allLen 50 | let bodyPnts = this._getArrowBodyPoints( 51 | bonePnts, 52 | neckLeft, 53 | neckRight, 54 | factor 55 | ) 56 | let count = bodyPnts.length 57 | let leftPnts = [tailLeft].concat(bodyPnts.slice(0, count / 2)) 58 | leftPnts.push(neckLeft) 59 | let rightPnts = [tailRight].concat(bodyPnts.slice(count / 2, count)) 60 | rightPnts.push(neckRight) 61 | leftPnts = PlotUtil.getQBSplinePoints(leftPnts) 62 | rightPnts = PlotUtil.getQBSplinePoints(rightPnts) 63 | return new Cesium.PolygonHierarchy( 64 | Transform.transformWGS84ArrayToCartesianArray( 65 | Parse.parsePositions( 66 | leftPnts.concat(headPnts, rightPnts.reverse(), [ 67 | swallowTailPnt, 68 | leftPnts[0] 69 | ]) 70 | ) 71 | ) 72 | ) 73 | } 74 | } 75 | 76 | export default TailedAttackArrowGraphics 77 | -------------------------------------------------------------------------------- /src/core/edit/EditRectangle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:41:34 4 | */ 5 | 6 | import Edit from './Edit' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class EditRectangle extends Edit { 13 | constructor(overlay) { 14 | super() 15 | this._overlay = overlay 16 | this._positions = [] 17 | } 18 | 19 | _mountEntity() { 20 | this._delegate = new Cesium.Entity() 21 | this._delegate.merge(this._overlay.delegate) 22 | this._overlay.show = false 23 | this._delegate.rectangle.coordinates = new Cesium.CallbackProperty(time => { 24 | if (this._positions.length > 1) { 25 | return Cesium.Rectangle.fromCartesianArray(this._positions) 26 | } else { 27 | return null 28 | } 29 | }, false) 30 | this._layer.add(this._delegate) 31 | } 32 | 33 | _mountAnchor() { 34 | this._positions = [].concat( 35 | Transform.transformWGS84ArrayToCartesianArray(this._overlay.positions) 36 | ) 37 | this._positions.forEach((item, index) => { 38 | this.createAnchor(item, index) 39 | }) 40 | } 41 | 42 | _onClick(e) { 43 | if (this._isMoving) { 44 | this._isMoving = false 45 | if (this._pickedAnchor && this._pickedAnchor.position) { 46 | let position = this._clampToGround ? e.surfacePosition : e.position 47 | this._pickedAnchor.position.setValue(position) 48 | let properties = this._pickedAnchor.properties.getValue( 49 | Cesium.JulianDate.now() 50 | ) 51 | this._positions[properties.index] = position 52 | } 53 | } else { 54 | this._isMoving = true 55 | if (!e.target || !e.target.id) { 56 | return false 57 | } 58 | this._pickedAnchor = e.target.id 59 | } 60 | } 61 | 62 | _onMouseMove(e) { 63 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 64 | if (!this._isMoving) { 65 | return 66 | } 67 | if (this._pickedAnchor && this._pickedAnchor.position) { 68 | let properties = this._pickedAnchor.properties.getValue( 69 | Cesium.JulianDate.now() 70 | ) 71 | let position = this._clampToGround ? e.surfacePosition : e.position 72 | this._pickedAnchor.position.setValue(position) 73 | this._positions[properties.index] = position 74 | } 75 | } 76 | 77 | _onRightClick(e) { 78 | this.unbindEvent() 79 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 80 | this._positions 81 | ) 82 | this._overlay.show = true 83 | this._plotEvent.raiseEvent(this._overlay) 84 | } 85 | } 86 | 87 | export default EditRectangle 88 | -------------------------------------------------------------------------------- /src/core/edit/EditFineArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:46:07 4 | */ 5 | 6 | import Edit from './Edit' 7 | import FineArrowGraphics from '../graphics/FineArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | class EditFineArrow extends Edit { 14 | constructor(overlay) { 15 | super() 16 | this._overlay = overlay 17 | this._positions = [] 18 | this._graphics = new FineArrowGraphics() 19 | } 20 | 21 | _mountEntity() { 22 | this._delegate = new Cesium.Entity() 23 | this._delegate.merge(this._overlay.delegate) 24 | this._overlay.show = false 25 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(() => { 26 | if (this._positions.length > 1) { 27 | this._graphics.positions = this._positions 28 | return this._graphics.hierarchy 29 | } else { 30 | return null 31 | } 32 | }, false) 33 | this._layer.add(this._delegate) 34 | } 35 | 36 | _mountAnchor() { 37 | this._positions = [].concat( 38 | Transform.transformWGS84ArrayToCartesianArray(this._overlay.positions) 39 | ) 40 | this._positions.forEach((item, index) => { 41 | this.createAnchor(item, index) 42 | }) 43 | } 44 | 45 | _onClick(e) { 46 | if (this._isMoving) { 47 | this._isMoving = false 48 | if (this._pickedAnchor && this._pickedAnchor.position) { 49 | let position = this._clampToGround ? e.surfacePosition : e.position 50 | this._pickedAnchor.position.setValue(position) 51 | let properties = this._pickedAnchor.properties.getValue( 52 | Cesium.JulianDate.now() 53 | ) 54 | this._positions[properties.index] = position 55 | } 56 | } else { 57 | this._isMoving = true 58 | if (!e.target || !e.target.id) { 59 | return false 60 | } 61 | this._pickedAnchor = e.target.id 62 | } 63 | } 64 | 65 | _onMouseMove(e) { 66 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 67 | if (!this._isMoving) { 68 | return 69 | } 70 | if (this._pickedAnchor && this._pickedAnchor.position) { 71 | let properties = this._pickedAnchor.properties.getValue( 72 | Cesium.JulianDate.now() 73 | ) 74 | let position = this._clampToGround ? e.surfacePosition : e.position 75 | this._pickedAnchor.position.setValue(position) 76 | this._positions[properties.index] = position 77 | } 78 | } 79 | 80 | _onRightClick(e) { 81 | this.unbindEvent() 82 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 83 | this._positions 84 | ) 85 | this._overlay.show = true 86 | this._plotEvent.raiseEvent(this._overlay) 87 | } 88 | } 89 | 90 | export default EditFineArrow 91 | -------------------------------------------------------------------------------- /src/core/edit/EditAttackArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:46:07 4 | */ 5 | 6 | import Edit from './Edit' 7 | import AttackArrowGraphics from '../graphics/AttackArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | class EditAttackArrow extends Edit { 14 | constructor(overlay) { 15 | super() 16 | this._overlay = overlay 17 | this._positions = [] 18 | this._graphics = new AttackArrowGraphics() 19 | } 20 | 21 | _mountEntity() { 22 | this._delegate = new Cesium.Entity() 23 | this._delegate.merge(this._overlay.delegate) 24 | this._overlay.show = false 25 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(() => { 26 | if (this._positions.length > 2) { 27 | this._graphics.positions = this._positions 28 | return this._graphics.hierarchy 29 | } else { 30 | return null 31 | } 32 | }, false) 33 | this._layer.add(this._delegate) 34 | } 35 | 36 | _mountAnchor() { 37 | this._positions = [].concat( 38 | Transform.transformWGS84ArrayToCartesianArray(this._overlay.positions) 39 | ) 40 | this._positions.forEach((item, index) => { 41 | this.createAnchor(item, index) 42 | }) 43 | } 44 | 45 | _onClick(e) { 46 | if (this._isMoving) { 47 | this._isMoving = false 48 | if (this._pickedAnchor && this._pickedAnchor.position) { 49 | let position = this._clampToGround ? e.surfacePosition : e.position 50 | this._pickedAnchor.position.setValue(position) 51 | let properties = this._pickedAnchor.properties.getValue( 52 | Cesium.JulianDate.now() 53 | ) 54 | this._positions[properties.index] = position 55 | } 56 | } else { 57 | this._isMoving = true 58 | if (!e.target || !e.target.id) { 59 | return false 60 | } 61 | this._pickedAnchor = e.target.id 62 | } 63 | } 64 | 65 | _onMouseMove(e) { 66 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 67 | if (!this._isMoving) { 68 | return 69 | } 70 | if (this._pickedAnchor && this._pickedAnchor.position) { 71 | let properties = this._pickedAnchor.properties.getValue( 72 | Cesium.JulianDate.now() 73 | ) 74 | let position = this._clampToGround ? e.surfacePosition : e.position 75 | this._pickedAnchor.position.setValue(position) 76 | this._positions[properties.index] = position 77 | } 78 | } 79 | 80 | _onRightClick(e) { 81 | this.unbindEvent() 82 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 83 | this._positions 84 | ) 85 | this._overlay.show = true 86 | this._plotEvent.raiseEvent(this._overlay) 87 | } 88 | } 89 | 90 | export default EditAttackArrow 91 | -------------------------------------------------------------------------------- /src/core/edit/EditDoubleArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:46:07 4 | */ 5 | 6 | import Edit from './Edit' 7 | import DoubleArrowGraphics from '../graphics/DoubleArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | class EditDoubleArrow extends Edit { 14 | constructor(overlay) { 15 | super() 16 | this._overlay = overlay 17 | this._positions = [] 18 | this._graphics = new DoubleArrowGraphics() 19 | } 20 | 21 | _mountEntity() { 22 | this._delegate = new Cesium.Entity() 23 | this._delegate.merge(this._overlay.delegate) 24 | this._overlay.show = false 25 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(() => { 26 | if (this._positions.length > 2) { 27 | this._graphics.positions = this._positions 28 | return this._graphics.hierarchy 29 | } else { 30 | return null 31 | } 32 | }, false) 33 | this._layer.add(this._delegate) 34 | } 35 | 36 | _mountAnchor() { 37 | this._positions = [].concat( 38 | Transform.transformWGS84ArrayToCartesianArray(this._overlay.positions) 39 | ) 40 | this._positions.forEach((item, index) => { 41 | this.createAnchor(item, index) 42 | }) 43 | } 44 | 45 | _onClick(e) { 46 | if (this._isMoving) { 47 | this._isMoving = false 48 | if (this._pickedAnchor && this._pickedAnchor.position) { 49 | let position = this._clampToGround ? e.surfacePosition : e.position 50 | this._pickedAnchor.position.setValue(position) 51 | let properties = this._pickedAnchor.properties.getValue( 52 | Cesium.JulianDate.now() 53 | ) 54 | this._positions[properties.index] = position 55 | } 56 | } else { 57 | this._isMoving = true 58 | if (!e.target || !e.target.id) { 59 | return false 60 | } 61 | this._pickedAnchor = e.target.id 62 | } 63 | } 64 | 65 | _onMouseMove(e) { 66 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 67 | if (!this._isMoving) { 68 | return 69 | } 70 | if (this._pickedAnchor && this._pickedAnchor.position) { 71 | let properties = this._pickedAnchor.properties.getValue( 72 | Cesium.JulianDate.now() 73 | ) 74 | let position = this._clampToGround ? e.surfacePosition : e.position 75 | this._pickedAnchor.position.setValue(position) 76 | this._positions[properties.index] = position 77 | } 78 | } 79 | 80 | _onRightClick(e) { 81 | this.unbindEvent() 82 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 83 | this._positions 84 | ) 85 | this._overlay.show = true 86 | this._plotEvent.raiseEvent(this._overlay) 87 | } 88 | } 89 | 90 | export default EditDoubleArrow 91 | -------------------------------------------------------------------------------- /src/core/edit/EditGatheringPlace.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:46:07 4 | */ 5 | 6 | import Edit from './Edit' 7 | import GatheringPlaceGraphics from '../graphics/GatheringPlaceGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | class EditGatheringPlace extends Edit { 14 | constructor(overlay) { 15 | super() 16 | this._overlay = overlay 17 | this._positions = [] 18 | this._graphics = new GatheringPlaceGraphics() 19 | } 20 | 21 | _mountEntity() { 22 | this._delegate = new Cesium.Entity() 23 | this._delegate.merge(this._overlay.delegate) 24 | this._overlay.show = false 25 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(() => { 26 | if (this._positions.length > 1) { 27 | this._graphics.positions = this._positions 28 | return this._graphics.hierarchy 29 | } else { 30 | return null 31 | } 32 | }, false) 33 | this._layer.add(this._delegate) 34 | } 35 | 36 | _mountAnchor() { 37 | this._positions = [].concat( 38 | Transform.transformWGS84ArrayToCartesianArray(this._overlay.positions) 39 | ) 40 | this._positions.forEach((item, index) => { 41 | this.createAnchor(item, index) 42 | }) 43 | } 44 | 45 | _onClick(e) { 46 | if (this._isMoving) { 47 | this._isMoving = false 48 | if (this._pickedAnchor && this._pickedAnchor.position) { 49 | let properties = this._pickedAnchor.properties.getValue( 50 | Cesium.JulianDate.now() 51 | ) 52 | let position = this._clampToGround ? e.surfacePosition : e.position 53 | this._pickedAnchor.position.setValue(position) 54 | this._positions[properties.index] = position 55 | } 56 | } else { 57 | this._isMoving = true 58 | if (!e.target || !e.target.id) { 59 | return false 60 | } 61 | this._pickedAnchor = e.target.id 62 | } 63 | } 64 | 65 | _onMouseMove(e) { 66 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 67 | if (!this._isMoving) { 68 | return 69 | } 70 | if (this._pickedAnchor && this._pickedAnchor.position) { 71 | let properties = this._pickedAnchor.properties.getValue( 72 | Cesium.JulianDate.now() 73 | ) 74 | let position = this._clampToGround ? e.surfacePosition : e.position 75 | this._pickedAnchor.position.setValue(position) 76 | this._positions[properties.index] = position 77 | } 78 | } 79 | 80 | _onRightClick(e) { 81 | this.unbindEvent() 82 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 83 | this._positions 84 | ) 85 | this._overlay.show = true 86 | this._plotEvent.raiseEvent(this._overlay) 87 | } 88 | } 89 | 90 | export default EditGatheringPlace 91 | -------------------------------------------------------------------------------- /src/core/edit/EditTailedAttackArrow.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:46:07 4 | */ 5 | 6 | import Edit from './Edit' 7 | import TailedAttackArrowGraphics from '../graphics/TailedAttackArrowGraphics' 8 | 9 | const { Transform } = DC 10 | 11 | const { Cesium } = DC.Namespace 12 | 13 | class EditTailedAttackArrow extends Edit { 14 | constructor(overlay) { 15 | super() 16 | this._overlay = overlay 17 | this._positions = [] 18 | this._graphics = new TailedAttackArrowGraphics() 19 | } 20 | 21 | _mountEntity() { 22 | this._delegate = new Cesium.Entity() 23 | this._delegate.merge(this._overlay.delegate) 24 | this._overlay.show = false 25 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(() => { 26 | if (this._positions.length > 2) { 27 | this._graphics.positions = this._positions 28 | return this._graphics.hierarchy 29 | } else { 30 | return null 31 | } 32 | }, false) 33 | this._layer.add(this._delegate) 34 | } 35 | 36 | _mountAnchor() { 37 | this._positions = [].concat( 38 | Transform.transformWGS84ArrayToCartesianArray(this._overlay.positions) 39 | ) 40 | this._positions.forEach((item, index) => { 41 | this.createAnchor(item, index) 42 | }) 43 | } 44 | 45 | _onClick(e) { 46 | if (this._isMoving) { 47 | this._isMoving = false 48 | if (this._pickedAnchor && this._pickedAnchor.position) { 49 | let position = this._clampToGround ? e.surfacePosition : e.position 50 | let properties = this._pickedAnchor.properties.getValue( 51 | Cesium.JulianDate.now() 52 | ) 53 | this._pickedAnchor.position.setValue(position) 54 | this._positions[properties.index] = position 55 | } 56 | } else { 57 | this._isMoving = true 58 | if (!e.target || !e.target.id) { 59 | return false 60 | } 61 | this._pickedAnchor = e.target.id 62 | } 63 | } 64 | 65 | _onMouseMove(e) { 66 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 67 | if (!this._isMoving) { 68 | return 69 | } 70 | if (this._pickedAnchor && this._pickedAnchor.position) { 71 | let properties = this._pickedAnchor.properties.getValue( 72 | Cesium.JulianDate.now() 73 | ) 74 | let position = this._clampToGround ? e.surfacePosition : e.position 75 | this._pickedAnchor.position.setValue(position) 76 | this._positions[properties.index] = position 77 | } 78 | } 79 | 80 | _onRightClick(e) { 81 | this.unbindEvent() 82 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 83 | this._positions 84 | ) 85 | this._overlay.show = true 86 | this._plotEvent.raiseEvent(this._overlay) 87 | } 88 | } 89 | 90 | export default EditTailedAttackArrow 91 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # DC-Plot 2 | 3 |

4 | 5 | 6 | 7 |

8 | 9 | [**🇨🇳 中文**](./README_zh.md) | [**🇬🇧English**](./README.md) 10 | 11 | > DC-SDK 标绘工具,如点、线、面绘制和一些军事对象绘制。 12 | 13 | > [主页](http://dc.dvgis.cn) 14 | 15 | ```warning 16 | Tips:本框架是 JS+GIS 的框架包。开发者需要有一定的前端技术和 GIS 相关技术 17 | ``` 18 | 19 | ## 安装 20 | 21 | > CDN 22 | 23 | ```html 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | > NPM / YARN 37 | 38 | ```shell 39 | yarn add @dvgis/dc-sdk @dvgis/dc-overlay @dvgis/dc-plot 40 | npm install @dvgis/dc-sdk @dvgis/dc-overlay @dvgis/dc-plot 41 | ``` 42 | 43 | ```js 44 | import DC from 'dvgis/dc-sdk/dist/dc.base.min' //基础包 45 | import DcCore from 'dvgis/dc-sdk/dist/dc.core.min' //核心包 46 | import DcOverlay from 'dvgis/dc-overlay/dist/dc.overlay.min' //要素包 47 | import DcPlot from 'dvgis/dc-plot/dist/dc.plot.min' //标绘包 48 | import 'dvgis/dc-sdk/dist/dc.core.min.css' // 主要样式 49 | ``` 50 | 51 | ## 配置 52 | 53 | > Vue 54 | 55 | ```js 56 | // vue.config.js vue 文件 57 | 58 | const path = require('path') 59 | const CopywebpackPlugin = require('copy-webpack-plugin') 60 | const dvgisDist = './node_modules/@dvgis' 61 | 62 | module.exports = { 63 | // 其他配置 64 | chainWebpack: config => { 65 | config.resolve.alias.set('dvgis', path.resolve(__dirname, dvgisDist)) 66 | config.plugin('copy').use(CopywebpackPlugin, [ 67 | [ 68 | { 69 | from: path.join(dvgisDist, 'dc-sdk/dist/resources'), 70 | to: 'libs/dc-sdk/resources' 71 | } 72 | ] 73 | ]) 74 | } 75 | } 76 | ``` 77 | 78 | ## 开始 79 | 80 | ```js 81 | DC.use(DcCore) 82 | DC.use(DcOverlay) 83 | DC.use(DcPlot) 84 | DC.ready(() => { 85 | let viewer = new DC.Viewer(divId) // divId 为一个div节点的Id属性值,如果不传入,会无法初始化3D场景 86 | }) 87 | ``` 88 | 89 | ## 文档 90 | 91 | [DC Api](https://resource.dvgis.cn/dc-api) 92 | 93 | [Cesium Api](https://cesium.com/docs/cesiumjs-ref-doc/) 94 | 95 | ## 示例 96 | 97 | ![picture](http://dc.dvgis.cn/examples/images/overlay/plot-overlay.png) 98 | 99 | ## 版权声明 100 | 101 | ```warning 102 | 1.框架是一个基本平台,完全开源,任何个人和机构可以修改、重构,无需经过我方授权。 103 | 2.后期会添加一系列针对性的插件和工具,会适量的开源。 104 | 3.任何个人和机构在遵守下列条件的前提下可以永久免费使用: 105 | 1)程序包完整引用; 106 | 2)保留此版权信息在控制台输出 107 | 我方保留对此版权信息的最终解释权。 108 | ``` 109 | 110 | ## 感谢 111 | -------------------------------------------------------------------------------- /src/core/draw/DrawCircle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-29 21:24:55 4 | */ 5 | 6 | import Draw from './Draw' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | const DEF_STYLE = { 13 | material: Cesium.Color.YELLOW.withAlpha(0.6), 14 | fill: true 15 | } 16 | 17 | class DrawCircle extends Draw { 18 | constructor(style) { 19 | super() 20 | this._positions = [] 21 | this._radius = 0 22 | this._style = { 23 | ...DEF_STYLE, 24 | ...style 25 | } 26 | } 27 | 28 | _mountEntity() { 29 | this._delegate = new Cesium.Entity({ 30 | polygon: { 31 | ...this._style, 32 | hierarchy: new Cesium.CallbackProperty(() => { 33 | if (this._positions.length > 1) { 34 | this._radius = Cesium.Cartesian3.distance( 35 | this._positions[0], 36 | this._positions[1] 37 | ) 38 | if (this._radius <= 0) { 39 | return null 40 | } 41 | let cep = Cesium.EllipseGeometryLibrary.computeEllipsePositions( 42 | { 43 | center: this._positions[0], 44 | semiMajorAxis: this._radius, 45 | semiMinorAxis: this._radius, 46 | rotation: 0, 47 | granularity: 0.005 48 | }, 49 | false, 50 | true 51 | ) 52 | let pnts = Cesium.Cartesian3.unpackArray(cep.outerPositions) 53 | pnts.push(pnts[0]) 54 | return new Cesium.PolygonHierarchy(pnts) 55 | } else { 56 | return null 57 | } 58 | }, false) 59 | } 60 | }) 61 | this._layer.add(this._delegate) 62 | } 63 | 64 | _onClick(e) { 65 | let len = this._positions.length 66 | let position = this._clampToGround ? e.surfacePosition : e.position 67 | if (len === 0) { 68 | this._positions.push(position) 69 | this.createAnchor(position, true) 70 | this._floatingAnchor = this.createAnchor(position) 71 | } 72 | this._positions.push(position) 73 | if (len > 0) { 74 | this.createAnchor(position) 75 | } 76 | if (len > 1) { 77 | this._positions.pop() 78 | this.unbindEvent() 79 | let circle = new DC.Circle( 80 | Transform.transformCartesianToWGS84(this._positions[0]), 81 | this._radius 82 | ) 83 | circle.setStyle(this._style) 84 | this._plotEvent.raiseEvent(circle) 85 | } 86 | } 87 | 88 | _onMouseMove(e) { 89 | this._tooltip.showAt(e.windowPosition, '单击选择点位') 90 | if (this._floatingAnchor) { 91 | let position = this._clampToGround ? e.surfacePosition : e.position 92 | this._floatingAnchor.position.setValue(position) 93 | this._positions.pop() 94 | this._positions.push(position) 95 | } 96 | } 97 | } 98 | 99 | export default DrawCircle 100 | -------------------------------------------------------------------------------- /src/core/edit/Edit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:50:53 4 | */ 5 | 6 | const { MouseEventType } = DC 7 | 8 | const { Cesium } = DC.Namespace 9 | 10 | class Edit { 11 | constructor() { 12 | this._viewer = undefined 13 | this._overlay = undefined 14 | this._anchors = [] 15 | this._delegate = undefined 16 | this._pickedAnchor = undefined 17 | this._isMoving = false 18 | this._clampToGround = true 19 | this._tooltip = undefined 20 | this._layer = undefined 21 | this._anchorLayer = undefined 22 | this._layer = undefined 23 | this._plotEvent = undefined 24 | this._options = {} 25 | } 26 | 27 | _mountEntity() {} 28 | 29 | _mountAnchor() {} 30 | 31 | _onClick(e) {} 32 | 33 | _onMouseMove(e) {} 34 | 35 | _onRightClick(e) {} 36 | 37 | bindEvent() { 38 | this._viewer.on(MouseEventType.CLICK, this._onClick, this) 39 | this._viewer.on(MouseEventType.MOUSE_MOVE, this._onMouseMove, this) 40 | this._viewer.on(MouseEventType.RIGHT_CLICK, this._onRightClick, this) 41 | } 42 | 43 | unbindEvent() { 44 | this._viewer.off(MouseEventType.CLICK, this._onClick, this) 45 | this._viewer.off(MouseEventType.MOUSE_MOVE, this._onMouseMove, this) 46 | this._viewer.off(MouseEventType.RIGHT_CLICK, this._onRightClick, this) 47 | } 48 | 49 | createAnchor(position, index, isMid = false, isCenter = false) { 50 | let image = isMid 51 | ? this._options.icon_midAnchor 52 | : isCenter 53 | ? this._options.icon_center 54 | : this._options.icon_anchor 55 | let anchor = this._anchorLayer.add({ 56 | position: position, 57 | billboard: { 58 | image: image, 59 | width: 12, 60 | height: 12, 61 | eyeOffset: new Cesium.ConstantProperty( 62 | new Cesium.Cartesian3(0, 0, -500) 63 | ), 64 | heightReference: 65 | this._viewer.scene.mode === Cesium.SceneMode.SCENE3D && 66 | this._clampToGround 67 | ? Cesium.HeightReference.CLAMP_TO_GROUND 68 | : Cesium.HeightReference.NONE 69 | }, 70 | properties: { 71 | isMid: isMid, 72 | index: index 73 | } 74 | }) 75 | this._anchors.push(anchor) 76 | } 77 | 78 | computeMidPosition(p1, p2) { 79 | let c1 = Cesium.Ellipsoid.WGS84.cartesianToCartographic(p1) 80 | let c2 = Cesium.Ellipsoid.WGS84.cartesianToCartographic(p2) 81 | let cm = new Cesium.EllipsoidGeodesic(c1, c2).interpolateUsingFraction(0.5) 82 | return Cesium.Ellipsoid.WGS84.cartographicToCartesian(cm) 83 | } 84 | 85 | start(plot) { 86 | this._viewer = plot.viewer 87 | this._tooltip = plot.viewer.tooltip 88 | this._layer = plot.overlayLayer 89 | this._anchorLayer = plot.anchorLayer 90 | this._plotEvent = plot.plotEvent 91 | this._options = plot.options 92 | this._clampToGround = plot.options.clampToGround ?? true 93 | this._mountEntity() 94 | this._mountAnchor() 95 | this.bindEvent() 96 | } 97 | } 98 | 99 | export default Edit 100 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DC-Plot 2 | 3 |

4 | 5 | 6 | 7 |

8 | 9 | [**🇨🇳 中文**](./README_zh.md) | [**🇬🇧English**](./README.md) 10 | 11 | > DC-SDK plotting tools, such as point, line, surface drawing and some military object drawing. 12 | 13 | > [Home Page](http://dc.dvgis.cn) 14 | 15 | ```warning 16 | Tips:This SDK is JS+GIS framework package. Developers need to have some front-end technology and GIS related technology 17 | ``` 18 | 19 | ## Installation 20 | 21 | > CDN 22 | 23 | ```html 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ``` 35 | 36 | > NPM / YARN 37 | 38 | ```shell 39 | yarn add @dvgis/dc-sdk @dvgis/dc-overlay @dvgis/dc-plot 40 | npm install @dvgis/dc-sdk @dvgis/dc-overlay @dvgis/dc-plot 41 | ``` 42 | 43 | ```js 44 | import DC from 'dvgis/dc-sdk/dist/dc.base.min' //Basic Package 45 | import DcCore from 'dvgis/dc-sdk/dist/dc.core.min' //Core Package 46 | import DcOverlay from 'dvgis/dc-overlay/dist/dc.overlay.min' //Overlay Package 47 | import DcPlot from 'dvgis/dc-plot/dist/dc.plot.min' //Plot Package 48 | import 'dvgis/dc-sdk/dist/dc.core.min.css' // Main Style Sheet 49 | ``` 50 | 51 | ## Setting 52 | 53 | > Vue 54 | 55 | ```js 56 | // vue.config.js 57 | 58 | const path = require('path') 59 | const CopywebpackPlugin = require('copy-webpack-plugin') 60 | const dvgisDist = './node_modules/@dvgis' 61 | 62 | module.exports = { 63 | // other settings 64 | chainWebpack: config => { 65 | config.resolve.alias.set('dvgis', path.resolve(__dirname, dvgisDist)) 66 | config.plugin('copy').use(CopywebpackPlugin, [ 67 | [ 68 | { 69 | from: path.join(dvgisDist, 'dc-sdk/dist/resources'), 70 | to: 'libs/dc-sdk/resources' 71 | } 72 | ] 73 | ]) 74 | } 75 | } 76 | ``` 77 | 78 | ## Start 79 | 80 | ```js 81 | DC.use(DcCore) 82 | DC.use(DcOverlay) 83 | DC.use(DcPlot) 84 | DC.ready(() => { 85 | let viewer = new DC.Viewer(divId) // divId is the Id attribute value of a div node. If it is not passed in, the 3D scene cannot be initialized 86 | }) 87 | ``` 88 | 89 | ## Documentation 90 | 91 | [DC Api](https://resource.dvgis.cn/dc-api) 92 | 93 | [Cesium Api](https://cesium.com/docs/cesiumjs-ref-doc/) 94 | 95 | ## Demo 96 | 97 | ![picture](http://dc.dvgis.cn/examples/images/overlay/plot-overlay.png) 98 | 99 | ## Copyright statement 100 | 101 | ```warning 102 | 1. The framework is a basic platform, completely open source, which can be modified and reconstructed by any individual or institution without our authorization. 103 | 2. A series of targeted plug-ins and tools will be added later, and an appropriate amount of open source. 104 | 3. Free and permanent use by any person or institution subject to the following conditions: 105 | 1) complete package reference; 106 | 2) reserve this copyright information in the console output 107 | We reserve the right of final interpretation of this copyright information. 108 | ``` 109 | 110 | ## Thanks 111 | -------------------------------------------------------------------------------- /src/core/edit/EditCircle.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-31 10:54:38 4 | */ 5 | 6 | import Edit from './Edit' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class EditCircle extends Edit { 13 | constructor(overlay) { 14 | super() 15 | this._overlay = overlay 16 | this._center = undefined 17 | this._radius = 0 18 | this._positions = [] 19 | } 20 | 21 | _mountEntity() { 22 | this._radius = this._overlay.radius 23 | this._center = Transform.transformWGS84ToCartesian(this._overlay.center) 24 | this._overlay.show = false 25 | this._delegate = new Cesium.Entity({ 26 | polygon: { 27 | material: this._overlay.delegate?.polygon?.material 28 | } 29 | }) 30 | this._positions = [].concat([ 31 | this._center, 32 | this._computeCirclePoints(this._center, this._radius)[0] 33 | ]) 34 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(time => { 35 | if (this._positions.length > 1) { 36 | this._radius = Cesium.Cartesian3.distance( 37 | this._positions[0], 38 | this._positions[1] 39 | ) 40 | if (this._radius <= 0) { 41 | return null 42 | } 43 | let pnts = this._computeCirclePoints(this._positions[0], this._radius) 44 | pnts.push(pnts[0]) 45 | return new Cesium.PolygonHierarchy(pnts) 46 | } else { 47 | return null 48 | } 49 | }, false) 50 | this._layer.add(this._delegate) 51 | } 52 | 53 | _mountAnchor() { 54 | this._positions.forEach((item, index) => { 55 | this.createAnchor(item, index, false, index % 2 === 0) 56 | }) 57 | } 58 | 59 | _computeCirclePoints(center, radius) { 60 | let pnts = [] 61 | let cep = Cesium.EllipseGeometryLibrary.computeEllipsePositions( 62 | { 63 | center: center, 64 | semiMajorAxis: radius, 65 | semiMinorAxis: radius, 66 | rotation: 0, 67 | granularity: 0.005 68 | }, 69 | false, 70 | true 71 | ) 72 | if (cep && cep.outerPositions) { 73 | pnts = Cesium.Cartesian3.unpackArray(cep.outerPositions) 74 | } 75 | return pnts 76 | } 77 | 78 | _onClick(e) { 79 | let now = Cesium.JulianDate.now() 80 | if (this._isMoving) { 81 | this._isMoving = false 82 | if (this._pickedAnchor && this._pickedAnchor.position) { 83 | let position = this._clampToGround ? e.surfacePosition : e.position 84 | this._pickedAnchor.position.setValue(position) 85 | let properties = this._pickedAnchor.properties.getValue(now) 86 | this._positions[properties.index] = position 87 | } 88 | } else { 89 | this._isMoving = true 90 | if (!e.target || !e.target.id) { 91 | return false 92 | } 93 | this._pickedAnchor = e.target.id 94 | } 95 | } 96 | 97 | _onMouseMove(e) { 98 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 99 | if (!this._isMoving) { 100 | return 101 | } 102 | if (this._pickedAnchor && this._pickedAnchor.position) { 103 | let properties = this._pickedAnchor.properties.getValue( 104 | Cesium.JulianDate.now() 105 | ) 106 | let position = this._clampToGround ? e.surfacePosition : e.position 107 | this._pickedAnchor.position.setValue(position) 108 | this._positions[properties.index] = position 109 | } 110 | } 111 | 112 | _onRightClick(e) { 113 | this.unbindEvent() 114 | this._overlay.center = Transform.transformCartesianToWGS84( 115 | this._positions[0] 116 | ) 117 | this._overlay.radius = this._radius 118 | this._overlay.show = true 119 | this._plotEvent.raiseEvent(this._overlay) 120 | } 121 | } 122 | 123 | export default EditCircle 124 | -------------------------------------------------------------------------------- /src/core/edit/EditPolyline.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 22:39:34 4 | */ 5 | 6 | import Edit from './Edit' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class EditPolyline extends Edit { 13 | constructor(overlay) { 14 | super() 15 | this._overlay = overlay 16 | this._positions = [] 17 | } 18 | 19 | _mountEntity() { 20 | this._delegate = new Cesium.Entity() 21 | this._delegate.merge(this._overlay.delegate) 22 | this._overlay.show = false 23 | this._delegate.polyline.positions = new Cesium.CallbackProperty(() => { 24 | if (this._positions.length > 1) { 25 | return this._positions 26 | } else { 27 | return null 28 | } 29 | }, false) 30 | this._layer.add(this._delegate) 31 | } 32 | 33 | _mountAnchor() { 34 | let positions = [].concat( 35 | this._overlay.delegate.polyline.positions.getValue( 36 | Cesium.JulianDate.now() 37 | ) 38 | ) 39 | for (let i = 0; i < positions.length - 1; i++) { 40 | let mid = this.computeMidPosition(positions[i], positions[i + 1]) 41 | this._positions.push(positions[i]) 42 | this._positions.push(mid) 43 | } 44 | this._positions.push(positions[positions.length - 1]) 45 | this._positions.forEach((item, index) => { 46 | this.createAnchor(item, index, index % 2 !== 0) 47 | }) 48 | } 49 | 50 | _onClick(e) { 51 | if (this._isMoving) { 52 | this._isMoving = false 53 | if (this._pickedAnchor && this._pickedAnchor.position) { 54 | let position = this._clampToGround ? e.surfacePosition : e.position 55 | this._pickedAnchor.position.setValue(position) 56 | let properties = this._pickedAnchor.properties.getValue( 57 | Cesium.JulianDate.now() 58 | ) 59 | if (properties.isMid) { 60 | let preMidPosition = this.computeMidPosition( 61 | this._positions[properties.index], 62 | this._positions[properties.index - 1] 63 | ) 64 | let nextMidPosition = this.computeMidPosition( 65 | this._positions[properties.index], 66 | this._positions[properties.index + 1] 67 | ) 68 | this._anchorLayer.removeAll() 69 | this._anchors = [] 70 | this._positions.splice( 71 | properties.index, 72 | 1, 73 | preMidPosition, 74 | position, 75 | nextMidPosition 76 | ) 77 | this._positions.forEach((item, index) => { 78 | this.createAnchor(item, index, index % 2 !== 0) 79 | }) 80 | } 81 | } 82 | } else { 83 | this._isMoving = true 84 | if (!e.target.id) { 85 | return false 86 | } 87 | this._pickedAnchor = e.target.id 88 | } 89 | } 90 | 91 | _onMouseMove(e) { 92 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 93 | if (!this._isMoving) { 94 | return 95 | } 96 | if (this._pickedAnchor && this._pickedAnchor.position) { 97 | let properties = this._pickedAnchor.properties.getValue( 98 | Cesium.JulianDate.now() 99 | ) 100 | let position = this._clampToGround ? e.surfacePosition : e.position 101 | 102 | this._pickedAnchor.position.setValue(position) 103 | this._positions[properties.index] = position 104 | if (!properties.isMid) { 105 | let currentIndex = properties.index 106 | let preAnchorIndex = -1 107 | let preMidAnchorIndex = -1 108 | let nextAnchorIndex = -1 109 | let nextMidAnchorIndex = -1 110 | let len = this._positions.length 111 | if (currentIndex === 0) { 112 | nextAnchorIndex = currentIndex + 2 113 | nextMidAnchorIndex = currentIndex + 1 114 | } else if (properties.index === len - 1) { 115 | preAnchorIndex = currentIndex - 2 116 | preMidAnchorIndex = currentIndex - 1 117 | } else { 118 | preAnchorIndex = currentIndex - 2 119 | preMidAnchorIndex = currentIndex - 1 120 | nextAnchorIndex = currentIndex + 2 121 | nextMidAnchorIndex = currentIndex + 1 122 | } 123 | 124 | if (preAnchorIndex > 0) { 125 | let preMidPosition = this.computeMidPosition( 126 | this._positions[preAnchorIndex], 127 | this._positions[currentIndex] 128 | ) 129 | this._positions[preMidAnchorIndex] = preMidPosition 130 | this._anchors[preMidAnchorIndex].position.setValue(preMidPosition) 131 | } 132 | 133 | if (nextAnchorIndex > 0) { 134 | let nextMidPosition = this.computeMidPosition( 135 | this._positions[nextAnchorIndex], 136 | this._positions[currentIndex] 137 | ) 138 | this._positions[nextMidAnchorIndex] = nextMidPosition 139 | this._anchors[nextMidAnchorIndex].position.setValue(nextMidPosition) 140 | } 141 | } 142 | } 143 | } 144 | 145 | _onRightClick(e) { 146 | this.unbindEvent() 147 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 148 | this._positions 149 | ) 150 | this._overlay.show = true 151 | this._plotEvent.raiseEvent(this._overlay) 152 | } 153 | } 154 | 155 | export default EditPolyline 156 | -------------------------------------------------------------------------------- /src/core/graphics/AttackArrowGraphics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 16:22:50 4 | */ 5 | 6 | const { Transform, Parse, PlotUtil } = DC 7 | 8 | const { Cesium } = DC.Namespace 9 | 10 | const HALF_PI = Math.PI / 2 11 | 12 | class AttackArrowGraphics { 13 | constructor(options) { 14 | this._positions = options?.positions || [] 15 | this.headHeightFactor = 0.18 16 | this.headWidthFactor = 0.3 17 | this.neckHeightFactor = 0.85 18 | this.neckWidthFactor = 0.15 19 | this.headTailFactor = 0.8 20 | } 21 | 22 | set positions(positions) { 23 | this._positions = positions 24 | } 25 | 26 | get positions() { 27 | return this._positions 28 | } 29 | 30 | get hierarchy() { 31 | return this._createHierarchy() 32 | } 33 | 34 | _getArrowHeadPoints(points, tailLeft, tailRight) { 35 | let len = PlotUtil.getBaseLength(points) 36 | let headHeight = len * this.headHeightFactor 37 | let headPnt = points[points.length - 1] 38 | len = PlotUtil.distance(headPnt, points[points.length - 2]) 39 | let tailWidth = PlotUtil.distance(tailLeft, tailRight) 40 | if (headHeight > tailWidth * this.headTailFactor) { 41 | headHeight = tailWidth * this.headTailFactor 42 | } 43 | let headWidth = headHeight * this.headWidthFactor 44 | let neckWidth = headHeight * this.neckWidthFactor 45 | headHeight = headHeight > len ? len : headHeight 46 | let neckHeight = headHeight * this.neckHeightFactor 47 | let headEndPnt = PlotUtil.getThirdPoint( 48 | points[points.length - 2], 49 | headPnt, 50 | 0, 51 | headHeight, 52 | true 53 | ) 54 | let neckEndPnt = PlotUtil.getThirdPoint( 55 | points[points.length - 2], 56 | headPnt, 57 | 0, 58 | neckHeight, 59 | true 60 | ) 61 | let headLeft = PlotUtil.getThirdPoint( 62 | headPnt, 63 | headEndPnt, 64 | HALF_PI, 65 | headWidth, 66 | false 67 | ) 68 | let headRight = PlotUtil.getThirdPoint( 69 | headPnt, 70 | headEndPnt, 71 | HALF_PI, 72 | headWidth, 73 | true 74 | ) 75 | let neckLeft = PlotUtil.getThirdPoint( 76 | headPnt, 77 | neckEndPnt, 78 | HALF_PI, 79 | neckWidth, 80 | false 81 | ) 82 | let neckRight = PlotUtil.getThirdPoint( 83 | headPnt, 84 | neckEndPnt, 85 | HALF_PI, 86 | neckWidth, 87 | true 88 | ) 89 | return [neckLeft, headLeft, headPnt, headRight, neckRight] 90 | } 91 | 92 | _getArrowBodyPoints(points, neckLeft, neckRight, tailWidthFactor) { 93 | let allLen = PlotUtil.wholeDistance(points) 94 | let len = PlotUtil.getBaseLength(points) 95 | let tailWidth = len * tailWidthFactor 96 | let neckWidth = PlotUtil.distance(neckLeft, neckRight) 97 | let widthDif = (tailWidth - neckWidth) / 2 98 | let tempLen = 0 99 | let leftBodyPnts = [] 100 | let rightBodyPnts = [] 101 | for (let i = 1; i < points.length - 1; i++) { 102 | let angle = 103 | PlotUtil.getAngleOfThreePoints( 104 | points[i - 1], 105 | points[i], 106 | points[i + 1] 107 | ) / 2 108 | tempLen += PlotUtil.distance(points[i - 1], points[i]) 109 | let w = (tailWidth / 2 - (tempLen / allLen) * widthDif) / Math.sin(angle) 110 | let left = PlotUtil.getThirdPoint( 111 | points[i - 1], 112 | points[i], 113 | Math.PI - angle, 114 | w, 115 | true 116 | ) 117 | let right = PlotUtil.getThirdPoint( 118 | points[i - 1], 119 | points[i], 120 | angle, 121 | w, 122 | false 123 | ) 124 | leftBodyPnts.push(left) 125 | rightBodyPnts.push(right) 126 | } 127 | return leftBodyPnts.concat(rightBodyPnts) 128 | } 129 | 130 | _createHierarchy() { 131 | let pnts = Parse.parsePolygonCoordToArray( 132 | Transform.transformCartesianArrayToWGS84Array(this._positions) 133 | )[0] 134 | let tailLeft = pnts[0] 135 | let tailRight = pnts[1] 136 | if (PlotUtil.isClockWise(pnts[0], pnts[1], pnts[2])) { 137 | tailLeft = pnts[1] 138 | tailRight = pnts[0] 139 | } 140 | let midTail = PlotUtil.mid(tailLeft, tailRight) 141 | let bonePnts = [midTail].concat(pnts.slice(2)) 142 | // 计算箭头 143 | let headPnts = this._getArrowHeadPoints(bonePnts, tailLeft, tailRight) 144 | let neckLeft = headPnts[0] 145 | let neckRight = headPnts[4] 146 | let tailWidthFactor = 147 | PlotUtil.distance(tailLeft, tailRight) / PlotUtil.getBaseLength(bonePnts) 148 | // 计算箭身 149 | let bodyPnts = this._getArrowBodyPoints( 150 | bonePnts, 151 | neckLeft, 152 | neckRight, 153 | tailWidthFactor 154 | ) 155 | // 整合 156 | let count = bodyPnts.length 157 | let leftPnts = [tailLeft].concat(bodyPnts.slice(0, count / 2)) 158 | leftPnts.push(neckLeft) 159 | let rightPnts = [tailRight].concat(bodyPnts.slice(count / 2, count)) 160 | rightPnts.push(neckRight) 161 | leftPnts = PlotUtil.getQBSplinePoints(leftPnts) 162 | rightPnts = PlotUtil.getQBSplinePoints(rightPnts) 163 | return new Cesium.PolygonHierarchy( 164 | Transform.transformWGS84ArrayToCartesianArray( 165 | Parse.parsePositions(leftPnts.concat(headPnts, rightPnts.reverse())) 166 | ) 167 | ) 168 | } 169 | } 170 | 171 | export default AttackArrowGraphics 172 | -------------------------------------------------------------------------------- /src/core/edit/EditPolygon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 23:12:09 4 | */ 5 | 6 | import Edit from './Edit' 7 | 8 | const { Transform } = DC 9 | 10 | const { Cesium } = DC.Namespace 11 | 12 | class EditPolygon extends Edit { 13 | constructor(overlay) { 14 | super() 15 | this._overlay = overlay 16 | this._positions = [] 17 | } 18 | 19 | _mountEntity() { 20 | this._delegate = new Cesium.Entity() 21 | this._delegate.merge(this._overlay.delegate) 22 | this._overlay.show = false 23 | this._delegate.polygon.hierarchy = new Cesium.CallbackProperty(time => { 24 | if (this._positions.length > 2) { 25 | return new Cesium.PolygonHierarchy(this._positions) 26 | } else { 27 | return null 28 | } 29 | }, false) 30 | this._layer.add(this._delegate) 31 | } 32 | 33 | _mountAnchor() { 34 | let positions = [].concat( 35 | this._overlay.delegate.polygon.hierarchy.getValue(Cesium.JulianDate.now()) 36 | .positions 37 | ) 38 | positions.push(positions[0]) 39 | for (let i = 0; i < positions.length - 1; i++) { 40 | let mid = this.computeMidPosition(positions[i], positions[i + 1]) 41 | this._positions.push(positions[i]) 42 | this._positions.push(mid) 43 | } 44 | this._positions.forEach((item, index) => { 45 | this.createAnchor(item, index, index % 2 !== 0) 46 | }) 47 | } 48 | 49 | _onClick(e) { 50 | if (this._isMoving) { 51 | this._isMoving = false 52 | if (this._pickedAnchor && this._pickedAnchor.position) { 53 | let position = this._clampToGround ? e.surfacePosition : e.position 54 | this._pickedAnchor.position.setValue(position) 55 | let properties = this._pickedAnchor.properties.getValue( 56 | Cesium.JulianDate.now() 57 | ) 58 | let currentIndex = properties.index 59 | if (properties.isMid) { 60 | let preMidPosition 61 | let nextMidPosition 62 | let len = this._positions.length 63 | if (currentIndex === len - 1) { 64 | preMidPosition = this.computeMidPosition( 65 | this._positions[currentIndex], 66 | this._positions[currentIndex - 1] 67 | ) 68 | nextMidPosition = this.computeMidPosition( 69 | this._positions[currentIndex], 70 | this._positions[0] 71 | ) 72 | } else { 73 | preMidPosition = this.computeMidPosition( 74 | this._positions[currentIndex], 75 | this._positions[currentIndex - 1] 76 | ) 77 | nextMidPosition = this.computeMidPosition( 78 | this._positions[currentIndex], 79 | this._positions[currentIndex + 1] 80 | ) 81 | } 82 | this._positions.splice( 83 | properties.index, 84 | 1, 85 | preMidPosition, 86 | position, 87 | nextMidPosition 88 | ) 89 | this._anchorLayer.removeAll() 90 | this._anchors = [] 91 | this._positions.forEach((item, index) => { 92 | this.createAnchor(item, index, index % 2 !== 0) 93 | }) 94 | } 95 | } 96 | } else { 97 | this._isMoving = true 98 | if (!e.target.id) { 99 | return false 100 | } 101 | this._pickedAnchor = e.target.id 102 | } 103 | } 104 | 105 | _onMouseMove(e) { 106 | this._tooltip.showAt(e.windowPosition, '点击锚点移动,右击结束编辑') 107 | if (!this._isMoving) { 108 | return 109 | } 110 | if (this._pickedAnchor && this._pickedAnchor.position) { 111 | let properties = this._pickedAnchor.properties.getValue( 112 | Cesium.JulianDate.now() 113 | ) 114 | let position = this._clampToGround ? e.surfacePosition : e.position 115 | let currentIndex = properties.index 116 | this._pickedAnchor.position.setValue(position) 117 | this._positions[currentIndex] = position 118 | let len = this._positions.length 119 | if (!properties.isMid) { 120 | let preAnchorIndex = -1 121 | let preMidAnchorIndex = -1 122 | let nextAnchorIndex = -1 123 | let nextMidAnchorIndex = -1 124 | if (currentIndex === 0) { 125 | preAnchorIndex = len - 2 126 | preMidAnchorIndex = len - 1 127 | nextAnchorIndex = currentIndex + 2 128 | nextMidAnchorIndex = currentIndex + 1 129 | } else if (currentIndex === len - 2) { 130 | preAnchorIndex = currentIndex - 2 131 | preMidAnchorIndex = currentIndex - 1 132 | nextAnchorIndex = 0 133 | nextMidAnchorIndex = len - 1 134 | } else { 135 | preAnchorIndex = currentIndex - 2 136 | preMidAnchorIndex = currentIndex - 1 137 | nextAnchorIndex = currentIndex + 2 138 | nextMidAnchorIndex = currentIndex + 1 139 | } 140 | let preMidPosition = this.computeMidPosition( 141 | this._positions[preAnchorIndex], 142 | this._positions[currentIndex] 143 | ) 144 | let nextMidPosition = this.computeMidPosition( 145 | this._positions[nextAnchorIndex], 146 | this._positions[currentIndex] 147 | ) 148 | this._positions[preMidAnchorIndex] = preMidPosition 149 | this._positions[nextMidAnchorIndex] = nextMidPosition 150 | this._anchors[preMidAnchorIndex].position.setValue(preMidPosition) 151 | this._anchors[nextMidAnchorIndex].position.setValue(nextMidPosition) 152 | } 153 | } 154 | } 155 | 156 | _onRightClick(e) { 157 | this.unbindEvent() 158 | this._overlay.positions = Transform.transformCartesianArrayToWGS84Array( 159 | this._positions 160 | ) 161 | this._overlay.show = true 162 | this._plotEvent.raiseEvent(this._overlay) 163 | } 164 | } 165 | 166 | export default EditPolygon 167 | -------------------------------------------------------------------------------- /src/core/Plot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-29 19:26:06 4 | */ 5 | 6 | import DrawPoint from './draw/DrawPoint' 7 | import DrawPolyline from './draw/DrawPolyline' 8 | import DrawPolygon from './draw/DrawPolygon' 9 | import DrawCircle from './draw/DrawCircle' 10 | import DrawRectangle from './draw/DrawRectangle' 11 | import DrawBillboard from './draw/DrawBillboard' 12 | import DrawAttackArrow from './draw/DrawAttackArrow' 13 | import DrawDoubleArrow from './draw/DrawDoubleArrow' 14 | import DrawFineArrow from './draw/DrawFineArrow' 15 | import DrawGatheringPlace from './draw/DrawGatheringPlace' 16 | import DrawTailedAttackArrow from './draw/DrawTailedAttackArrow' 17 | import EditPoint from './edit/EditPoint' 18 | import EditPolyline from './edit/EditPolyline' 19 | import EditPolygon from './edit/EditPolygon' 20 | import EditCircle from './edit/EditCircle' 21 | import EditRectangle from './edit/EditRectangle' 22 | import EditBillboard from './edit/EditBillboard' 23 | import EditAttackArrow from './edit/EditAttackArrow' 24 | import EditDoubleArrow from './edit/EditDoubleArrow' 25 | import EditFineArrow from './edit/EditFineArrow' 26 | import EditGatheringPlace from './edit/EditGatheringPlace' 27 | import EditTailedAttackArrow from './edit/EditTailedAttackArrow' 28 | 29 | const IMG_CIRCLE_RED = require('./images/circle_red.png') 30 | 31 | const IMG_CIRCLE_BLUE = require('./images/circle_blue.png') 32 | 33 | const IMG_CIRCLE_YELLOW = require('./images/circle_yellow.png') 34 | 35 | const { OverlayType } = DC 36 | 37 | const { Cesium } = DC.Namespace 38 | 39 | const DEF_OPTS = { 40 | icon_center: IMG_CIRCLE_YELLOW, 41 | icon_anchor: IMG_CIRCLE_RED, 42 | icon_midAnchor: IMG_CIRCLE_BLUE, 43 | icon_size: [12, 12], 44 | clampToGround: true 45 | } 46 | 47 | class Plot { 48 | constructor(viewer, options = {}) { 49 | this._viewer = viewer 50 | this._options = { 51 | ...DEF_OPTS, 52 | ...options 53 | } 54 | this._plotEvent = new Cesium.Event() 55 | this._callback = undefined 56 | this._drawWorker = undefined 57 | this._editWorker = undefined 58 | this._overlayLayer = new Cesium.CustomDataSource('plot-overlay-layer') 59 | this._viewer.dataSources.add(this._overlayLayer) 60 | this._anchorLayer = new Cesium.CustomDataSource('plot-overlay-layer') 61 | this._viewer.dataSources.add(this._anchorLayer) 62 | this._state = undefined 63 | } 64 | 65 | get viewer() { 66 | return this._viewer 67 | } 68 | 69 | get options() { 70 | return this._options 71 | } 72 | 73 | get plotEvent() { 74 | return this._plotEvent 75 | } 76 | 77 | get overlayLayer() { 78 | return this._overlayLayer.entities 79 | } 80 | 81 | get anchorLayer() { 82 | return this._anchorLayer.entities 83 | } 84 | 85 | get state() { 86 | return this._state 87 | } 88 | 89 | _completeCallback(overlay) { 90 | this._drawWorker = undefined 91 | this._editWorker = undefined 92 | this._viewer.tooltip.enable = false 93 | this._overlayLayer.entities.removeAll() 94 | this._anchorLayer.entities.removeAll() 95 | this._callback && this._callback.call(this, overlay) 96 | } 97 | 98 | _bindEvent(callback) { 99 | this._plotEvent.removeEventListener(this._completeCallback, this) 100 | this._callback = callback 101 | this._plotEvent.addEventListener(this._completeCallback, this) 102 | } 103 | 104 | _createDrawWorker(type, style) { 105 | switch (type) { 106 | case OverlayType.POINT: 107 | this._drawWorker = new DrawPoint(style) 108 | break 109 | case OverlayType.POLYLINE: 110 | this._drawWorker = new DrawPolyline(style) 111 | break 112 | case OverlayType.POLYGON: 113 | this._drawWorker = new DrawPolygon(style) 114 | break 115 | case OverlayType.CIRCLE: 116 | this._drawWorker = new DrawCircle(style) 117 | break 118 | case OverlayType.RECTANGLE: 119 | this._drawWorker = new DrawRectangle(style) 120 | break 121 | case OverlayType.BILLBOARD: 122 | this._drawWorker = new DrawBillboard(style) 123 | break 124 | case OverlayType.ATTACK_ARROW: 125 | this._drawWorker = new DrawAttackArrow(style) 126 | break 127 | case OverlayType.DOUBLE_ARROW: 128 | this._drawWorker = new DrawDoubleArrow(style) 129 | break 130 | case OverlayType.FINE_ARROW: 131 | this._drawWorker = new DrawFineArrow(style) 132 | break 133 | case OverlayType.TAILED_ATTACK_ARROW: 134 | this._drawWorker = new DrawTailedAttackArrow(style) 135 | break 136 | case OverlayType.GATHERING_PLACE: 137 | this._drawWorker = new DrawGatheringPlace(style) 138 | break 139 | default: 140 | break 141 | } 142 | } 143 | 144 | _createEditWorker(overlay) { 145 | switch (overlay.type) { 146 | case OverlayType.POINT: 147 | this._editWorker = new EditPoint(overlay) 148 | break 149 | case OverlayType.POLYLINE: 150 | this._editWorker = new EditPolyline(overlay) 151 | break 152 | case OverlayType.POLYGON: 153 | this._editWorker = new EditPolygon(overlay) 154 | break 155 | case OverlayType.CIRCLE: 156 | this._editWorker = new EditCircle(overlay) 157 | break 158 | case OverlayType.RECTANGLE: 159 | this._editWorker = new EditRectangle(overlay) 160 | break 161 | case OverlayType.BILLBOARD: 162 | this._editWorker = new EditBillboard(overlay) 163 | break 164 | case OverlayType.ATTACK_ARROW: 165 | this._editWorker = new EditAttackArrow(overlay) 166 | break 167 | case OverlayType.DOUBLE_ARROW: 168 | this._editWorker = new EditDoubleArrow(overlay) 169 | break 170 | case OverlayType.FINE_ARROW: 171 | this._editWorker = new EditFineArrow(overlay) 172 | break 173 | case OverlayType.TAILED_ATTACK_ARROW: 174 | this._editWorker = new EditTailedAttackArrow(overlay) 175 | break 176 | case OverlayType.GATHERING_PLACE: 177 | this._editWorker = new EditGatheringPlace(overlay) 178 | break 179 | default: 180 | break 181 | } 182 | } 183 | 184 | draw(type, callback, style) { 185 | this._state = 'draw' 186 | if (this._drawWorker) { 187 | this._drawWorker.unbindEvent() 188 | this._drawWorker = undefined 189 | } 190 | this._viewer.tooltip.enable = true 191 | this._bindEvent(callback) 192 | this._createDrawWorker(type, style) 193 | this._drawWorker && this._drawWorker.start(this) 194 | } 195 | 196 | edit(overlay, callback) { 197 | this._state = 'edit' 198 | if (this._editWorker) { 199 | this._editWorker.unbindEvent() 200 | this._editWorker = undefined 201 | } 202 | this._viewer.tooltip.enable = true 203 | this._bindEvent(callback) 204 | this._createEditWorker(overlay) 205 | this._editWorker && this._editWorker.start(this) 206 | } 207 | 208 | destroy() { 209 | this._plotEvent.removeEventListener(this._completeCallback, this) 210 | this._viewer.dataSources.remove(this._overlayLayer) 211 | this._viewer.dataSources.remove(this._anchorLayer) 212 | this._viewer = undefined 213 | this._plotEvent = undefined 214 | } 215 | } 216 | 217 | export default Plot 218 | -------------------------------------------------------------------------------- /src/core/graphics/DoubleArrowGraphics.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @Author: Caven 3 | * @Date: 2020-08-30 16:27:29 4 | */ 5 | const { Transform, Parse, PlotUtil } = DC 6 | 7 | const { Cesium } = DC.Namespace 8 | 9 | const HALF_PI = Math.PI / 2 10 | 11 | class DoubleArrowGraphics { 12 | constructor(options) { 13 | this._positions = options?.positions || [] 14 | this.headHeightFactor = 0.25 15 | this.headWidthFactor = 0.3 16 | this.neckHeightFactor = 0.85 17 | this.neckWidthFactor = 0.15 18 | } 19 | 20 | set positions(positions) { 21 | this._positions = positions 22 | } 23 | 24 | get positions() { 25 | return this._positions 26 | } 27 | 28 | get hierarchy() { 29 | return this._createHierarchy() 30 | } 31 | 32 | _getArrowPoints(pnt1, pnt2, pnt3, clockWise) { 33 | let midPnt = PlotUtil.mid(pnt1, pnt2) 34 | let len = PlotUtil.distance(midPnt, pnt3) 35 | let midPnt1 = PlotUtil.getThirdPoint(pnt3, midPnt, 0, len * 0.3, true) 36 | let midPnt2 = PlotUtil.getThirdPoint(pnt3, midPnt, 0, len * 0.5, true) 37 | midPnt1 = PlotUtil.getThirdPoint( 38 | midPnt, 39 | midPnt1, 40 | HALF_PI, 41 | len / 5, 42 | clockWise 43 | ) 44 | midPnt2 = PlotUtil.getThirdPoint( 45 | midPnt, 46 | midPnt2, 47 | HALF_PI, 48 | len / 4, 49 | clockWise 50 | ) 51 | let points = [midPnt, midPnt1, midPnt2, pnt3] 52 | // 计算箭头部分 53 | let arrowPnts = this._getArrowHeadPoints(points) 54 | let neckLeftPoint = arrowPnts[0] 55 | let neckRightPoint = arrowPnts[4] 56 | // 计算箭身部分 57 | let tailWidthFactor = 58 | PlotUtil.distance(pnt1, pnt2) / PlotUtil.getBaseLength(points) / 2 59 | let bodyPnts = this._getArrowBodyPoints( 60 | points, 61 | neckLeftPoint, 62 | neckRightPoint, 63 | tailWidthFactor 64 | ) 65 | let n = bodyPnts.length 66 | let lPoints = bodyPnts.slice(0, n / 2) 67 | let rPoints = bodyPnts.slice(n / 2, n) 68 | lPoints.push(neckLeftPoint) 69 | rPoints.push(neckRightPoint) 70 | lPoints = lPoints.reverse() 71 | lPoints.push(pnt2) 72 | rPoints = rPoints.reverse() 73 | rPoints.push(pnt1) 74 | return lPoints.reverse().concat(arrowPnts, rPoints) 75 | } 76 | 77 | _getArrowHeadPoints(points) { 78 | let len = PlotUtil.getBaseLength(points) 79 | let headHeight = len * this.headHeightFactor 80 | let headPnt = points[points.length - 1] 81 | let headWidth = headHeight * this.headWidthFactor 82 | let neckWidth = headHeight * this.neckWidthFactor 83 | let neckHeight = headHeight * this.neckHeightFactor 84 | let headEndPnt = PlotUtil.getThirdPoint( 85 | points[points.length - 2], 86 | headPnt, 87 | 0, 88 | headHeight, 89 | true 90 | ) 91 | let neckEndPnt = PlotUtil.getThirdPoint( 92 | points[points.length - 2], 93 | headPnt, 94 | 0, 95 | neckHeight, 96 | true 97 | ) 98 | let headLeft = PlotUtil.getThirdPoint( 99 | headPnt, 100 | headEndPnt, 101 | HALF_PI, 102 | headWidth, 103 | false 104 | ) 105 | let headRight = PlotUtil.getThirdPoint( 106 | headPnt, 107 | headEndPnt, 108 | HALF_PI, 109 | headWidth, 110 | true 111 | ) 112 | let neckLeft = PlotUtil.getThirdPoint( 113 | headPnt, 114 | neckEndPnt, 115 | HALF_PI, 116 | neckWidth, 117 | false 118 | ) 119 | let neckRight = PlotUtil.getThirdPoint( 120 | headPnt, 121 | neckEndPnt, 122 | HALF_PI, 123 | neckWidth, 124 | true 125 | ) 126 | return [neckLeft, headLeft, headPnt, headRight, neckRight] 127 | } 128 | 129 | _getArrowBodyPoints(points, neckLeft, neckRight, tailWidthFactor) { 130 | let allLen = PlotUtil.wholeDistance(points) 131 | let len = PlotUtil.getBaseLength(points) 132 | let tailWidth = len * tailWidthFactor 133 | let neckWidth = PlotUtil.distance(neckLeft, neckRight) 134 | let widthDif = (tailWidth - neckWidth) / 2 135 | let tempLen = 0 136 | let leftBodyPnts = [] 137 | let rightBodyPnts = [] 138 | for (let i = 1; i < points.length - 1; i++) { 139 | let angle = 140 | PlotUtil.getAngleOfThreePoints( 141 | points[i - 1], 142 | points[i], 143 | points[i + 1] 144 | ) / 2 145 | tempLen += PlotUtil.distance(points[i - 1], points[i]) 146 | let w = (tailWidth / 2 - (tempLen / allLen) * widthDif) / Math.sin(angle) 147 | let left = PlotUtil.getThirdPoint( 148 | points[i - 1], 149 | points[i], 150 | Math.PI - angle, 151 | w, 152 | true 153 | ) 154 | let right = PlotUtil.getThirdPoint( 155 | points[i - 1], 156 | points[i], 157 | angle, 158 | w, 159 | false 160 | ) 161 | leftBodyPnts.push(left) 162 | rightBodyPnts.push(right) 163 | } 164 | return leftBodyPnts.concat(rightBodyPnts) 165 | } 166 | 167 | _getTempPoint4(linePnt1, linePnt2, point) { 168 | let midPnt = PlotUtil.mid(linePnt1, linePnt2) 169 | let len = PlotUtil.distance(midPnt, point) 170 | let angle = PlotUtil.getAngleOfThreePoints(linePnt1, midPnt, point) 171 | let symPnt, distance1, distance2, mid 172 | if (angle < HALF_PI) { 173 | distance1 = len * Math.sin(angle) 174 | distance2 = len * Math.cos(angle) 175 | mid = PlotUtil.getThirdPoint(linePnt1, midPnt, HALF_PI, distance1, false) 176 | symPnt = PlotUtil.getThirdPoint(midPnt, mid, HALF_PI, distance2, true) 177 | } else if (angle >= HALF_PI && angle < Math.PI) { 178 | distance1 = len * Math.sin(Math.PI - angle) 179 | distance2 = len * Math.cos(Math.PI - angle) 180 | mid = PlotUtil.getThirdPoint(linePnt1, midPnt, HALF_PI, distance1, false) 181 | symPnt = PlotUtil.getThirdPoint(midPnt, mid, HALF_PI, distance2, false) 182 | } else if (angle >= Math.PI && angle < Math.PI * 1.5) { 183 | distance1 = len * Math.sin(angle - Math.PI) 184 | distance2 = len * Math.cos(angle - Math.PI) 185 | mid = PlotUtil.getThirdPoint(linePnt1, midPnt, HALF_PI, distance1, true) 186 | symPnt = PlotUtil.getThirdPoint(midPnt, mid, HALF_PI, distance2, true) 187 | } else { 188 | distance1 = len * Math.sin(Math.PI * 2 - angle) 189 | distance2 = len * Math.cos(Math.PI * 2 - angle) 190 | mid = PlotUtil.getThirdPoint(linePnt1, midPnt, HALF_PI, distance1, true) 191 | symPnt = PlotUtil.getThirdPoint(midPnt, mid, HALF_PI, distance2, false) 192 | } 193 | return symPnt 194 | } 195 | 196 | _createHierarchy() { 197 | let count = this._positions.length 198 | let tempPoint4 = undefined 199 | let connPoint = undefined 200 | let pnts = Parse.parsePolygonCoordToArray( 201 | Transform.transformCartesianArrayToWGS84Array(this._positions) 202 | )[0] 203 | let pnt1 = pnts[0] 204 | let pnt2 = pnts[1] 205 | let pnt3 = pnts[2] 206 | if (count === 3) tempPoint4 = this._getTempPoint4(pnt1, pnt2, pnt3) 207 | else tempPoint4 = pnts[3] 208 | if (count === 3 || count === 4) connPoint = PlotUtil.mid(pnt1, pnt2) 209 | else connPoint = pnts[4] 210 | let leftArrowPnts, rightArrowPnts 211 | if (PlotUtil.isClockWise(pnt1, pnt2, pnt3)) { 212 | leftArrowPnts = this._getArrowPoints(pnt1, connPoint, tempPoint4, false) 213 | rightArrowPnts = this._getArrowPoints(connPoint, pnt2, pnt3, true) 214 | } else { 215 | leftArrowPnts = this._getArrowPoints(pnt2, connPoint, pnt3, false) 216 | rightArrowPnts = this._getArrowPoints(connPoint, pnt1, tempPoint4, true) 217 | } 218 | let m = leftArrowPnts.length 219 | let t = (m - 5) / 2 220 | let llBodyPnts = leftArrowPnts.slice(0, t) 221 | let lArrowPnts = leftArrowPnts.slice(t, t + 5) 222 | let lrBodyPnts = leftArrowPnts.slice(t + 5, m) 223 | let rlBodyPnts = rightArrowPnts.slice(0, t) 224 | let rArrowPnts = rightArrowPnts.slice(t, t + 5) 225 | let rrBodyPnts = rightArrowPnts.slice(t + 5, m) 226 | rlBodyPnts = PlotUtil.getBezierPoints(rlBodyPnts) 227 | let bodyPnts = PlotUtil.getBezierPoints( 228 | rrBodyPnts.concat(llBodyPnts.slice(1)) 229 | ) 230 | lrBodyPnts = PlotUtil.getBezierPoints(lrBodyPnts) 231 | return new Cesium.PolygonHierarchy( 232 | Transform.transformWGS84ArrayToCartesianArray( 233 | Parse.parsePositions( 234 | rlBodyPnts.concat(rArrowPnts, bodyPnts, lArrowPnts, lrBodyPnts) 235 | ) 236 | ) 237 | ) 238 | } 239 | } 240 | 241 | export default DoubleArrowGraphics 242 | -------------------------------------------------------------------------------- /LICENSE.MD: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019-present Caven Chen 2 | 3 | Apache License 4 | Version 2.0, January 2004 5 | http://www.apache.org/licenses/ 6 | 7 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 8 | 9 | 1. Definitions. 10 | 11 | "License" shall mean the terms and conditions for use, reproduction, 12 | and distribution as defined by Sections 1 through 9 of this document. 13 | 14 | "Licensor" shall mean the copyright owner or entity authorized by 15 | the copyright owner that is granting the License. 16 | 17 | "Legal Entity" shall mean the union of the acting entity and all 18 | other entities that control, are controlled by, or are under common 19 | control with that entity. For the purposes of this definition, 20 | "control" means (i) the power, direct or indirect, to cause the 21 | direction or management of such entity, whether by contract or 22 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 23 | outstanding shares, or (iii) beneficial ownership of such entity. 24 | 25 | "You" (or "Your") shall mean an individual or Legal Entity 26 | exercising permissions granted by this License. 27 | 28 | "Source" form shall mean the preferred form for making modifications, 29 | including but not limited to software source code, documentation 30 | source, and configuration files. 31 | 32 | "Object" form shall mean any form resulting from mechanical 33 | transformation or translation of a Source form, including but 34 | not limited to compiled object code, generated documentation, 35 | and conversions to other media types. 36 | 37 | "Work" shall mean the work of authorship, whether in Source or 38 | Object form, made available under the License, as indicated by a 39 | copyright notice that is included in or attached to the work 40 | (an example is provided in the Appendix below). 41 | 42 | "Derivative Works" shall mean any work, whether in Source or Object 43 | form, that is based on (or derived from) the Work and for which the 44 | editorial revisions, annotations, elaborations, or other modifications 45 | represent, as a whole, an original work of authorship. For the purposes 46 | of this License, Derivative Works shall not include works that remain 47 | separable from, or merely link (or bind by name) to the interfaces of, 48 | the Work and Derivative Works thereof. 49 | 50 | "Contribution" shall mean any work of authorship, including 51 | the original version of the Work and any modifications or additions 52 | to that Work or Derivative Works thereof, that is intentionally 53 | submitted to Licensor for inclusion in the Work by the copyright owner 54 | or by an individual or Legal Entity authorized to submit on behalf of 55 | the copyright owner. For the purposes of this definition, "submitted" 56 | means any form of electronic, verbal, or written communication sent 57 | to the Licensor or its representatives, including but not limited to 58 | communication on electronic mailing lists, source code control systems, 59 | and issue tracking systems that are managed by, or on behalf of, the 60 | Licensor for the purpose of discussing and improving the Work, but 61 | excluding communication that is conspicuously marked or otherwise 62 | designated in writing by the copyright owner as "Not a Contribution." 63 | 64 | "Contributor" shall mean Licensor and any individual or Legal Entity 65 | on behalf of whom a Contribution has been received by Licensor and 66 | subsequently incorporated within the Work. 67 | 68 | 2. Grant of Copyright License. Subject to the terms and conditions of 69 | this License, each Contributor hereby grants to You a perpetual, 70 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 71 | copyright license to reproduce, prepare Derivative Works of, 72 | publicly display, publicly perform, sublicense, and distribute the 73 | Work and such Derivative Works in Source or Object form. 74 | 75 | 3. Grant of Patent License. Subject to the terms and conditions of 76 | this License, each Contributor hereby grants to You a perpetual, 77 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 78 | (except as stated in this section) patent license to make, have made, 79 | use, offer to sell, sell, import, and otherwise transfer the Work, 80 | where such license applies only to those patent claims licensable 81 | by such Contributor that are necessarily infringed by their 82 | Contribution(s) alone or by combination of their Contribution(s) 83 | with the Work to which such Contribution(s) was submitted. If You 84 | institute patent litigation against any entity (including a 85 | cross-claim or counterclaim in a lawsuit) alleging that the Work 86 | or a Contribution incorporated within the Work constitutes direct 87 | or contributory patent infringement, then any patent licenses 88 | granted to You under this License for that Work shall terminate 89 | as of the date such litigation is filed. 90 | 91 | 4. Redistribution. You may reproduce and distribute copies of the 92 | Work or Derivative Works thereof in any medium, with or without 93 | modifications, and in Source or Object form, provided that You 94 | meet the following conditions: 95 | 96 | (a) You must give any other recipients of the Work or 97 | Derivative Works a copy of this License; and 98 | 99 | (b) You must cause any modified files to carry prominent notices 100 | stating that You changed the files; and 101 | 102 | (c) You must retain, in the Source form of any Derivative Works 103 | that You distribute, all copyright, patent, trademark, and 104 | attribution notices from the Source form of the Work, 105 | excluding those notices that do not pertain to any part of 106 | the Derivative Works; and 107 | 108 | (d) If the Work includes a "NOTICE" text file as part of its 109 | distribution, then any Derivative Works that You distribute must 110 | include a readable copy of the attribution notices contained 111 | within such NOTICE file, excluding those notices that do not 112 | pertain to any part of the Derivative Works, in at least one 113 | of the following places: within a NOTICE text file distributed 114 | as part of the Derivative Works; within the Source form or 115 | documentation, if provided along with the Derivative Works; or, 116 | within a display generated by the Derivative Works, if and 117 | wherever such third-party notices normally appear. The contents 118 | of the NOTICE file are for informational purposes only and 119 | do not modify the License. You may add Your own attribution 120 | notices within Derivative Works that You distribute, alongside 121 | or as an addendum to the NOTICE text from the Work, provided 122 | that such additional attribution notices cannot be construed 123 | as modifying the License. 124 | 125 | You may add Your own copyright statement to Your modifications and 126 | may provide additional or different license terms and conditions 127 | for use, reproduction, or distribution of Your modifications, or 128 | for any such Derivative Works as a whole, provided Your use, 129 | reproduction, and distribution of the Work otherwise complies with 130 | the conditions stated in this License. 131 | 132 | 5. Submission of Contributions. Unless You explicitly state otherwise, 133 | any Contribution intentionally submitted for inclusion in the Work 134 | by You to the Licensor shall be under the terms and conditions of 135 | this License, without any additional terms or conditions. 136 | Notwithstanding the above, nothing herein shall supersede or modify 137 | the terms of any separate license agreement you may have executed 138 | with Licensor regarding such Contributions. 139 | 140 | 6. Trademarks. This License does not grant permission to use the trade 141 | names, trademarks, service marks, or product names of the Licensor, 142 | except as required for reasonable and customary use in describing the 143 | origin of the Work and reproducing the content of the NOTICE file. 144 | 145 | 7. Disclaimer of Warranty. Unless required by applicable law or 146 | agreed to in writing, Licensor provides the Work (and each 147 | Contributor provides its Contributions) on an "AS IS" BASIS, 148 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 149 | implied, including, without limitation, any warranties or conditions 150 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 151 | PARTICULAR PURPOSE. You are solely responsible for determining the 152 | appropriateness of using or redistributing the Work and assume any 153 | risks associated with Your exercise of permissions under this License. 154 | 155 | 8. Limitation of Liability. In no event and under no legal theory, 156 | whether in tort (including negligence), contract, or otherwise, 157 | unless required by applicable law (such as deliberate and grossly 158 | negligent acts) or agreed to in writing, shall any Contributor be 159 | liable to You for damages, including any direct, indirect, special, 160 | incidental, or consequential damages of any character arising as a 161 | result of this License or out of the use or inability to use the 162 | Work (including but not limited to damages for loss of goodwill, 163 | work stoppage, computer failure or malfunction, or any and all 164 | other commercial damages or losses), even if such Contributor 165 | has been advised of the possibility of such damages. 166 | 167 | 9. Accepting Warranty or Additional Liability. While redistributing 168 | the Work or Derivative Works thereof, You may choose to offer, 169 | and charge a fee for, acceptance of support, warranty, indemnity, 170 | or other liability obligations and/or rights consistent with this 171 | License. However, in accepting such obligations, You may act only 172 | on Your own behalf and on Your sole responsibility, not on behalf 173 | of any other Contributor, and only if You agree to indemnify, 174 | defend, and hold each Contributor harmless for any liability 175 | incurred by, or claims asserted against, such Contributor by reason 176 | of your accepting any such warranty or additional liability. 177 | 178 | END OF TERMS AND CONDITIONS 179 | 180 | APPENDIX: How to apply the Apache License to your work. 181 | 182 | To apply the Apache License to your work, attach the following 183 | boilerplate notice, with the fields enclosed by brackets "[]" 184 | replaced with your own identifying information. (Don't include 185 | the brackets!) The text should be enclosed in the appropriate 186 | comment syntax for the file format. We also recommend that a 187 | file or class name and description of purpose be included on the 188 | same "printed page" as the copyright notice for easier 189 | identification within third-party archives. 190 | 191 | Copyright (c) 2019-present Caven Chen 192 | 193 | Licensed under the Apache License, Version 2.0 (the "License"); 194 | you may not use this file except in compliance with the License. 195 | You may obtain a copy of the License at 196 | 197 | http://www.apache.org/licenses/LICENSE-2.0 198 | 199 | Unless required by applicable law or agreed to in writing, software 200 | distributed under the License is distributed on an "AS IS" BASIS, 201 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 202 | See the License for the specific language governing permissions and 203 | limitations under the License. 204 | --------------------------------------------------------------------------------