From 2e1b7d5c8a0a40d553ea6e2f3e552800f16bb123 Mon Sep 17 00:00:00 2001 From: fan Date: Mon, 3 Jul 2023 13:16:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 9 + .eslintignore | 7 + .eslintrc.cjs | 90 + .gitignore | 33 + .gitmodule | 2 + .gitmodules | 7 + .npmrc | 3 + .prettierrc | 4 + .vscode/extensions.json | 15 + .vscode/settings.json | 16 + README.md | 62 + graphic-pixi | 1 + index.html | 21 + package.json | 52 + postcss.config.cjs | 27 + public/drawIcon.svg | 21 + public/favicon.ico | Bin 0 -> 64483 bytes public/icons/favicon-128x128.png | Bin 0 -> 12324 bytes public/icons/favicon-16x16.png | Bin 0 -> 859 bytes public/icons/favicon-32x32.png | Bin 0 -> 2039 bytes public/icons/favicon-96x96.png | Bin 0 -> 9643 bytes quasar.config.js | 213 + scripts/proto.cjs | 91 + scripts/sync.cjs | 70 + src/App.vue | 7 + src/api/ApiCommon.ts | 42 + src/api/DraftApi.ts | 86 + src/api/LineInfoApi.ts | 79 + src/api/PublishApi.ts | 89 + src/api/UserApi.ts | 77 + src/assets/quasar-logo-vertical.svg | 15 + src/boot/.gitkeep | 0 src/boot/@pixi/graphics-extras.ts | 7 + src/boot/axios.ts | 111 + src/components/SysMenu.vue | 85 + src/components/draw-app/DrawProperties.vue | 133 + .../properties/AxleCountingProperty.vue | 164 + .../draw-app/properties/CanvasProperty.vue | 80 + .../draw-app/properties/IscsFanProperty.vue | 42 + .../draw-app/properties/LinkProperty.vue | 96 + .../draw-app/properties/PathLineProperty.vue | 91 + .../draw-app/properties/PlatformProperty.vue | 75 + .../draw-app/properties/RectProperty.vue | 100 + .../draw-app/properties/RunLineProperty.vue | 189 + .../draw-app/properties/SectionProperty.vue | 132 + .../draw-app/properties/SeparatorProperty.vue | 57 + .../draw-app/properties/SignalProperty.vue | 85 + .../properties/StationLineProperty.vue | 87 + .../draw-app/properties/StationProperty.vue | 127 + .../draw-app/properties/TrainProperty.vue | 84 + .../properties/TrainWindowProperty.vue | 86 + .../draw-app/properties/TurnoutProperty.vue | 149 + .../draw-app/templates/LinkTemplate.vue | 96 + .../draw-app/templates/PlatformTemplate.vue | 76 + .../draw-app/templates/RectTemplate.vue | 76 + .../draw-app/templates/StationTemplate.vue | 70 + .../draw-app/templates/TrainTemplate.vue | 51 + src/configs/TokenManage.ts | 13 + src/configs/UrlManage.ts | 15 + src/css/app.scss | 1 + src/css/quasar.variables.scss | 25 + .../graphics/AxleCountingInteraction.ts | 56 + src/drawApp/graphics/GraphicDataBase.ts | 153 + src/drawApp/graphics/IscsFanInteraction.ts | 38 + src/drawApp/graphics/LinkInteraction.ts | 182 + src/drawApp/graphics/PathLineInteraction.ts | 70 + src/drawApp/graphics/PlatformInteraction.ts | 307 ++ src/drawApp/graphics/PolygonInteraction.ts | 197 + src/drawApp/graphics/RectInteraction.ts | 75 + src/drawApp/graphics/RunLineInteraction.ts | 214 + src/drawApp/graphics/SectionInteraction.ts | 69 + src/drawApp/graphics/SeparatorInteraction.ts | 43 + src/drawApp/graphics/SignalInteraction.ts | 369 ++ src/drawApp/graphics/StationInteraction.ts | 178 + .../graphics/StationLineInteraction.ts | 55 + src/drawApp/graphics/TrainInteraction.ts | 296 ++ src/drawApp/graphics/TrainLineInteraction.ts | 110 + .../graphics/TrainWindowInteraction.ts | 49 + src/drawApp/graphics/TurnoutInteraction.ts | 93 + src/drawApp/index.ts | 393 ++ src/drawApp/lineApp.ts | 137 + src/drawApp/lineNetApp.ts | 132 + src/env.d.ts | 9 + src/graphics/CommonGraphics.ts | 116 + src/graphics/axleCounting/AxleCounting.ts | 116 + .../axleCounting/AxleCountingDrawAssistant.ts | 394 ++ src/graphics/iscs-fan/IscsFan.ts | 125 + src/graphics/iscs-fan/IscsFanDrawAssistant.ts | 77 + src/graphics/iscs-fan/iscs-fan-data.json | 66 + .../iscs-fan/iscs-fan-spritesheet.png | Bin 0 -> 15944 bytes src/graphics/link/Link.ts | 102 + src/graphics/link/LinkDrawAssistant.ts | 336 ++ src/graphics/pathLine/PathLine.ts | 159 + .../pathLine/PathLineDrawAssistant.ts | 219 + src/graphics/platform/Platform.ts | 429 ++ .../platform/PlatformDrawAssistant.ts | 119 + src/graphics/polygon/Polygon.ts | 72 + src/graphics/polygon/PolygonDrawAssistant.ts | 195 + src/graphics/polygon/PolygonUtils.ts | 90 + src/graphics/rect/Rect.ts | 99 + src/graphics/rect/RectDrawAssistant.ts | 120 + src/graphics/runLine/RunLine.ts | 292 ++ src/graphics/runLine/RunLineDrawAssistant.ts | 232 + src/graphics/runLine/RunLineName.ts | 46 + src/graphics/section/Section.ts | 256 + src/graphics/section/SectionDrawAssistant.ts | 261 + src/graphics/separator/Separator.ts | 94 + .../separator/SeparatorDrawAssistant.ts | 269 + src/graphics/signal/Lamp.ts | 73 + src/graphics/signal/LampMainBody.ts | 204 + src/graphics/signal/Signal.ts | 206 + src/graphics/signal/SignalCode.ts | 50 + src/graphics/signal/SignalDrawAssistant.ts | 167 + src/graphics/station/Station.ts | 224 + src/graphics/station/StationDrawAssistant.ts | 123 + src/graphics/stationLine/StationLine.ts | 144 + .../stationLine/StationLineDrawAssistant.ts | 124 + src/graphics/train/Train.ts | 401 ++ src/graphics/train/TrainDrawAssistant.ts | 71 + src/graphics/trainLine/TrainLine.ts | 81 + src/graphics/trainLine/TrainLineAssistant.ts | 76 + src/graphics/trainLine/trainLineSprites.png | Bin 0 -> 8918 bytes src/graphics/trainWindow/TrainWindow.ts | 86 + .../trainWindow/TrainWindowDrawAssistant.ts | 227 + .../trainWindow/oneClickDrawAssistant.ts | 81 + src/graphics/turnout/Turnout.ts | 351 ++ src/graphics/turnout/TurnoutDrawAssistant.ts | 445 ++ src/jl-graphic/app/JlDrawApp.ts | 679 +++ src/jl-graphic/app/JlGraphicApp.ts | 905 ++++ src/jl-graphic/app/index.ts | 2 + src/jl-graphic/core/GraphicRelation.ts | 185 + src/jl-graphic/core/GraphicStore.ts | 185 + src/jl-graphic/core/IdGenerator.ts | 28 + src/jl-graphic/core/JlGraphic.ts | 1015 ++++ src/jl-graphic/core/index.ts | 4 + src/jl-graphic/global.d.ts | 158 + src/jl-graphic/graphic/AbsorbablePosition.ts | 252 + src/jl-graphic/graphic/DashedLine.ts | 102 + src/jl-graphic/graphic/DraggablePoint.ts | 45 + src/jl-graphic/graphic/VectorGraphic.ts | 44 + src/jl-graphic/graphic/VectorText.ts | 35 + src/jl-graphic/graphic/index.ts | 4 + src/jl-graphic/index.ts | 7 + src/jl-graphic/math/Constants.ts | 26 + src/jl-graphic/math/Vector2.ts | 360 ++ src/jl-graphic/math/index.ts | 4 + src/jl-graphic/message/WsMsgBroker.ts | 248 + src/jl-graphic/message/index.ts | 1 + src/jl-graphic/operation/JlOperation.ts | 99 + src/jl-graphic/operation/index.ts | 1 + src/jl-graphic/plugins/AnimationManager.ts | 75 + src/jl-graphic/plugins/CommonMousePlugin.ts | 328 ++ src/jl-graphic/plugins/CopyPlugin.ts | 141 + src/jl-graphic/plugins/GraphicEditPlugin.ts | 514 ++ .../plugins/GraphicTransformPlugin.ts | 899 ++++ src/jl-graphic/plugins/InteractionPlugin.ts | 489 ++ src/jl-graphic/plugins/KeyboardPlugin.ts | 351 ++ src/jl-graphic/plugins/index.ts | 6 + src/jl-graphic/ui/ContextMenu.ts | 774 +++ src/jl-graphic/ui/Menu.ts | 177 + src/jl-graphic/utils/GraphicUtils.ts | 695 +++ src/jl-graphic/utils/IntersectUtils.ts | 362 ++ src/jl-graphic/utils/index.ts | 53 + src/layouts/DrawLayout.vue | 361 ++ src/layouts/LineLayout.vue | 81 + src/layouts/MainLayout.vue | 74 + src/pages/DraftManage.vue | 365 ++ src/pages/ErrorNotFound.vue | 27 + src/pages/IndexPage.vue | 7 + src/pages/LineInfoManage.vue | 270 + src/pages/LineMonitorPage.vue | 69 + src/pages/MonitorPage.vue | 91 + src/pages/PublishManage.vue | 182 + src/pages/UserLogin.vue | 90 + src/pages/UserManage.vue | 215 + src/pages/UserRegister.vue | 97 + src/protos/Device.ts | 566 +++ src/protos/LineNetTrainOffset.ts | 234 + src/protos/LineNetTrainOffsetDiagram.ts | 236 + src/protos/device_info.ts | 327 ++ src/protos/device_status.ts | 4489 +++++++++++++++++ src/protos/section_status.ts | 219 + src/protos/stationLayoutGraphics.ts | 4126 +++++++++++++++ src/protos/train.ts | 1512 ++++++ src/protos/ws_message.ts | 646 +++ src/quasar.d.ts | 9 + src/router/index.ts | 36 + src/router/routes.ts | 90 + src/shims-vue.d.ts | 10 + src/stores/draw-store.ts | 87 + src/stores/example-store.ts | 15 + src/stores/index.ts | 32 + src/stores/line-net-store.ts | 58 + src/stores/line-store.ts | 50 + src/stores/store-flag.d.ts | 10 + src/utils/CommonNotify.ts | 38 + tsconfig.json | 8 + yarn.lock | 3399 +++++++++++++ 198 files changed, 41564 insertions(+) create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc.cjs create mode 100644 .gitignore create mode 100644 .gitmodule create mode 100644 .gitmodules create mode 100644 .npmrc create mode 100644 .prettierrc create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json create mode 100644 README.md create mode 160000 graphic-pixi create mode 100644 index.html create mode 100644 package.json create mode 100644 postcss.config.cjs create mode 100644 public/drawIcon.svg create mode 100644 public/favicon.ico create mode 100644 public/icons/favicon-128x128.png create mode 100644 public/icons/favicon-16x16.png create mode 100644 public/icons/favicon-32x32.png create mode 100644 public/icons/favicon-96x96.png create mode 100644 quasar.config.js create mode 100644 scripts/proto.cjs create mode 100644 scripts/sync.cjs create mode 100644 src/App.vue create mode 100644 src/api/ApiCommon.ts create mode 100644 src/api/DraftApi.ts create mode 100644 src/api/LineInfoApi.ts create mode 100644 src/api/PublishApi.ts create mode 100644 src/api/UserApi.ts create mode 100644 src/assets/quasar-logo-vertical.svg create mode 100644 src/boot/.gitkeep create mode 100644 src/boot/@pixi/graphics-extras.ts create mode 100644 src/boot/axios.ts create mode 100644 src/components/SysMenu.vue create mode 100644 src/components/draw-app/DrawProperties.vue create mode 100644 src/components/draw-app/properties/AxleCountingProperty.vue create mode 100644 src/components/draw-app/properties/CanvasProperty.vue create mode 100644 src/components/draw-app/properties/IscsFanProperty.vue create mode 100644 src/components/draw-app/properties/LinkProperty.vue create mode 100644 src/components/draw-app/properties/PathLineProperty.vue create mode 100644 src/components/draw-app/properties/PlatformProperty.vue create mode 100644 src/components/draw-app/properties/RectProperty.vue create mode 100644 src/components/draw-app/properties/RunLineProperty.vue create mode 100644 src/components/draw-app/properties/SectionProperty.vue create mode 100644 src/components/draw-app/properties/SeparatorProperty.vue create mode 100644 src/components/draw-app/properties/SignalProperty.vue create mode 100644 src/components/draw-app/properties/StationLineProperty.vue create mode 100644 src/components/draw-app/properties/StationProperty.vue create mode 100644 src/components/draw-app/properties/TrainProperty.vue create mode 100644 src/components/draw-app/properties/TrainWindowProperty.vue create mode 100644 src/components/draw-app/properties/TurnoutProperty.vue create mode 100644 src/components/draw-app/templates/LinkTemplate.vue create mode 100644 src/components/draw-app/templates/PlatformTemplate.vue create mode 100644 src/components/draw-app/templates/RectTemplate.vue create mode 100644 src/components/draw-app/templates/StationTemplate.vue create mode 100644 src/components/draw-app/templates/TrainTemplate.vue create mode 100644 src/configs/TokenManage.ts create mode 100644 src/configs/UrlManage.ts create mode 100644 src/css/app.scss create mode 100644 src/css/quasar.variables.scss create mode 100644 src/drawApp/graphics/AxleCountingInteraction.ts create mode 100644 src/drawApp/graphics/GraphicDataBase.ts create mode 100644 src/drawApp/graphics/IscsFanInteraction.ts create mode 100644 src/drawApp/graphics/LinkInteraction.ts create mode 100644 src/drawApp/graphics/PathLineInteraction.ts create mode 100644 src/drawApp/graphics/PlatformInteraction.ts create mode 100644 src/drawApp/graphics/PolygonInteraction.ts create mode 100644 src/drawApp/graphics/RectInteraction.ts create mode 100644 src/drawApp/graphics/RunLineInteraction.ts create mode 100644 src/drawApp/graphics/SectionInteraction.ts create mode 100644 src/drawApp/graphics/SeparatorInteraction.ts create mode 100644 src/drawApp/graphics/SignalInteraction.ts create mode 100644 src/drawApp/graphics/StationInteraction.ts create mode 100644 src/drawApp/graphics/StationLineInteraction.ts create mode 100644 src/drawApp/graphics/TrainInteraction.ts create mode 100644 src/drawApp/graphics/TrainLineInteraction.ts create mode 100644 src/drawApp/graphics/TrainWindowInteraction.ts create mode 100644 src/drawApp/graphics/TurnoutInteraction.ts create mode 100644 src/drawApp/index.ts create mode 100644 src/drawApp/lineApp.ts create mode 100644 src/drawApp/lineNetApp.ts create mode 100644 src/env.d.ts create mode 100644 src/graphics/CommonGraphics.ts create mode 100644 src/graphics/axleCounting/AxleCounting.ts create mode 100644 src/graphics/axleCounting/AxleCountingDrawAssistant.ts create mode 100644 src/graphics/iscs-fan/IscsFan.ts create mode 100644 src/graphics/iscs-fan/IscsFanDrawAssistant.ts create mode 100644 src/graphics/iscs-fan/iscs-fan-data.json create mode 100644 src/graphics/iscs-fan/iscs-fan-spritesheet.png create mode 100644 src/graphics/link/Link.ts create mode 100644 src/graphics/link/LinkDrawAssistant.ts create mode 100644 src/graphics/pathLine/PathLine.ts create mode 100644 src/graphics/pathLine/PathLineDrawAssistant.ts create mode 100644 src/graphics/platform/Platform.ts create mode 100644 src/graphics/platform/PlatformDrawAssistant.ts create mode 100644 src/graphics/polygon/Polygon.ts create mode 100644 src/graphics/polygon/PolygonDrawAssistant.ts create mode 100644 src/graphics/polygon/PolygonUtils.ts create mode 100644 src/graphics/rect/Rect.ts create mode 100644 src/graphics/rect/RectDrawAssistant.ts create mode 100644 src/graphics/runLine/RunLine.ts create mode 100644 src/graphics/runLine/RunLineDrawAssistant.ts create mode 100644 src/graphics/runLine/RunLineName.ts create mode 100644 src/graphics/section/Section.ts create mode 100644 src/graphics/section/SectionDrawAssistant.ts create mode 100644 src/graphics/separator/Separator.ts create mode 100644 src/graphics/separator/SeparatorDrawAssistant.ts create mode 100644 src/graphics/signal/Lamp.ts create mode 100644 src/graphics/signal/LampMainBody.ts create mode 100644 src/graphics/signal/Signal.ts create mode 100644 src/graphics/signal/SignalCode.ts create mode 100644 src/graphics/signal/SignalDrawAssistant.ts create mode 100644 src/graphics/station/Station.ts create mode 100644 src/graphics/station/StationDrawAssistant.ts create mode 100644 src/graphics/stationLine/StationLine.ts create mode 100644 src/graphics/stationLine/StationLineDrawAssistant.ts create mode 100644 src/graphics/train/Train.ts create mode 100644 src/graphics/train/TrainDrawAssistant.ts create mode 100644 src/graphics/trainLine/TrainLine.ts create mode 100644 src/graphics/trainLine/TrainLineAssistant.ts create mode 100644 src/graphics/trainLine/trainLineSprites.png create mode 100644 src/graphics/trainWindow/TrainWindow.ts create mode 100644 src/graphics/trainWindow/TrainWindowDrawAssistant.ts create mode 100644 src/graphics/trainWindow/oneClickDrawAssistant.ts create mode 100644 src/graphics/turnout/Turnout.ts create mode 100644 src/graphics/turnout/TurnoutDrawAssistant.ts create mode 100644 src/jl-graphic/app/JlDrawApp.ts create mode 100644 src/jl-graphic/app/JlGraphicApp.ts create mode 100644 src/jl-graphic/app/index.ts create mode 100644 src/jl-graphic/core/GraphicRelation.ts create mode 100644 src/jl-graphic/core/GraphicStore.ts create mode 100644 src/jl-graphic/core/IdGenerator.ts create mode 100644 src/jl-graphic/core/JlGraphic.ts create mode 100644 src/jl-graphic/core/index.ts create mode 100644 src/jl-graphic/global.d.ts create mode 100644 src/jl-graphic/graphic/AbsorbablePosition.ts create mode 100644 src/jl-graphic/graphic/DashedLine.ts create mode 100644 src/jl-graphic/graphic/DraggablePoint.ts create mode 100644 src/jl-graphic/graphic/VectorGraphic.ts create mode 100644 src/jl-graphic/graphic/VectorText.ts create mode 100644 src/jl-graphic/graphic/index.ts create mode 100644 src/jl-graphic/index.ts create mode 100644 src/jl-graphic/math/Constants.ts create mode 100644 src/jl-graphic/math/Vector2.ts create mode 100644 src/jl-graphic/math/index.ts create mode 100644 src/jl-graphic/message/WsMsgBroker.ts create mode 100644 src/jl-graphic/message/index.ts create mode 100644 src/jl-graphic/operation/JlOperation.ts create mode 100644 src/jl-graphic/operation/index.ts create mode 100644 src/jl-graphic/plugins/AnimationManager.ts create mode 100644 src/jl-graphic/plugins/CommonMousePlugin.ts create mode 100644 src/jl-graphic/plugins/CopyPlugin.ts create mode 100644 src/jl-graphic/plugins/GraphicEditPlugin.ts create mode 100644 src/jl-graphic/plugins/GraphicTransformPlugin.ts create mode 100644 src/jl-graphic/plugins/InteractionPlugin.ts create mode 100644 src/jl-graphic/plugins/KeyboardPlugin.ts create mode 100644 src/jl-graphic/plugins/index.ts create mode 100644 src/jl-graphic/ui/ContextMenu.ts create mode 100644 src/jl-graphic/ui/Menu.ts create mode 100644 src/jl-graphic/utils/GraphicUtils.ts create mode 100644 src/jl-graphic/utils/IntersectUtils.ts create mode 100644 src/jl-graphic/utils/index.ts create mode 100644 src/layouts/DrawLayout.vue create mode 100644 src/layouts/LineLayout.vue create mode 100644 src/layouts/MainLayout.vue create mode 100644 src/pages/DraftManage.vue create mode 100644 src/pages/ErrorNotFound.vue create mode 100644 src/pages/IndexPage.vue create mode 100644 src/pages/LineInfoManage.vue create mode 100644 src/pages/LineMonitorPage.vue create mode 100644 src/pages/MonitorPage.vue create mode 100644 src/pages/PublishManage.vue create mode 100644 src/pages/UserLogin.vue create mode 100644 src/pages/UserManage.vue create mode 100644 src/pages/UserRegister.vue create mode 100644 src/protos/Device.ts create mode 100644 src/protos/LineNetTrainOffset.ts create mode 100644 src/protos/LineNetTrainOffsetDiagram.ts create mode 100644 src/protos/device_info.ts create mode 100644 src/protos/device_status.ts create mode 100644 src/protos/section_status.ts create mode 100644 src/protos/stationLayoutGraphics.ts create mode 100644 src/protos/train.ts create mode 100644 src/protos/ws_message.ts create mode 100644 src/quasar.d.ts create mode 100644 src/router/index.ts create mode 100644 src/router/routes.ts create mode 100644 src/shims-vue.d.ts create mode 100644 src/stores/draw-store.ts create mode 100644 src/stores/example-store.ts create mode 100644 src/stores/index.ts create mode 100644 src/stores/line-net-store.ts create mode 100644 src/stores/line-store.ts create mode 100644 src/stores/store-flag.d.ts create mode 100644 src/utils/CommonNotify.ts create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9d08a1a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..7b59e09 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,7 @@ +/dist +/src-capacitor +/src-cordova +/.quasar +/node_modules +.eslintrc.js +/src-ssr diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..796b2e8 --- /dev/null +++ b/.eslintrc.cjs @@ -0,0 +1,90 @@ +module.exports = { + // https://eslint.org/docs/user-guide/configuring#configuration-cascading-and-hierarchy + // This option interrupts the configuration hierarchy at this file + // Remove this if you have an higher level ESLint config file (it usually happens into a monorepos) + root: true, + + // https://eslint.vuejs.org/user-guide/#how-to-use-a-custom-parser + // Must use parserOptions instead of "parser" to allow vue-eslint-parser to keep working + // `parser: 'vue-eslint-parser'` is already included with any 'plugin:vue/**' config and should be omitted + parserOptions: { + parser: require.resolve('@typescript-eslint/parser'), + extraFileExtensions: [ '.vue' ] + }, + + env: { + browser: true, + es2021: true, + node: true, + 'vue/setup-compiler-macros': true + }, + + // Rules order is important, please avoid shuffling them + extends: [ + // Base ESLint recommended rules + // 'eslint:recommended', + + // https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/eslint-plugin#usage + // ESLint typescript rules + 'plugin:@typescript-eslint/recommended', + + // Uncomment any of the lines below to choose desired strictness, + // but leave only one uncommented! + // See https://eslint.vuejs.org/rules/#available-rules + 'plugin:vue/vue3-essential', // Priority A: Essential (Error Prevention) + // 'plugin:vue/vue3-strongly-recommended', // Priority B: Strongly Recommended (Improving Readability) + // 'plugin:vue/vue3-recommended', // Priority C: Recommended (Minimizing Arbitrary Choices and Cognitive Overhead) + + // https://github.com/prettier/eslint-config-prettier#installation + // usage with Prettier, provided by 'eslint-config-prettier'. + 'prettier' + ], + + plugins: [ + // required to apply rules which need type information + '@typescript-eslint', + + // https://eslint.vuejs.org/user-guide/#why-doesn-t-it-work-on-vue-files + // required to lint *.vue files + 'vue' + + // https://github.com/typescript-eslint/typescript-eslint/issues/389#issuecomment-509292674 + // Prettier has not been included as plugin to avoid performance impact + // add it as an extension for your IDE + + ], + + globals: { + ga: 'readonly', // Google Analytics + cordova: 'readonly', + __statics: 'readonly', + __QUASAR_SSR__: 'readonly', + __QUASAR_SSR_SERVER__: 'readonly', + __QUASAR_SSR_CLIENT__: 'readonly', + __QUASAR_SSR_PWA__: 'readonly', + process: 'readonly', + Capacitor: 'readonly', + chrome: 'readonly' + }, + + // add your custom rules here + rules: { + + 'prefer-promise-reject-errors': 'off', + + quotes: ['warn', 'single', { avoidEscape: true }], + + // this rule, if on, would require explicit return type on the `render` function + '@typescript-eslint/explicit-function-return-type': 'off', + + // in plain CommonJS modules, you can't use `import foo = require('foo')` to pass this rule, so it has to be disabled + '@typescript-eslint/no-var-requires': 'off', + + // The core 'no-unused-vars' rules (in the eslint:recommended ruleset) + // does not work with type definitions + 'no-unused-vars': 'off', + + // allow debugger during development only + 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..553e134 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +.DS_Store +.thumbs.db +node_modules + +# Quasar core related directories +.quasar +/dist + +# Cordova related directories and files +/src-cordova/node_modules +/src-cordova/platforms +/src-cordova/plugins +/src-cordova/www + +# Capacitor related directories and files +/src-capacitor/www +/src-capacitor/node_modules + +# BEX related directories and files +/src-bex/www +/src-bex/js/core + +# Log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Editor directories and files +.idea +*.suo +*.ntvs* +*.njsproj +*.sln diff --git a/.gitmodule b/.gitmodule new file mode 100644 index 0000000..0f4cb2d --- /dev/null +++ b/.gitmodule @@ -0,0 +1,2 @@ +[submodule "graphic-pixi"] + branch = bj-rtss diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2eba59a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,7 @@ +[submodule "bj-rtss-message"] + path = bj-rtss-message + url = https://git.code.tencent.com/beijing-rtss-test/bj-rtss-message.git +[submodule "graphic-pixi"] + path = graphic-pixi + url = https://git.code.tencent.com/jl-framework/graphic-pixi.git + branch = bj-rtss diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..32bd84d --- /dev/null +++ b/.npmrc @@ -0,0 +1,3 @@ +# pnpm-related options +shamefully-hoist=true +strict-peer-dependencies=false diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..650cb88 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "semi": true +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..fe38802 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,15 @@ +{ + "recommendations": [ + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode", + "editorconfig.editorconfig", + "vue.volar", + "wayou.vscode-todo-highlight" + ], + "unwantedRecommendations": [ + "octref.vetur", + "hookyqr.beautify", + "dbaeumer.jshint", + "ms-vscode.vscode-typescript-tslint-plugin" + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..746cf57 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,16 @@ +{ + "editor.bracketPairColorization.enabled": true, + "editor.guides.bracketPairs": true, + "editor.formatOnSave": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "editor.codeActionsOnSave": [ + "source.fixAll.eslint" + ], + "eslint.validate": [ + "javascript", + "javascriptreact", + "typescript", + "vue" + ], + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b725997 --- /dev/null +++ b/README.md @@ -0,0 +1,62 @@ +# BjRtssClient (bj-rtss-client) + +beijing rtss 测试系统 + +## 项目 clone 说明 + +此项目包含子模块,拉取方式: + +- 1.在克隆主项目的时候带上参数 --recurse-submodules +- 2.或者 clone 完成后,在项目目录中执行:git submodule init && git submodule update + +## 安装依赖 + +```bash +yarn +# or +npm install +``` + +## 编译 proto 文件 + +```bash +yarn run proto +# or +npm run proto +``` + +### Start the app in development mode (hot-code reloading, error reporting, etc.) + +```bash +quasar dev +# or +yarn run dev +# or +npm run dev +``` + +### Lint the files + +```bash +yarn lint +# or +npm run lint +``` + +### Format the files + +```bash +yarn format +# or +npm run format +``` + +### Build the app for production + +```bash +quasar build +``` + +### Customize the configuration + +See [Configuring quasar.config.js](https://v2.quasar.dev/quasar-cli-vite/quasar-config-js). diff --git a/graphic-pixi b/graphic-pixi new file mode 160000 index 0000000..7e4eaed --- /dev/null +++ b/graphic-pixi @@ -0,0 +1 @@ +Subproject commit 7e4eaed0cf06d68c75cb51c30329eff5fe4d1e3f diff --git a/index.html b/index.html new file mode 100644 index 0000000..3c8c78f --- /dev/null +++ b/index.html @@ -0,0 +1,21 @@ + + + + <%= productName %> + + + + + + + + + + + + + + + + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..d6f2c59 --- /dev/null +++ b/package.json @@ -0,0 +1,52 @@ +{ + "name": "bj-rtss-client", + "version": "0.0.1", + "description": "beijing rtss 测试系统", + "productName": "BJRTSSCLIENT", + "author": "walker ", + "private": true, + "scripts": { + "lint": "eslint --ext .js,.ts,.vue ./", + "format": "prettier --write \"**/*.{js,ts,vue,scss,html,md,json}\" --ignore-path .gitignore", + "test": "echo \"No test specified\" && exit 0", + "dev": "quasar dev", + "build": "quasar build", + "protoc": "node scripts/proto.cjs", + "sync": "node scripts/sync.cjs" + }, + "dependencies": { + "@pixi/filter-outline": "^5.2.0", + "@pixi/graphics-extras": "^7.2.4", + "@quasar/extras": "^1.0.0", + "@stomp/stompjs": "^7.0.0", + "axios": "^1.2.1", + "google-protobuf": "^3.21.2", + "js-base64": "^3.7.5", + "pinia": "^2.0.11", + "pixi-viewport": "^5.0.1", + "pixi.js": "^7.2.4", + "quasar": "^2.6.0", + "vue": "^3.0.0", + "vue-router": "^4.0.0" + }, + "devDependencies": { + "@quasar/app-vite": "^1.0.0", + "@types/google-protobuf": "^3.15.6", + "@types/node": "^12.20.21", + "@typescript-eslint/eslint-plugin": "^5.10.0", + "@typescript-eslint/parser": "^5.10.0", + "autoprefixer": "^10.4.2", + "eslint": "^8.10.0", + "eslint-config-prettier": "^8.1.0", + "eslint-plugin-vue": "^9.0.0", + "prettier": "^2.5.1", + "protoc-gen-ts": "^0.8.6", + "ts-md5": "^1.3.1", + "typescript": "^4.5.4" + }, + "engines": { + "node": "^18 || ^16 || ^14.19", + "npm": ">= 6.13.4", + "yarn": ">= 1.21.1" + } +} diff --git a/postcss.config.cjs b/postcss.config.cjs new file mode 100644 index 0000000..94b7b1c --- /dev/null +++ b/postcss.config.cjs @@ -0,0 +1,27 @@ +/* eslint-disable */ +// https://github.com/michael-ciniawsky/postcss-load-config + +module.exports = { + plugins: [ + // https://github.com/postcss/autoprefixer + require('autoprefixer')({ + overrideBrowserslist: [ + 'last 4 Chrome versions', + 'last 4 Firefox versions', + 'last 4 Edge versions', + 'last 4 Safari versions', + 'last 4 Android versions', + 'last 4 ChromeAndroid versions', + 'last 4 FirefoxAndroid versions', + 'last 4 iOS versions' + ] + }) + + // https://github.com/elchininet/postcss-rtlcss + // If you want to support RTL css, then + // 1. yarn/npm install postcss-rtlcss + // 2. optionally set quasar.config.js > framework > lang to an RTL language + // 3. uncomment the following line: + // require('postcss-rtlcss') + ] +} diff --git a/public/drawIcon.svg b/public/drawIcon.svg new file mode 100644 index 0000000..e6ff62e --- /dev/null +++ b/public/drawIcon.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ae7bbdb712f8ce9fe49761b68ef3a2d4c51606f9 GIT binary patch literal 64483 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 literal 0 HcmV?d00001 diff --git a/public/icons/favicon-128x128.png b/public/icons/favicon-128x128.png new file mode 100644 index 0000000000000000000000000000000000000000..14011761929f4ffbef81be318a347c0032eb6f42 GIT binary patch literal 12324 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 h$J#u>{O`^5_ boot files are part of "main.js" + // https://v2.quasar.dev/quasar-cli-vite/boot-files + boot: ['axios', '@pixi/graphics-extras'], + + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#css + css: ['app.scss'], + + // https://github.com/quasarframework/quasar/tree/dev/extras + extras: [ + // 'ionicons-v4', + // 'mdi-v5', + // 'fontawesome-v6', + // 'eva-icons', + // 'themify', + // 'line-awesome', + // 'roboto-font-latin-ext', // this or either 'roboto-font', NEVER both! + + 'roboto-font', // optional, you are not bound to it + 'material-icons', // optional, you are not bound to it + 'material-symbols-outlined', + ], + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#build + build: { + target: { + browser: ['es2019', 'edge88', 'firefox78', 'chrome87', 'safari13.1'], + node: 'node16', + }, + + vueRouterMode: 'history', // available values: 'hash', 'history' + vueRouterBase: BasePath, + // vueDevtools, + // vueOptionsAPI: false, + + // rebuildCache: true, // rebuilds Vite/linter/etc cache on startup + + publicPath: BasePath, + // analyze: true, + // env: {}, + // rawDefine: {} + // ignorePublicFolder: true, + // minify: false, + // polyfillModulePreload: true, + // distDir + // distDir: `dist/${BasePath}`, + + // extendViteConf (viteConf) {}, + // viteVuePluginOptions: {}, + + // vitePlugins: [ + // [ 'package-name', { ..options.. } ] + // ] + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#devServer + devServer: { + // https: true + open: true, // opens browser window automatically + base: BasePath, + }, + + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#framework + framework: { + config: { + notify: { + position: 'top', + timeout: 2000, + progress: true, + }, + }, + + // iconSet: 'material-icons', // Quasar icon set + // lang: 'en-US', // Quasar language pack + lang: 'zh-CN', + + // For special cases outside of where the auto-import strategy can have an impact + // (like functional components as one of the examples), + // you can manually specify Quasar components/directives to be available everywhere: + // + // components: [], + // directives: [], + + // Quasar plugins + plugins: ['Notify', 'Dialog', 'Dark', 'AppFullscreen', 'Loading'], + }, + + // animations: 'all', // --- includes all animations + // https://v2.quasar.dev/options/animations + animations: [], + + // https://v2.quasar.dev/quasar-cli-vite/quasar-config-js#sourcefiles + // sourceFiles: { + // rootComponent: 'src/App.vue', + // router: 'src/router/index', + // store: 'src/store/index', + // registerServiceWorker: 'src-pwa/register-service-worker', + // serviceWorker: 'src-pwa/custom-service-worker', + // pwaManifestFile: 'src-pwa/manifest.json', + // electronMain: 'src-electron/electron-main', + // electronPreload: 'src-electron/electron-preload' + // }, + + // https://v2.quasar.dev/quasar-cli-vite/developing-ssr/configuring-ssr + ssr: { + // ssrPwaHtmlFilename: 'offline.html', // do NOT use index.html as name! + // will mess up SSR + + // extendSSRWebserverConf (esbuildConf) {}, + // extendPackageJson (json) {}, + + pwa: false, + + // manualStoreHydration: true, + // manualPostHydrationTrigger: true, + + prodPort: 3000, // The default port that the production server should use + // (gets superseded if process.env.PORT is specified at runtime) + + middlewares: [ + 'render', // keep this as last one + ], + }, + + // https://v2.quasar.dev/quasar-cli-vite/developing-pwa/configuring-pwa + pwa: { + workboxMode: 'generateSW', // or 'injectManifest' + injectPwaMetaTags: true, + swFilename: 'sw.js', + manifestFilename: 'manifest.json', + useCredentialsForManifestTag: false, + // useFilenameHashes: true, + // extendGenerateSWOptions (cfg) {} + // extendInjectManifestOptions (cfg) {}, + // extendManifestJson (json) {} + // extendPWACustomSWConf (esbuildConf) {} + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-cordova-apps/configuring-cordova + cordova: { + // noIosLegacyBuildFlag: true, // uncomment only if you know what you are doing + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-capacitor-apps/configuring-capacitor + capacitor: { + hideSplashscreen: true, + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-electron-apps/configuring-electron + electron: { + // extendElectronMainConf (esbuildConf) + // extendElectronPreloadConf (esbuildConf) + + inspectPort: 5858, + + bundler: 'packager', // 'packager' or 'builder' + + packager: { + // https://github.com/electron-userland/electron-packager/blob/master/docs/api.md#options + // OS X / Mac App Store + // appBundleId: '', + // appCategoryType: '', + // osxSign: '', + // protocol: 'myapp://path', + // Windows only + // win32metadata: { ... } + }, + + builder: { + // https://www.electron.build/configuration/configuration + + appId: 'bj-rtss-client', + }, + }, + + // Full list of options: https://v2.quasar.dev/quasar-cli-vite/developing-browser-extensions/configuring-bex + bex: { + contentScripts: ['my-content-script'], + + // extendBexScriptsConf (esbuildConf) {} + // extendBexManifestJson (json) {} + }, + }; +}); diff --git a/scripts/proto.cjs b/scripts/proto.cjs new file mode 100644 index 0000000..90b41ad --- /dev/null +++ b/scripts/proto.cjs @@ -0,0 +1,91 @@ +/** + * 将proto文件编译到 src/proto/ + */ +const { readdirSync } = require('fs'); +const { resolve } = require('path'); +const os = require('os'); + +const { exec } = require('child_process'); + +const messageDir = resolve(__dirname, '../bj-rtss-message'); +const protoDir = resolve(messageDir, 'protos'); +const destDir = resolve(__dirname, '../src/protos'); + +/** + * 递归处理所有proto文件生成 + * @param {*} file 文件 + * @param {*} path 目录 + */ +function recursiveGenerate(file, path = [], cmds = []) { + if (file.isFile()) { + // 文件,生成 + if (file.name.endsWith('.proto')) { + cmds.push(buildGenerateCmd(file.name, path)); + } else { + console.warn('不是proto文件', file.name); + } + } else if (file.isDirectory()) { + // 文件夹,递归 + readdirSync(resolve(protoDir, ...path, file.name), { + withFileTypes: true, + }).forEach((f) => { + const subPath = [...path, file.name]; + recursiveGenerate(f, subPath, cmds); + }); + } +} + +const isLinux = os.type().toLowerCase().includes('linux'); + +function buildGenerateCmd(name, path = []) { + const protoPath = resolve(protoDir, ...path); + const tsPath = resolve(destDir, ...path); + + let cmd = ['protoc', `-I=${protoPath}`, `--ts_out=${tsPath}`, `${name}`]; + let cmdStr = cmd.join(' '); + return cmdStr; +} + +function main() { + const protocDir = resolve(messageDir, 'protoc-23.1'); + const protocBin = resolve( + protocDir, + `bin/${isLinux ? 'linux-x86_64' : 'win64'}` + ); + const prepareCmds = []; + const setPathCmd = isLinux + ? ['export', `PATH=${protocBin}:${protocDir}:"$PATH"`].join(' ') + : ['set', `PATH=${protocBin};${protocDir};%PATH%`].join(' '); + const protocVersionCmd = ['protoc', '--version'].join(' '); + prepareCmds.push(setPathCmd); + prepareCmds.push(protocVersionCmd); + + readdirSync(protoDir, { + withFileTypes: true, + }).forEach((f) => { + recursiveGenerate(f, [], prepareCmds); + }); + + console.log(prepareCmds); + + exec( + prepareCmds.join(' && '), + { + maxBuffer: 1024 * 2000, + }, + (err, stdout, stderr) => { + if (err) { + console.error(err); + throw err; + } else if (stderr.length > 0) { + console.error(stderr.toString()); + throw new Error(stderr.toString()); + } else { + console.log(stdout); + } + } + ); +} + +// 执行 +main(); diff --git a/scripts/sync.cjs b/scripts/sync.cjs new file mode 100644 index 0000000..a8fc918 --- /dev/null +++ b/scripts/sync.cjs @@ -0,0 +1,70 @@ +/** + * 同步图形框架文件到 src/jl-graphic/ + */ +const { + readdirSync, + existsSync, + copyFileSync, + mkdirSync, + rmSync, +} = require('fs'); +const { resolve } = require('path'); + +const jlGraphicSrcPath = resolve(__dirname, '../graphic-pixi/src/jlgraphic'); +const jlGraphicLibPath = resolve(__dirname, '../src/jl-graphic'); + +/** + * 检查并初始化当前项目引入的jl-graphic库 + */ +function checkAndInitJlGraphicLib() { + const exist = existsSync(jlGraphicLibPath); + if (exist) { + console.log('jl-graphic文件夹已存在,清空'); + readdirSync(jlGraphicLibPath, { + withFileTypes: true, + }).forEach((file) => { + if (file.isDirectory()) { + rmSync(resolve(jlGraphicLibPath, file.name), { recursive: true }); + } else { + rmSync(resolve(jlGraphicLibPath, file.name)); + } + }); + } else { + console.log('jl-graphic文件夹不存在,创建'); + // 文件夹不存在,创建 + mkdirSync(jlGraphicLibPath); + } +} + +function copyJlGraphicFiles() { + readdirSync(jlGraphicSrcPath, { + withFileTypes: true, + }).forEach((file) => { + recursiveCopyFiles(file); + }); +} + +function recursiveCopyFiles(file, path = []) { + if (file.isFile()) { + const fileSrcPath = resolve(jlGraphicSrcPath, ...path, file.name); + const fileDestPath = resolve(jlGraphicLibPath, ...path, file.name); + console.log(`copy file ${fileSrcPath} -> ${fileDestPath}`); + copyFileSync(fileSrcPath, fileDestPath); + } else if (file.isDirectory()) { + const srcDir = resolve(jlGraphicSrcPath, ...path, file.name); + const dirPath = resolve(jlGraphicLibPath, ...path, file.name); + mkdirSync(dirPath); + readdirSync(srcDir, { + withFileTypes: true, + }).forEach((subFile) => { + recursiveCopyFiles(subFile, [...path, file.name]); + }); + } +} + +function main() { + checkAndInitJlGraphicLib(); + copyJlGraphicFiles(); +} + +main(); diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..fe0a246 --- /dev/null +++ b/src/App.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/api/ApiCommon.ts b/src/api/ApiCommon.ts new file mode 100644 index 0000000..18494ce --- /dev/null +++ b/src/api/ApiCommon.ts @@ -0,0 +1,42 @@ +export class PageQueryDto { + current: number; + size: number; + orders?: OrderItemDto[]; + constructor(current: number, size: number, orders?: OrderItemDto[]) { + this.current = current; + this.size = size; + this.orders = orders; + } +} + +export class OrderItemDto { + column: string; + asc: boolean; + constructor(column: string, asc: boolean) { + this.column = column; + this.asc = asc; + } + + static asc(column: string): OrderItemDto { + return new OrderItemDto(column, true); + } + static desc(column: string): OrderItemDto { + return new OrderItemDto(column, false); + } +} + +export interface PageDto { + records: T[]; + /** + * 记录总数 + */ + total: number; + /** + * 第几页 + */ + current: number; + /** + * 每页数量 + */ + size: number; +} diff --git a/src/api/DraftApi.ts b/src/api/DraftApi.ts new file mode 100644 index 0000000..92970da --- /dev/null +++ b/src/api/DraftApi.ts @@ -0,0 +1,86 @@ +import { api } from 'src/boot/axios'; +import { PageDto, PageQueryDto } from './ApiCommon'; + +const DraftUriBase = '/api/drafting'; + +interface Item { + id: number; + name: string; + proto: string; + type: string; + createdAt: string; + updateAt: string; + creatorId?: number; +} + +export class PagingQueryParams extends PageQueryDto { + name?: string; +} + +/** + * 分页查询 + * @param params + * @returns + */ +export async function pageQuery( + params: PagingQueryParams +): Promise> { + const response = await api.get(`${DraftUriBase}/paging`, { + params: params, + }); + return response.data; +} + +/** + * 创建草稿 + * @param params + * @returns + */ +export function createDraft(draftData: { name: string; type: string }) { + return api.post(`${DraftUriBase}`, draftData); +} + +/** + * 删除草稿 + * @param id 草稿id + */ +export function deleteDraft(id: number) { + return api.delete(`${DraftUriBase}/${id}`); +} + +/** + * 获取草稿数据 + * @param params + * @returns + */ +export async function getDraft(id: number): Promise { + const response = await api.get(`${DraftUriBase}/${id}`); + return response.data; +} + +/** + * 保存草稿数据 + * @param data + * @returns + */ +export function saveDraft( + id: number, + data: { + proto: string; + } +) { + return api.put(`${DraftUriBase}/${id}`, data); +} + +/** + * 另存草稿数据 + * @param data + * @returns + */ +export async function saveAsDraft( + id: number, + data: { name: string; proto: string } +): Promise { + const response = await api.post(`${DraftUriBase}/${id}/saveAs`, data); + return response.data; +} diff --git a/src/api/LineInfoApi.ts b/src/api/LineInfoApi.ts new file mode 100644 index 0000000..a2c5fb2 --- /dev/null +++ b/src/api/LineInfoApi.ts @@ -0,0 +1,79 @@ +import { api } from 'src/boot/axios'; +import { PageDto, PageQueryDto } from './ApiCommon'; + +const UriBase = '/api/lineInfo'; + +export interface createParams { + name: string; + lineId: number; + config?: string; +} + +interface Item extends createParams { + id: number; + createdAt: string; + updateAt: string; +} + +export class PagingQueryParams extends PageQueryDto { + name?: string; +} + +/** + * 分页查询 + * @param params + * @returns + */ +export async function pageQuery( + params: PagingQueryParams +): Promise> { + const response = await api.get(`${UriBase}/paging`, { + params: params, + }); + return response.data; +} + +/** + * 创建线路 + * @param params + * @returns + */ +export function createLine(data: createParams) { + return api.post(`${UriBase}`, data); +} + +/** + * 删除线路 + * @param id 线路id + */ +export function deleteLine(id: number) { + return api.delete(`${UriBase}/${id}`); +} + +/** + * 保存线路数据 + * @param id 草稿id + */ +export function saveLineData(id: number, data: createParams) { + return api.put(`${UriBase}/${id}`, data); +} + +/** + * 获取线路数据详情 + * @param params + * @returns + */ +export async function getLineInfo(id: number): Promise { + const response = await api.get(`${UriBase}/${id}`); + return response.data; +} + +/** + * 获取线路信息列表 + * @param params + * @returns + */ +export async function getLineList(): Promise> { + const response = await api.get(`${UriBase}/list`); + return response.data; +} diff --git a/src/api/PublishApi.ts b/src/api/PublishApi.ts new file mode 100644 index 0000000..db1f1c3 --- /dev/null +++ b/src/api/PublishApi.ts @@ -0,0 +1,89 @@ +import { api } from 'src/boot/axios'; +import { PageDto, PageQueryDto } from './ApiCommon'; + +const PublishUriBase = '/api/publishedGi'; + +interface Item { + id: number; + name: string; + proto: string; + createdAt: string; + updateAt: string; + creatorId?: number; +} + +export class PagingQueryParams extends PageQueryDto { + name?: string; +} + +/** + * 草稿图发布 + * @param id 草稿id + */ +export function publishDraft(data: { + name: string; + lineId?: number; + draftingId: number; +}) { + return api.post(`${PublishUriBase}/publish`, data); +} + +/** + * 获取发布图形数据列表 + * @param params + * @returns + */ +export async function getDraft(): Promise { + const response = await api.get(`${PublishUriBase}/list`); + return response.data; +} + +/** + * 分页查询 + * @param params + * @returns + */ +export async function pageQuery( + params: PagingQueryParams +): Promise> { + const response = await api.get(`${PublishUriBase}/paging`, { + params: params, + }); + return response.data; +} + +/** + * 删除发布图 + * @param id 草稿id + */ +export function deletePublish(id: number) { + return api.delete(`${PublishUriBase}/${id}`); +} +/** + * 获取发布地图详细信息 + * @param id 发布地图id + */ +export async function getPublishMapInfoById(id: number): Promise { + const response = await api.get(`${PublishUriBase}/${id}`); + return response.data; +} +/** + * 获取已发布的线路地图数据 + */ +export async function getPublishLineNet(): Promise { + const response = await api.get(`${PublishUriBase}/publish/lineNetwork/info`); + return response.data; +} + +/** + * 获取发布地图详细信息 + * @param id 发布地图线路ID + * @param type 发布地图线路类型 + */ +export async function getPublishMapInfoByLineId( + lineId: number, + type: string +): Promise { + const response = await api.get(`${PublishUriBase}/${type}/${lineId}`); + return response.data; +} diff --git a/src/api/UserApi.ts b/src/api/UserApi.ts new file mode 100644 index 0000000..085fe3f --- /dev/null +++ b/src/api/UserApi.ts @@ -0,0 +1,77 @@ +import { api } from 'src/boot/axios'; +import { PageDto, PageQueryDto } from './ApiCommon'; +import { Md5 } from 'ts-md5'; + +const UserUriBase = '/api/user'; + +interface RegisterInfo { + name: string; + mobile: string; + password: string; +} + +interface User { + id: string; + name: string; + mobile: string; + password: string; + registerTime: string; +} + +const PasswordSult = '4a6d74126bfd06d69406fcccb7e7d5d9'; // 密码加盐 +function encryptPassword(password: string): string { + const md5 = new Md5(); + return md5.appendStr(`${password}${PasswordSult}`).end() as string; +} + +/** + * 用户注册 + * @param info + * @returns + */ +export async function register(info: RegisterInfo): Promise { + const response = await api.post(`${UserUriBase}/register`, { + ...info, + password: encryptPassword(info.password), + }); + return response.data as User; +} + +interface LoginInfo { + account: string; + password: string; +} + +/** + * 用户登录 + * @param loginInfo + * @returns + */ +export async function login(loginInfo: LoginInfo): Promise { + const info = { ...loginInfo, password: encryptPassword(loginInfo.password) }; + const response = await api.post(`${UserUriBase}/login`, info); + return response.data; +} + +export class PagingQueryParams extends PageQueryDto { + name?: string; + roleId?: number; +} + +/** + * 分页查询用户信息 + * @param params + * @returns + */ +export async function pageQuery( + params: PagingQueryParams +): Promise> { + const response = await api.get(`${UserUriBase}/paging`, { + params: params, + }); + return response.data; +} + +export function distributeRole(query: { userId: number; roleIds: number[] }) { + return api.post('/api/role/distribute', query); +} diff --git a/src/assets/quasar-logo-vertical.svg b/src/assets/quasar-logo-vertical.svg new file mode 100644 index 0000000..8210831 --- /dev/null +++ b/src/assets/quasar-logo-vertical.svg @@ -0,0 +1,15 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/boot/.gitkeep b/src/boot/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/boot/@pixi/graphics-extras.ts b/src/boot/@pixi/graphics-extras.ts new file mode 100644 index 0000000..4a70eb8 --- /dev/null +++ b/src/boot/@pixi/graphics-extras.ts @@ -0,0 +1,7 @@ +import { boot } from 'quasar/wrappers'; +import * as GraphicsExtras from '@pixi/graphics-extras'; +// "async" is optional; +// more info on params: https://v2.quasar.dev/quasar-cli/boot-files +export default boot(async (/* { app, router, ... } */) => { + GraphicsExtras; +}); diff --git a/src/boot/axios.ts b/src/boot/axios.ts new file mode 100644 index 0000000..3fe93a6 --- /dev/null +++ b/src/boot/axios.ts @@ -0,0 +1,111 @@ +import axios, { AxiosInstance } from 'axios'; +import { AxiosError } from 'axios'; +import { Dialog } from 'quasar'; +import { boot } from 'quasar/wrappers'; +import { getJwtToken } from 'src/configs/TokenManage'; +import { getHttpBase } from 'src/configs/UrlManage'; + +declare module '@vue/runtime-core' { + interface ComponentCustomProperties { + $axios: AxiosInstance; + } +} + +interface ErrorData { + status: number; + title: string; + detail: string; + code: number; +} + +export class ApiError { + origin: AxiosError; + /** + * 业务错误代码 + */ + code: number; + /** + * 错误信息 + */ + title: string; + /** + * 相关问题描述 + */ + detail?: string; + constructor(origin: AxiosError) { + this.origin = origin; + const response = origin.response; + if (response) { + const err = response.data as ErrorData; + this.code = err.code; + this.title = err.title; + this.detail = err.detail; + } else { + this.code = origin.status || -1; + this.title = origin.message; + } + } + + static from(err: AxiosError): ApiError { + return new ApiError(err); + } + + /** + * 是否认证失败(登录过期) + * @returns + */ + isAuthError(): boolean { + return this.origin.response?.status === 401; + } +} + +// Be careful when using SSR for cross-request state pollution +// due to creating a Singleton instance here; +// If any client changes this (global) instance, it might be a +// good idea to move this instance creation inside of the +// "export default () => {}" function below (which runs individually +// for each client) +const api = axios.create({ baseURL: getHttpBase() }); + +export default boot(({ app, router }) => { + // for use inside Vue files (Options API) through this.$axios and this.$api + + // 拦截请求,添加 + api.interceptors.request.use( + (config) => { + config.headers.Authorization = getJwtToken(); + return config; + }, + (err: AxiosError) => { + return Promise.reject(ApiError.from(err)); + } + ); + + api.interceptors.response.use( + (response) => { + return response; + }, + (err) => { + if (err.response && err.response.status === 401) { + Dialog.create({ + title: '认证失败', + message: '认证失败或登录超时,请重新登录', + persistent: true, + }).onOk(() => { + router.push({ name: 'login' }); + }); + } + return Promise.reject(ApiError.from(err)); + } + ); + + app.config.globalProperties.$axios = axios; + // ^ ^ ^ this will allow you to use this.$axios (for Vue Options API form) + // so you won't necessarily have to import axios in each vue file + + app.config.globalProperties.$api = api; + // ^ ^ ^ this will allow you to use this.$api (for Vue Options API form) + // so you can easily perform requests against your app's API +}); + +export { api }; diff --git a/src/components/SysMenu.vue b/src/components/SysMenu.vue new file mode 100644 index 0000000..cd3d17e --- /dev/null +++ b/src/components/SysMenu.vue @@ -0,0 +1,85 @@ + + + diff --git a/src/components/draw-app/DrawProperties.vue b/src/components/draw-app/DrawProperties.vue new file mode 100644 index 0000000..31f4a2b --- /dev/null +++ b/src/components/draw-app/DrawProperties.vue @@ -0,0 +1,133 @@ + + + diff --git a/src/components/draw-app/properties/AxleCountingProperty.vue b/src/components/draw-app/properties/AxleCountingProperty.vue new file mode 100644 index 0000000..c503ea4 --- /dev/null +++ b/src/components/draw-app/properties/AxleCountingProperty.vue @@ -0,0 +1,164 @@ + + + diff --git a/src/components/draw-app/properties/CanvasProperty.vue b/src/components/draw-app/properties/CanvasProperty.vue new file mode 100644 index 0000000..e5d4f11 --- /dev/null +++ b/src/components/draw-app/properties/CanvasProperty.vue @@ -0,0 +1,80 @@ + + + diff --git a/src/components/draw-app/properties/IscsFanProperty.vue b/src/components/draw-app/properties/IscsFanProperty.vue new file mode 100644 index 0000000..95e1d3d --- /dev/null +++ b/src/components/draw-app/properties/IscsFanProperty.vue @@ -0,0 +1,42 @@ + + + diff --git a/src/components/draw-app/properties/LinkProperty.vue b/src/components/draw-app/properties/LinkProperty.vue new file mode 100644 index 0000000..e6d9b89 --- /dev/null +++ b/src/components/draw-app/properties/LinkProperty.vue @@ -0,0 +1,96 @@ + + + diff --git a/src/components/draw-app/properties/PathLineProperty.vue b/src/components/draw-app/properties/PathLineProperty.vue new file mode 100644 index 0000000..75c6c5e --- /dev/null +++ b/src/components/draw-app/properties/PathLineProperty.vue @@ -0,0 +1,91 @@ + + diff --git a/src/components/draw-app/properties/PlatformProperty.vue b/src/components/draw-app/properties/PlatformProperty.vue new file mode 100644 index 0000000..dd085c6 --- /dev/null +++ b/src/components/draw-app/properties/PlatformProperty.vue @@ -0,0 +1,75 @@ + + + diff --git a/src/components/draw-app/properties/RectProperty.vue b/src/components/draw-app/properties/RectProperty.vue new file mode 100644 index 0000000..d1ec7a3 --- /dev/null +++ b/src/components/draw-app/properties/RectProperty.vue @@ -0,0 +1,100 @@ + + + diff --git a/src/components/draw-app/properties/RunLineProperty.vue b/src/components/draw-app/properties/RunLineProperty.vue new file mode 100644 index 0000000..7183905 --- /dev/null +++ b/src/components/draw-app/properties/RunLineProperty.vue @@ -0,0 +1,189 @@ + + + diff --git a/src/components/draw-app/properties/SectionProperty.vue b/src/components/draw-app/properties/SectionProperty.vue new file mode 100644 index 0000000..12695da --- /dev/null +++ b/src/components/draw-app/properties/SectionProperty.vue @@ -0,0 +1,132 @@ + + + diff --git a/src/components/draw-app/properties/SeparatorProperty.vue b/src/components/draw-app/properties/SeparatorProperty.vue new file mode 100644 index 0000000..f5434d9 --- /dev/null +++ b/src/components/draw-app/properties/SeparatorProperty.vue @@ -0,0 +1,57 @@ + + + diff --git a/src/components/draw-app/properties/SignalProperty.vue b/src/components/draw-app/properties/SignalProperty.vue new file mode 100644 index 0000000..d3bf4e4 --- /dev/null +++ b/src/components/draw-app/properties/SignalProperty.vue @@ -0,0 +1,85 @@ + + + diff --git a/src/components/draw-app/properties/StationLineProperty.vue b/src/components/draw-app/properties/StationLineProperty.vue new file mode 100644 index 0000000..004d3dc --- /dev/null +++ b/src/components/draw-app/properties/StationLineProperty.vue @@ -0,0 +1,87 @@ + + + diff --git a/src/components/draw-app/properties/StationProperty.vue b/src/components/draw-app/properties/StationProperty.vue new file mode 100644 index 0000000..8742bd1 --- /dev/null +++ b/src/components/draw-app/properties/StationProperty.vue @@ -0,0 +1,127 @@ + + + diff --git a/src/components/draw-app/properties/TrainProperty.vue b/src/components/draw-app/properties/TrainProperty.vue new file mode 100644 index 0000000..e47f4ee --- /dev/null +++ b/src/components/draw-app/properties/TrainProperty.vue @@ -0,0 +1,84 @@ + + + diff --git a/src/components/draw-app/properties/TrainWindowProperty.vue b/src/components/draw-app/properties/TrainWindowProperty.vue new file mode 100644 index 0000000..9ba3067 --- /dev/null +++ b/src/components/draw-app/properties/TrainWindowProperty.vue @@ -0,0 +1,86 @@ + + + diff --git a/src/components/draw-app/properties/TurnoutProperty.vue b/src/components/draw-app/properties/TurnoutProperty.vue new file mode 100644 index 0000000..2944975 --- /dev/null +++ b/src/components/draw-app/properties/TurnoutProperty.vue @@ -0,0 +1,149 @@ + + + diff --git a/src/components/draw-app/templates/LinkTemplate.vue b/src/components/draw-app/templates/LinkTemplate.vue new file mode 100644 index 0000000..a6b82a1 --- /dev/null +++ b/src/components/draw-app/templates/LinkTemplate.vue @@ -0,0 +1,96 @@ + + + diff --git a/src/components/draw-app/templates/PlatformTemplate.vue b/src/components/draw-app/templates/PlatformTemplate.vue new file mode 100644 index 0000000..75c2ee2 --- /dev/null +++ b/src/components/draw-app/templates/PlatformTemplate.vue @@ -0,0 +1,76 @@ + + + diff --git a/src/components/draw-app/templates/RectTemplate.vue b/src/components/draw-app/templates/RectTemplate.vue new file mode 100644 index 0000000..75c2ee2 --- /dev/null +++ b/src/components/draw-app/templates/RectTemplate.vue @@ -0,0 +1,76 @@ + + + diff --git a/src/components/draw-app/templates/StationTemplate.vue b/src/components/draw-app/templates/StationTemplate.vue new file mode 100644 index 0000000..fe433bf --- /dev/null +++ b/src/components/draw-app/templates/StationTemplate.vue @@ -0,0 +1,70 @@ + + + diff --git a/src/components/draw-app/templates/TrainTemplate.vue b/src/components/draw-app/templates/TrainTemplate.vue new file mode 100644 index 0000000..5ecec59 --- /dev/null +++ b/src/components/draw-app/templates/TrainTemplate.vue @@ -0,0 +1,51 @@ + + + diff --git a/src/configs/TokenManage.ts b/src/configs/TokenManage.ts new file mode 100644 index 0000000..11dddf9 --- /dev/null +++ b/src/configs/TokenManage.ts @@ -0,0 +1,13 @@ +const JwtTokenKey = 'jwttoken'; + +export function saveJwtToken(token: string) { + sessionStorage.setItem(JwtTokenKey, `Bearer ${token}`); +} + +export function getJwtToken(): string | null { + return sessionStorage.getItem(JwtTokenKey); +} + +export function clearJwtToken(): void { + sessionStorage.removeItem(JwtTokenKey); +} diff --git a/src/configs/UrlManage.ts b/src/configs/UrlManage.ts new file mode 100644 index 0000000..3a4b1e4 --- /dev/null +++ b/src/configs/UrlManage.ts @@ -0,0 +1,15 @@ +function getHost(): string { + // return '192.168.3.7:9081'; + // return '192.168.3.47:9081'; + // return '192.168.3.37:9081'; + // return '192.168.3.15:9081'; + return '192.168.3.233:9081'; +} + +export function getHttpBase() { + return `http://${getHost()}`; +} + +export function getWebsocketUrl() { + return `ws://${getHost()}/ws-default`; +} diff --git a/src/css/app.scss b/src/css/app.scss new file mode 100644 index 0000000..ecac98f --- /dev/null +++ b/src/css/app.scss @@ -0,0 +1 @@ +// app global css in SCSS form diff --git a/src/css/quasar.variables.scss b/src/css/quasar.variables.scss new file mode 100644 index 0000000..3996ce1 --- /dev/null +++ b/src/css/quasar.variables.scss @@ -0,0 +1,25 @@ +// Quasar SCSS (& Sass) Variables +// -------------------------------------------------- +// To customize the look and feel of this app, you can override +// the Sass/SCSS variables found in Quasar's source Sass/SCSS files. + +// Check documentation for full list of Quasar variables + +// Your own variables (that are declared here) and Quasar's own +// ones will be available out of the box in your .vue/.scss/.sass files + +// It's highly recommended to change the default colors +// to match your app's branding. +// Tip: Use the "Theme Builder" on Quasar's documentation website. + +$primary : #1976D2; +$secondary : #26A69A; +$accent : #9C27B0; + +$dark : #1D1D1D; +$dark-page : #121212; + +$positive : #21BA45; +$negative : #C10015; +$info : #31CCEC; +$warning : #F2C037; diff --git a/src/drawApp/graphics/AxleCountingInteraction.ts b/src/drawApp/graphics/AxleCountingInteraction.ts new file mode 100644 index 0000000..ed80bfd --- /dev/null +++ b/src/drawApp/graphics/AxleCountingInteraction.ts @@ -0,0 +1,56 @@ +import * as pb_1 from 'google-protobuf'; +import { + AxleCounting, + IAxleCountingData, +} from 'src/graphics/axleCounting/AxleCounting'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; +import { KilometerSystem } from 'src/graphics/signal/Signal'; + +export class AxleCountingData + extends GraphicDataBase + implements IAxleCountingData +{ + constructor(data?: graphicData.AxleCounting) { + let axleCounting; + if (!data) { + axleCounting = new graphicData.AxleCounting({ + common: GraphicDataBase.defaultCommonInfo(AxleCounting.Type), + }); + } else { + axleCounting = data; + } + super(axleCounting); + } + + public get data(): graphicData.AxleCounting { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get kilometerSystem(): KilometerSystem { + return this.data.kilometerSystem; + } + set kilometerSystem(v: KilometerSystem) { + this.data.kilometerSystem = new graphicData.KilometerSystem(v); + } + get axleCountingRef(): graphicData.RelatedRef[] { + return this.data.axleCountingRef; + } + set axleCountingRef(points: graphicData.RelatedRef[]) { + this.data.axleCountingRef = points; + } + clone(): AxleCountingData { + return new AxleCountingData(this.data.cloneMessage()); + } + copyFrom(data: AxleCountingData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: AxleCountingData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/GraphicDataBase.ts b/src/drawApp/graphics/GraphicDataBase.ts new file mode 100644 index 0000000..225b259 --- /dev/null +++ b/src/drawApp/graphics/GraphicDataBase.ts @@ -0,0 +1,153 @@ +import * as pb_1 from 'google-protobuf'; +import { + ChildTransform, + GraphicData, + GraphicState, + GraphicTransform, + IChildTransform, + IGraphicTransform, +} from 'src/jl-graphic'; +// import { toStorageTransform } from '..'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { IPointData, Point } from 'pixi.js'; +import { state } from 'src/protos/device_status'; + +export interface ICommonInfo { + id: string; + graphicType: string; + transform: IGraphicTransform; + childTransforms: IChildTransform[]; +} +export function fromStoragePoint(p: graphicData.Point): Point { + return new Point(p.x, p.y); +} + +export function toStoragePoint(p: IPointData): graphicData.Point { + return new graphicData.Point({ x: p.x, y: p.y }); +} +export function fromStorageTransfrom( + transfrom: graphicData.Transform +): GraphicTransform { + return new GraphicTransform( + fromStoragePoint(transfrom.position), + fromStoragePoint(transfrom.scale), + transfrom.rotation, + fromStoragePoint(transfrom.skew) + ); +} + +export function toStorageTransform( + transform: GraphicTransform +): graphicData.Transform { + return new graphicData.Transform({ + position: toStoragePoint(transform.position), + scale: toStoragePoint(transform.scale), + rotation: transform.rotation, + skew: toStoragePoint(transform.skew), + }); +} + +export interface IProtoGraphicData extends pb_1.Message { + common: ICommonInfo; + code: string; +} + +export abstract class GraphicDataBase implements GraphicData { + _data: IProtoGraphicData; + constructor(data: IProtoGraphicData) { + this._data = data; + } + + static defaultCommonInfo(graphicType: string): graphicData.CommonInfo { + return new graphicData.CommonInfo({ + id: '', + graphicType: graphicType, + transform: new graphicData.Transform({ + position: new graphicData.Point({ x: 0, y: 0 }), + scale: new graphicData.Point({ x: 1, y: 1 }), + rotation: 0, + skew: new graphicData.Point({ x: 0, y: 0 }), + }), + childTransforms: [], + }); + } + + getData(): D { + return this._data as D; + } + + get id(): string { + return this._data.common.id; + } + set id(v: string) { + this._data.common.id = v; + } + get graphicType(): string { + return this._data.common.graphicType; + } + set graphicType(v: string) { + this._data.common.graphicType = v; + } + get transform(): GraphicTransform { + return GraphicTransform.from(this._data.common.transform); + } + set transform(v: GraphicTransform) { + this._data.common.transform = toStorageTransform(v); + } + get childTransforms(): ChildTransform[] | undefined { + const cts: ChildTransform[] = []; + if (this._data.common.childTransforms) { + this._data.common.childTransforms.forEach((ct) => { + cts.push(ChildTransform.from(ct)); + }); + } + return cts; + } + set childTransforms(v: ChildTransform[] | undefined) { + if (v) { + const cts: graphicData.ChildTransform[] = []; + v.forEach((ct) => + cts.push( + new graphicData.ChildTransform({ + ...ct, + transform: toStorageTransform(ct.transform), + }) + ) + ); + this._data.common.childTransforms = cts; + } else { + this._data.common.childTransforms = []; + } + } + + clone(): GraphicData { + throw new Error('Method not implemented.'); + } + copyFrom(gd: GraphicDataBase): void { + pb_1.Message.copyInto(gd._data, this._data); + } + eq(other: GraphicDataBase): boolean { + return pb_1.Message.equals(this._data, other._data); + } +} + +export abstract class GraphicStateBase implements GraphicState { + _graphicType: string; + _state: pb_1.Message; + constructor(state: pb_1.Message, graphicType: string) { + this._state = state; + this._graphicType = graphicType; + } + abstract get code(): string; + abstract copyFrom(data: GraphicState): void; + abstract eq(data: GraphicState): boolean; + getState(): S { + return this._state as S; + } + get graphicType(): string { + return this._graphicType; + } + clone(): GraphicState { + throw new Error('Method not implemented.'); + } +} diff --git a/src/drawApp/graphics/IscsFanInteraction.ts b/src/drawApp/graphics/IscsFanInteraction.ts new file mode 100644 index 0000000..80a8e07 --- /dev/null +++ b/src/drawApp/graphics/IscsFanInteraction.ts @@ -0,0 +1,38 @@ +import * as pb_1 from 'google-protobuf'; +import { IIscsFanData, IscsFan } from 'src/graphics/iscs-fan/IscsFan'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class IscsFanData extends GraphicDataBase implements IIscsFanData { + constructor(data?: graphicData.IscsFan) { + let fan; + if (data) { + fan = data; + } else { + fan = new graphicData.IscsFan({ + common: GraphicDataBase.defaultCommonInfo(IscsFan.Type), + }); + } + super(fan); + } + + public get data(): graphicData.IscsFan { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + clone(): IscsFanData { + return new IscsFanData(this.data.cloneMessage()); + } + copyFrom(data: IscsFanData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: IscsFanData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/LinkInteraction.ts b/src/drawApp/graphics/LinkInteraction.ts new file mode 100644 index 0000000..cd28295 --- /dev/null +++ b/src/drawApp/graphics/LinkInteraction.ts @@ -0,0 +1,182 @@ +import * as pb_1 from 'google-protobuf'; +import { IPointData, DisplayObject, FederatedMouseEvent } from 'pixi.js'; +import { ILinkData, Link } from 'src/graphics/link/Link'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { + GraphicApp, + GraphicInteractionPlugin, + JlGraphic, +} from 'src/jl-graphic'; +import { + addWayPoint, + clearWayPoint, + getWaypointRangeIndex, + PolylineEditPlugin, + removeLineWayPoint, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; + +export class LinkData extends GraphicDataBase implements ILinkData { + constructor(data?: graphicData.Link) { + let link; + if (!data) { + link = new graphicData.Link({ + common: GraphicDataBase.defaultCommonInfo(Link.Type), + }); + } else { + link = data; + } + super(link); + } + + public get data(): graphicData.Link { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get curve(): boolean { + return this.data.curve; + } + set curve(v: boolean) { + this.data.curve = v; + } + get curveNumber(): number { + return this.data.curve ? 1 : 0; + } + set curveNumber(v: number) { + this.data.curve = v === 0 ? false : true; + } + get segmentsCount(): number { + return this.data.segmentsCount; + } + set segmentsCount(v: number) { + this.data.segmentsCount = v; + } + get points(): IPointData[] { + return this.data.points; + } + set points(points: IPointData[]) { + this.data.points = points.map( + (p) => new graphicData.Point({ x: p.x, y: p.y }) + ); + } + get lineWidth(): number { + return this.data.lineWidth; + } + set lineWidth(v: number) { + this.data.lineWidth = v; + } + get lineColor(): string { + return this.data.lineColor; + } + set lineColor(v: string) { + this.data.lineColor = v; + } + clone(): LinkData { + return new LinkData(this.data.cloneMessage()); + } + copyFrom(data: LinkData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: LinkData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export const addWaypointConfig: MenuItemOptions = { + name: '添加路径点', +}; +export const removeWaypointConfig: MenuItemOptions = { + name: '移除路径点', +}; +export const clearWaypointsConfig: MenuItemOptions = { + name: '清除所有路径点', +}; + +const LinkEditMenu: ContextMenu = ContextMenu.init({ + name: '轨道编辑菜单', + groups: [ + { + items: [addWaypointConfig, clearWaypointsConfig], + }, + ], +}); +const EpEditMenu: ContextMenu = ContextMenu.init({ + name: '轨道编辑菜单2', + groups: [ + { + items: [removeWaypointConfig, clearWaypointsConfig], + }, + ], +}); + +export class DrawLinkPlugin extends GraphicInteractionPlugin { + static Name = 'link_draw_right_menu'; + constructor(app: GraphicApp) { + super(DrawLinkPlugin.Name, app); + app.registerMenu(LinkEditMenu); + app.registerMenu(EpEditMenu); + } + static init(app: GraphicApp) { + return new DrawLinkPlugin(app); + } + filter(...grahpics: JlGraphic[]): Link[] | undefined { + return grahpics.filter((g) => g.type === Link.Type).map((g) => g as Link); + } + bind(g: Link): void { + g.on('_rightclick', this.onContextMenu, this); + g.on('selected', this.onSelected, this); + } + + unbind(g: Link): void { + g.off('_rightclick', this.onContextMenu, this); + g.off('selected', this.onSelected, this); + } + + onSelected(g: DisplayObject) { + const polylineEditPlugin = g.assistantAppendMap.get( + PolylineEditPlugin.Name + ) as PolylineEditPlugin; + const link = g.getGraphic() as Link; + polylineEditPlugin.editedPoints.forEach((ep, index) => { + ep.on('rightclick', (e: FederatedMouseEvent) => { + this.app.registerMenu(EpEditMenu); + removeWaypointConfig.handler = () => { + removeLineWayPoint(link, index); + }; + clearWaypointsConfig.handler = () => { + clearWayPoint(link, false); + }; + EpEditMenu.open(e.global); + }); + }); + } + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const link = target.getGraphic() as Link; + this.app.updateSelected(link); + + addWaypointConfig.handler = () => { + const linePoints = link.linePoints; + const p = link.screenToLocalPoint(e.global); + const { start, end } = getWaypointRangeIndex( + linePoints, + false, + p, + link.datas.lineWidth + ); + addWayPoint(link, false, start, end, p); + }; + clearWaypointsConfig.handler = () => { + clearWayPoint(link, false); + }; + LinkEditMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/PathLineInteraction.ts b/src/drawApp/graphics/PathLineInteraction.ts new file mode 100644 index 0000000..dc34cd2 --- /dev/null +++ b/src/drawApp/graphics/PathLineInteraction.ts @@ -0,0 +1,70 @@ +import * as pb_1 from 'google-protobuf'; +import { IPointData } from 'pixi.js'; +import { + IPathLineData, + PathLine, + KilometerPoint, +} from 'src/graphics/pathLine/PathLine'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class PathLineData extends GraphicDataBase implements IPathLineData { + constructor(data?: graphicData.PathLine) { + let pathLine; + if (!data) { + pathLine = new graphicData.PathLine({ + common: GraphicDataBase.defaultCommonInfo(PathLine.Type), + }); + } else { + pathLine = data; + } + super(pathLine); + } + + public get data(): graphicData.PathLine { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get points(): IPointData[] { + return this.data.points; + } + set points(points: IPointData[]) { + this.data.points = points.map( + (p) => new graphicData.Point({ x: p.x, y: p.y }) + ); + } + get isUp(): boolean { + return this.data.isUp; + } + set isUp(v: boolean) { + this.data.isUp = v; + } + get kilometerPoints(): KilometerPoint[] { + return this.data.kilometerPoints; + } + set kilometerPoints(kilometerPoints: KilometerPoint[]) { + this.data.kilometerPoints = kilometerPoints.map( + (p) => + new graphicData.KilometerPoint({ + point: new graphicData.Point({ x: p.point.x, y: p.point.y }), + kilometer: p.kilometer, + stName: p.stName, + }) + ); + } + clone(): PathLineData { + return new PathLineData(this.data.cloneMessage()); + } + copyFrom(data: PathLineData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: PathLineData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/PlatformInteraction.ts b/src/drawApp/graphics/PlatformInteraction.ts new file mode 100644 index 0000000..c74247a --- /dev/null +++ b/src/drawApp/graphics/PlatformInteraction.ts @@ -0,0 +1,307 @@ +import * as pb_1 from 'google-protobuf'; +import { + IPlatformData, + IPlatformState, + Platform, +} from 'src/graphics/platform/Platform'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase'; +import { state } from 'src/protos/device_status'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { + GraphicApp, + GraphicInteractionPlugin, + JlGraphic, +} from 'src/jl-graphic'; +import { DisplayObject, FederatedMouseEvent } from 'pixi.js'; + +export class PlatformData extends GraphicDataBase implements IPlatformData { + constructor(data?: graphicData.Platform) { + let platform; + if (!data) { + platform = new graphicData.Platform({ + common: GraphicDataBase.defaultCommonInfo(Platform.Type), + }); + } else { + platform = data; + } + super(platform); + } + + public get data(): graphicData.Platform { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get hasdoor(): boolean { + return this.data.hasdoor; + } + set hasdoor(v: boolean) { + this.data.hasdoor = v; + } + get direction(): string { + return this.data.direction; + } + set direction(v: string) { + this.data.direction = v; + } + + clone(): PlatformData { + return new PlatformData(this.data.cloneMessage()); + } + copyFrom(data: PlatformData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: PlatformData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export class PlatformState extends GraphicStateBase implements IPlatformState { + constructor(proto?: state.Platform) { + let states; + if (proto) { + states = proto; + } else { + states = new state.Platform(); + } + super(states, Platform.Type); + } + + get emergstop(): boolean { + return this.states.emergstop; + } + set emergstop(v: boolean) { + this.states.emergstop = v; + } + get trainberth(): boolean { + return this.states.trainberth; + } + set trainberth(v: boolean) { + this.states.trainberth = v; + } + get close(): boolean { + return this.states.close; + } + set close(v: boolean) { + this.states.close = v; + } + get upHold(): boolean { + return this.states.upHold; + } + set upHold(v: boolean) { + this.states.upHold = v; + } + get downHold(): boolean { + return this.states.downHold; + } + set downHold(v: boolean) { + this.states.downHold = v; + } + get upOccHold(): boolean { + return this.states.upOccHold; + } + set upOccHold(v: boolean) { + this.states.upOccHold = v; + } + get downOccHold(): boolean { + return this.states.downOccHold; + } + set downOccHold(v: boolean) { + this.states.downOccHold = v; + } + get psdOpen(): boolean { + return this.states.psdOpen; + } + set psdOpen(v: boolean) { + this.states.psdOpen = v; + } + get psdCut(): boolean { + return this.states.psdCut; + } + set psdCut(v: boolean) { + this.states.psdCut = v; + } + + get upSkipstop(): boolean { + return this.states.upSkipstop; + } + set upSkipstop(v: boolean) { + this.states.upSkipstop = v; + } + get downSkipstop(): boolean { + return this.states.downSkipstop; + } + set downSkipstop(v: boolean) { + this.states.downSkipstop = v; + } + get upTrainSkipstop(): boolean { + return this.states.upTrainSkipstop; + } + set upTrainSkipstop(v: boolean) { + this.states.upTrainSkipstop = v; + } + get downTrainSkipstop(): boolean { + return this.states.downTrainSkipstop; + } + set downTrainSkipstop(v: boolean) { + this.states.downTrainSkipstop = v; + } + get nextSectionRunTime(): number { + return this.states.nextSectionRunTime; + } + set nextSectionRunTime(v: number) { + this.states.nextSectionRunTime = v; + } + get nextSectionRunLevel(): number { + return this.states.nextSectionRunLevel; + } + set nextSectionRunLevel(v: number) { + this.states.nextSectionRunLevel = v; + } + get stopTime(): number { + return this.states.stopTime; + } + set stopTime(v: number) { + this.states.stopTime = v; + } + get states(): state.Platform { + return this.getState(); + } + clone(): PlatformState { + return new PlatformState(this.states.cloneMessage()); + } +} + +const holdConfig: MenuItemOptions = { + name: '扣车', +}; +const removeHoldrConfig: MenuItemOptions = { + name: '取消扣车', +}; +const batchHoldConfig: MenuItemOptions = { + name: '批量扣车', +}; +const removeBatchHoldConfig: MenuItemOptions = { + name: '批量取消扣车', +}; +const earlyDepartureConfig: MenuItemOptions = { + name: '提前发车', +}; +const skipStopConfig: MenuItemOptions = { + name: '设置跳停', +}; +const removeSkipStopConfig: MenuItemOptions = { + name: '取消跳停', +}; +const dockTimeConfig: MenuItemOptions = { + name: '设置停站时间', +}; +const operatingLevelConfig: MenuItemOptions = { + name: '设置运行等级', +}; +const numberOfRegionalTrainsConfig: MenuItemOptions = { + name: '区间列车数量限制', +}; +const removeNumberOfRegionalTrainsConfig: MenuItemOptions = { + name: '取消区间列车数量限制', +}; +const platformMessadeConfig: MenuItemOptions = { + name: '站台详细信息', +}; + +const PlatformOperateMenu: ContextMenu = ContextMenu.init({ + name: '站台操作菜单', + groups: [ + { + items: [ + holdConfig, + removeHoldrConfig, + skipStopConfig, + removeSkipStopConfig, + ], + }, + ], +}); + +const dispatchPlatformOperateMenu: ContextMenu = ContextMenu.init({ + name: '调度仿真站台操作菜单', + groups: [ + { + items: [ + holdConfig, + removeHoldrConfig, + batchHoldConfig, + removeBatchHoldConfig, + earlyDepartureConfig, + skipStopConfig, + removeSkipStopConfig, + dockTimeConfig, + operatingLevelConfig, + numberOfRegionalTrainsConfig, + removeNumberOfRegionalTrainsConfig, + platformMessadeConfig, + ], + }, + ], +}); + +export class PlatformOperateInteraction extends GraphicInteractionPlugin { + static Name = 'platform_operate_menu'; + constructor(app: GraphicApp) { + super(PlatformOperateInteraction.Name, app); + app.registerMenu(PlatformOperateMenu); + } + static init(app: GraphicApp) { + return new PlatformOperateInteraction(app); + } + filter(...grahpics: JlGraphic[]): Platform[] | undefined { + return grahpics + .filter((g) => g.type === Platform.Type) + .map((g) => g as Platform); + } + bind(g: Platform): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.selectable = true; + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: Platform): void { + g.selectable = false; + g.eventMode = 'none'; + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const platform = target.getGraphic() as Platform; + this.app.updateSelected(platform); + holdConfig.handler = () => { + platform.states.upHold = true; + platform.states.upOccHold = true; + platform.doRepaint(); + }; + removeHoldrConfig.handler = () => { + platform.states.upHold = false; + platform.states.upOccHold = false; + platform.doRepaint(); + }; + skipStopConfig.handler = () => { + platform.states.upSkipstop = true; + platform.doRepaint(); + }; + removeSkipStopConfig.handler = () => { + platform.states.upSkipstop = false; + platform.doRepaint(); + }; + + PlatformOperateMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/PolygonInteraction.ts b/src/drawApp/graphics/PolygonInteraction.ts new file mode 100644 index 0000000..034fe9b --- /dev/null +++ b/src/drawApp/graphics/PolygonInteraction.ts @@ -0,0 +1,197 @@ +import * as pb_1 from 'google-protobuf'; +import { IPolygonData, Polygon } from 'src/graphics/polygon/Polygon'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; +import { DisplayObject, FederatedMouseEvent, IPointData } from 'pixi.js'; +import { + GraphicApp, + GraphicInteractionPlugin, + JlGraphic, +} from 'src/jl-graphic'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { + PolylineEditPlugin, + clearWayPoint, + removeLineWayPoint, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import { + addPolygonSegmentingPoint, + getWayLineIndex, +} from 'src/graphics/polygon/PolygonUtils'; + +export class PolygonData extends GraphicDataBase implements IPolygonData { + constructor(data?: graphicData.Polygon) { + let polygon; + if (!data) { + polygon = new graphicData.Polygon({ + common: GraphicDataBase.defaultCommonInfo(Polygon.Type), + }); + } else { + polygon = data; + } + super(polygon); + } + + public get data(): graphicData.Polygon { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get lineWidth(): number { + return this.data.lineWidth; + } + set lineWidth(v: number) { + this.data.lineWidth = v; + } + get lineColor(): string { + return this.data.lineColor; + } + set lineColor(v: string) { + this.data.lineColor = v; + } + get points(): IPointData[] { + return this.data.points; + } + set points(points: IPointData[]) { + this.data.points = points.map( + (p) => new graphicData.Point({ x: p.x, y: p.y }) + ); + } + + clone(): PolygonData { + return new PolygonData(this.data.cloneMessage()); + } + copyFrom(data: PolygonData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: PolygonData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +/** + * polygon编辑菜单配置 + */ + +const threeSegmentingConfig: MenuItemOptions = { + name: '3等分', +}; +const foreSegmentingConfig: MenuItemOptions = { + name: '4等分', +}; +const fiveSegmentingConfig: MenuItemOptions = { + name: '5等分', +}; + +const chooseSegmentingConfig: MenuItemOptions = { + name: '细分', + subMenu: [ + { + name: '内置图形', + items: [ + threeSegmentingConfig, + foreSegmentingConfig, + fiveSegmentingConfig, + ], + }, + ], +}; +const removeWaypointConfig: MenuItemOptions = { + name: '移除路径点', +}; +const clearWaypointsConfig: MenuItemOptions = { + name: '清除所有路径点', +}; +const PolygonEditMenu: ContextMenu = ContextMenu.init({ + name: '多边形边的编辑菜单', + groups: [ + { + items: [chooseSegmentingConfig, clearWaypointsConfig], + }, + ], +}); + +const EpEditMenu: ContextMenu = ContextMenu.init({ + name: '多边形点的编辑菜单', + groups: [ + { + items: [removeWaypointConfig, clearWaypointsConfig], + }, + ], +}); + +export class DrawPolygonPlugin extends GraphicInteractionPlugin { + static Name = 'polygon_draw_right_menu'; + constructor(app: GraphicApp) { + super(DrawPolygonPlugin.Name, app); + app.registerMenu(PolygonEditMenu); + app.registerMenu(EpEditMenu); + } + static init(app: GraphicApp) { + return new DrawPolygonPlugin(app); + } + filter(...grahpics: JlGraphic[]): Polygon[] | undefined { + return grahpics + .filter((g) => g.type === Polygon.Type) + .map((g) => g as Polygon); + } + bind(g: Polygon): void { + g.on('_rightclick', this.onContextMenu, this); + g.on('selected', this.onSelected, this); + } + + unbind(g: Polygon): void { + g.off('_rightclick', this.onContextMenu, this); + g.off('selected', this.onSelected, this); + } + + onSelected(g: DisplayObject) { + const polylineEditPlugin = g.assistantAppendMap.get( + PolylineEditPlugin.Name + ) as PolylineEditPlugin; + const link = g.getGraphic() as Polygon; + polylineEditPlugin.editedPoints.forEach((ep, index) => { + ep.on('rightclick', (e: FederatedMouseEvent) => { + this.app.registerMenu(EpEditMenu); + removeWaypointConfig.handler = () => { + removeLineWayPoint(link, index); + }; + clearWaypointsConfig.handler = () => { + clearWayPoint(link, false); + }; + EpEditMenu.open(e.global); + }); + }); + } + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const polygon = target.getGraphic() as Polygon; + this.app.updateSelected(polygon); + const linePoints = polygon.addOnePoints(); + const p = polygon.screenToLocalPoint(e.global); + const { start, end } = getWayLineIndex(linePoints, p); + + chooseSegmentingConfig.handler = () => { + addPolygonSegmentingPoint(polygon, start, end); + }; + threeSegmentingConfig.handler = () => { + addPolygonSegmentingPoint(polygon, start, end, 3); + }; + foreSegmentingConfig.handler = () => { + addPolygonSegmentingPoint(polygon, start, end, 4); + }; + fiveSegmentingConfig.handler = () => { + addPolygonSegmentingPoint(polygon, start, end, 5); + }; + clearWaypointsConfig.handler = () => { + clearWayPoint(polygon, false); + }; + PolygonEditMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/RectInteraction.ts b/src/drawApp/graphics/RectInteraction.ts new file mode 100644 index 0000000..3ea0c2e --- /dev/null +++ b/src/drawApp/graphics/RectInteraction.ts @@ -0,0 +1,75 @@ +import * as pb_1 from 'google-protobuf'; +import { IPointData } from 'pixi.js'; +import { IRectData, Rect } from 'src/graphics/rect/Rect'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class RectData extends GraphicDataBase implements IRectData { + constructor(data?: graphicData.Rect) { + let rect; + if (!data) { + rect = new graphicData.Rect({ + common: GraphicDataBase.defaultCommonInfo(Rect.Type), + }); + } else { + rect = data; + } + super(rect); + } + + public get data(): graphicData.Rect { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get lineWidth(): number { + return this.data.lineWidth; + } + set lineWidth(v: number) { + this.data.lineWidth = v; + } + get lineColor(): string { + return this.data.lineColor; + } + set lineColor(v: string) { + this.data.lineColor = v; + } + get point(): IPointData { + return this.data.point; + } + set point(point: IPointData) { + this.data.point = new graphicData.Point({ x: point.x, y: point.y }); + } + get width(): number { + return this.data.width; + } + set width(v: number) { + this.data.width = v; + } + get height(): number { + return this.data.height; + } + set height(v: number) { + this.data.height = v; + } + get radius(): number { + return this.data.radius; + } + set radius(v: number) { + this.data.radius = v; + } + clone(): RectData { + return new RectData(this.data.cloneMessage()); + } + copyFrom(data: RectData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: RectData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/RunLineInteraction.ts b/src/drawApp/graphics/RunLineInteraction.ts new file mode 100644 index 0000000..8a457f4 --- /dev/null +++ b/src/drawApp/graphics/RunLineInteraction.ts @@ -0,0 +1,214 @@ +import * as pb_1 from 'google-protobuf'; +import { + IRunLineData, + RunLine, + runLineConsts, +} from 'src/graphics/runLine/RunLine'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; +import { + GraphicInteractionPlugin, + GraphicApp, + JlGraphic, +} from 'src/jl-graphic'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { FederatedMouseEvent, DisplayObject, IPointData } from 'pixi.js'; +import { + addWayPoint, + clearWayPoint, + getWaypointRangeIndex, + PolylineEditPlugin, + removeLineWayPoint, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import { RunLineGraphicHitArea } from 'src/graphics/runLine/RunLineDrawAssistant'; + +export class RunLineData extends GraphicDataBase implements IRunLineData { + constructor(data?: graphicData.RunLine) { + let runLine; + if (!data) { + runLine = new graphicData.RunLine({ + common: GraphicDataBase.defaultCommonInfo(RunLine.Type), + }); + } else { + runLine = data; + } + super(runLine); + } + public get data(): graphicData.RunLine { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get points(): IPointData[] { + return this.data.points; + } + set points(points: IPointData[]) { + this.data.points = points.map( + (p) => new graphicData.Point({ x: p.x, y: p.y }) + ); + } + get nameColor(): string { + return this.data.nameColor; + } + set nameColor(v: string) { + this.data.nameColor = v; + } + get nameBgColor(): string { + return this.data.nameBgColor; + } + set nameBgColor(v: string) { + this.data.nameBgColor = v; + } + get containSta(): string[] { + return this.data.containSta; + } + set containSta(v: string[]) { + this.data.containSta = v; + } + get linkPathLines(): string[] { + return this.data.linkPathLines; + } + set linkPathLines(v: string[]) { + this.data.linkPathLines = v; + } + get lineId(): string { + return this.data.lineId; + } + set lineId(v: string) { + this.data.lineId = v; + } + clone(): RunLineData { + return new RunLineData(this.data.cloneMessage()); + } + copyFrom(data: RunLineData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: RunLineData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export const addWaypointConfig: MenuItemOptions = { + name: '添加路径点', +}; +export const removeWaypointConfig: MenuItemOptions = { + name: '移除路径点', +}; +export const clearWaypointsConfig: MenuItemOptions = { + name: '清除所有路径点', +}; + +const RunLineEditMenu: ContextMenu = ContextMenu.init({ + name: '运行线编辑菜单', + groups: [ + { + items: [addWaypointConfig, clearWaypointsConfig], + }, + ], +}); +const EpEditMenu: ContextMenu = ContextMenu.init({ + name: '运行线编辑菜单2', + groups: [ + { + items: [removeWaypointConfig, clearWaypointsConfig], + }, + ], +}); + +export class DrawRunLinePlugin extends GraphicInteractionPlugin { + static Name = 'runline_draw_right_menu'; + constructor(app: GraphicApp) { + super(DrawRunLinePlugin.Name, app); + app.registerMenu(RunLineEditMenu); + app.registerMenu(EpEditMenu); + } + static init(app: GraphicApp) { + return new DrawRunLinePlugin(app); + } + filter(...grahpics: JlGraphic[]): RunLine[] | undefined { + return grahpics + .filter((g) => g.type === RunLine.Type) + .map((g) => g as RunLine); + } + bind(g: RunLine): void { + g.on('_rightclick', this.onContextMenu, this); + g.on('selected', this.onSelected, this); + } + + unbind(g: RunLine): void { + g.off('_rightclick', this.onContextMenu, this); + g.off('selected', this.onSelected, this); + } + + onSelected(g: DisplayObject) { + const polylineEditPlugin = g.assistantAppendMap.get( + PolylineEditPlugin.Name + ) as PolylineEditPlugin; + const runLine = g.getGraphic() as RunLine; + polylineEditPlugin.editedPoints.forEach((ep, index) => { + ep.on('rightclick', (e: FederatedMouseEvent) => { + this.app.registerMenu(EpEditMenu); + removeWaypointConfig.handler = () => { + removeLineWayPoint(runLine, index); + }; + clearWaypointsConfig.handler = () => { + clearWayPoint(runLine, false); + }; + EpEditMenu.open(e.global); + }); + }); + } + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const runLine = target.getGraphic() as RunLine; + this.app.updateSelected(runLine); + + addWaypointConfig.handler = () => { + const linePoints = runLine.linePoints; + const p = runLine.screenToLocalPoint(e.global); + const { start, end } = getWaypointRangeIndex( + linePoints, + false, + p, + runLineConsts.runLineWidth + ); + addWayPoint(runLine, false, start, end, p); + }; + clearWaypointsConfig.handler = () => { + clearWayPoint(runLine, false); + }; + RunLineEditMenu.open(e.global); + } +} + +export class RunLineOperateInteraction extends GraphicInteractionPlugin { + static Name = 'runLine_operate_menu'; + constructor(app: GraphicApp) { + super(RunLineOperateInteraction.Name, app); + app.registerMenu(EpEditMenu); + } + static init(app: GraphicApp) { + return new RunLineOperateInteraction(app); + } + filter(...grahpics: JlGraphic[]): RunLine[] | undefined { + return grahpics + .filter((g) => g.type === RunLine.Type) + .map((g) => g as RunLine); + } + bind(g: RunLine): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.lineBody.hitArea = new RunLineGraphicHitArea(g); + g.selectable = true; + } + + unbind(g: RunLine): void { + g.selectable = false; + g.eventMode = 'none'; + } +} diff --git a/src/drawApp/graphics/SectionInteraction.ts b/src/drawApp/graphics/SectionInteraction.ts new file mode 100644 index 0000000..b8a8bff --- /dev/null +++ b/src/drawApp/graphics/SectionInteraction.ts @@ -0,0 +1,69 @@ +import * as pb_1 from 'google-protobuf'; +import { GraphicDataBase } from './GraphicDataBase'; +import { ISectionData, Section } from 'src/graphics/section/Section'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { IPointData } from 'pixi.js'; + +export class SectionData extends GraphicDataBase implements ISectionData { + constructor(data?: graphicData.Section) { + let section; + if (!data) { + section = new graphicData.Section({ + common: GraphicDataBase.defaultCommonInfo(Section.Type), + }); + } else { + section = data; + } + super(section); + } + public get data(): graphicData.Section { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get points(): IPointData[] { + return this.data.points; + } + set points(points: IPointData[]) { + this.data.points = points.map( + (p) => new graphicData.Point({ x: p.x, y: p.y }) + ); + } + get paRef(): graphicData.RelatedRef { + return this.data.paRef; + } + set paRef(ref: graphicData.RelatedRef) { + this.data.paRef = ref; + } + get pbRef(): graphicData.RelatedRef { + return this.data.pbRef; + } + set pbRef(ref: graphicData.RelatedRef) { + this.data.pbRef = ref; + } + get sectionType(): graphicData.Section.SectionType { + return this.data.sectionType; + } + set sectionType(type: graphicData.Section.SectionType) { + this.data.sectionType = type; + } + get children(): string[] { + return this.data.children; + } + set children(children: string[]) { + this.data.children = children; + } + clone(): SectionData { + return new SectionData(this.data.cloneMessage()); + } + copyFrom(data: SectionData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: SectionData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/SeparatorInteraction.ts b/src/drawApp/graphics/SeparatorInteraction.ts new file mode 100644 index 0000000..303ca13 --- /dev/null +++ b/src/drawApp/graphics/SeparatorInteraction.ts @@ -0,0 +1,43 @@ +import * as pb_1 from 'google-protobuf'; +import { ISeparatorData, Separator } from 'src/graphics/separator/Separator'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class SeparatorData extends GraphicDataBase implements ISeparatorData { + constructor(data?: graphicData.Separator) { + let separator; + if (!data) { + separator = new graphicData.Separator({ + common: GraphicDataBase.defaultCommonInfo(Separator.Type), + }); + } else { + separator = data; + } + super(separator); + } + + public get data(): graphicData.Separator { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get separatorType(): string { + return this.data.separatorType; + } + set separatorType(v: string) { + this.data.separatorType = v; + } + clone(): SeparatorData { + return new SeparatorData(this.data.cloneMessage()); + } + copyFrom(data: SeparatorData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: SeparatorData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/SignalInteraction.ts b/src/drawApp/graphics/SignalInteraction.ts new file mode 100644 index 0000000..658dede --- /dev/null +++ b/src/drawApp/graphics/SignalInteraction.ts @@ -0,0 +1,369 @@ +import * as pb_1 from 'google-protobuf'; +import { + ISignalData, + Signal, + ISignalState, + KilometerSystem, +} from 'src/graphics/signal/Signal'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase'; +import { + GraphicInteractionPlugin, + GraphicApp, + JlGraphic, +} from 'src/jl-graphic'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { FederatedMouseEvent, DisplayObject } from 'pixi.js'; +import { state } from 'src/protos/device_status'; + +export class SignalData extends GraphicDataBase implements ISignalData { + constructor(data?: graphicData.Signal) { + let signal; + if (!data) { + signal = new graphicData.Signal({ + common: GraphicDataBase.defaultCommonInfo(Signal.Type), + }); + } else { + signal = data; + } + super(signal); + } + public get data(): graphicData.Signal { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get mirror(): boolean { + return this.data.mirror; + } + set mirror(v: boolean) { + this.data.mirror = v; + } + get kilometerSystem(): KilometerSystem { + return this.data.kilometerSystem; + } + set kilometerSystem(v: KilometerSystem) { + this.data.kilometerSystem = new graphicData.KilometerSystem(v); + } + clone(): SignalData { + return new SignalData(this.data.cloneMessage()); + } + copyFrom(data: SignalData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: SignalData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export class SignalState extends GraphicStateBase implements ISignalState { + constructor(proto?: state.Signal) { + let states; + if (proto) { + states = proto; + } else { + states = new state.Signal(); + } + super(states, Signal.Type); + } + get code(): string { + return this.states.id; + } + get redOpen(): boolean { + return this.states.redOpen; + } + set redOpen(v: boolean) { + this.states.redOpen = v; + } + get redFlash(): boolean { + return this.states.redFlash; + } + set redFlash(v: boolean) { + this.states.redFlash = v; + } + get greenOpen(): boolean { + return this.states.greenOpen; + } + set greenOpen(v: boolean) { + this.states.greenOpen = v; + } + get greenFlash(): boolean { + return this.states.greenFlash; + } + set greenFlash(v: boolean) { + this.states.greenFlash = v; + } + get yellowOpen(): boolean { + return this.states.yellowOpen; + } + set yellowOpen(v: boolean) { + this.states.yellowOpen = v; + } + get yellowFlash(): boolean { + return this.states.yellowFlash; + } + set yellowFlash(v: boolean) { + this.states.yellowFlash = v; + } + get whiteOpen(): boolean { + return this.states.whiteOpen; + } + set whiteOpen(v: boolean) { + this.states.whiteOpen = v; + } + get whiteFlash(): boolean { + return this.states.whiteFlash; + } + set whiteFlash(v: boolean) { + this.states.whiteFlash = v; + } + get blueOpen(): boolean { + return this.states.blueOpen; + } + set blueOpen(v: boolean) { + this.states.blueOpen = v; + } + + get blueFlash(): boolean { + return this.states.blueFlash; + } + set blueFlash(v: boolean) { + this.states.blueFlash = v; + } + get fleetMode(): boolean { + return this.states.fleetMode; + } + set fleetMode(v: boolean) { + this.states.fleetMode = v; + } + get ctrlFleetMode(): boolean { + return this.states.ctrlFleetMode; + } + set ctrlFleetMode(v: boolean) { + this.states.ctrlFleetMode = v; + } + get autoMode(): boolean { + return this.states.autoMode; + } + set autoMode(v: boolean) { + this.states.autoMode = v; + } + get ctrlAutoMode(): boolean { + return this.states.ctrlAutoMode; + } + set ctrlAutoMode(v: boolean) { + this.states.ctrlAutoMode = v; + } + get extinguish(): boolean { + return this.states.extinguish; + } + set extinguish(v: boolean) { + this.states.extinguish = v; + } + get approachLock(): boolean { + return this.states.approachLock; + } + set approachLock(v: boolean) { + this.states.approachLock = v; + } + get protectRoute(): boolean { + return this.states.protectRoute; + } + set protectRoute(v: boolean) { + this.states.protectRoute = v; + } + get autoRouteDisable(): boolean { + return this.states.autoRouteDisable; + } + set autoRouteDisable(v: boolean) { + this.states.autoRouteDisable = v; + } + get callon(): boolean { + return this.states.callon; + } + set callon(v: boolean) { + this.states.callon = v; + } + get yellowYellow(): boolean { + return this.states.yellowYellow; + } + set yellowYellow(v: boolean) { + this.states.yellowYellow = v; + } + get yellowGreen(): boolean { + return this.states.yellowGreen; + } + set yellowGreen(v: boolean) { + this.states.yellowGreen = v; + } + get blocked(): boolean { + return this.states.blocked; + } + set blocked(v: boolean) { + this.states.blocked = v; + } + get lampFailure(): boolean { + return this.states.lampFailure; + } + set lampFailure(v: boolean) { + this.states.lampFailure = v; + } + get states(): state.Signal { + return this.getState(); + } + clone(): SignalState { + return new SignalState(this.states.cloneMessage()); + } + copyFrom(data: GraphicStateBase): void { + pb_1.Message.copyInto(data._state, this._state); + } + eq(data: GraphicStateBase): boolean { + return pb_1.Message.equals(this._state, data._state); + } +} + +const mirrorFlipConfig: MenuItemOptions = { + name: '镜像翻转', +}; +const signalCloseConfig: MenuItemOptions = { + name: '信号机关闭', +}; +const signalRedFlashConfig: MenuItemOptions = { + name: '信号机红闪', +}; +const signalOpenConfig: MenuItemOptions = { + name: '信号机开放', +}; +const signalFleetConfig: MenuItemOptions = { + name: '连锁自动进路', +}; +const humanControlConfig: MenuItemOptions = { + name: '进路交人工控', +}; +const logicConfig: MenuItemOptions = { + name: '逻辑点灯', +}; +const SignalEditMenu: ContextMenu = ContextMenu.init({ + name: '信号机编辑菜单', + groups: [ + { + items: [mirrorFlipConfig], + }, + ], +}); +const SignalOperateMenu: ContextMenu = ContextMenu.init({ + name: '信号机操作菜单', + groups: [ + { + items: [ + signalCloseConfig, + signalOpenConfig, + signalFleetConfig, + humanControlConfig, + logicConfig, + signalRedFlashConfig, + ], + }, + ], +}); +export class DrawSignalInteraction extends GraphicInteractionPlugin { + static Name = 'signal_draw_right_menu'; + constructor(app: GraphicApp) { + super(DrawSignalInteraction.Name, app); + app.registerMenu(SignalEditMenu); + } + static init(app: GraphicApp) { + return new DrawSignalInteraction(app); + } + filter(...grahpics: JlGraphic[]): Signal[] | undefined { + return grahpics + .filter((g) => g.type === Signal.Type) + .map((g) => g as Signal); + } + bind(g: Signal): void { + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: Signal): void { + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const signal = target.getGraphic() as Signal; + this.app.updateSelected(signal); + mirrorFlipConfig.handler = () => { + signal.mirror = !signal.mirror; + }; + SignalEditMenu.open(e.global); + } +} + +export class SignalOperateInteraction extends GraphicInteractionPlugin { + static Name = 'signal_operate_menu'; + constructor(app: GraphicApp) { + super(SignalOperateInteraction.Name, app); + app.registerMenu(SignalOperateMenu); + } + static init(app: GraphicApp) { + return new SignalOperateInteraction(app); + } + filter(...grahpics: JlGraphic[]): Signal[] | undefined { + return grahpics + .filter((g) => g.type === Signal.Type) + .map((g) => g as Signal); + } + bind(g: Signal): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.selectable = true; + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: Signal): void { + g.selectable = false; + g.eventMode = 'none'; + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const signal = target.getGraphic() as Signal; + this.app.updateSelected(signal); + signalCloseConfig.handler = () => { + signal.states.redOpen = true; + signal.states.greenOpen = false; + signal.doRepaint(); + }; + signalOpenConfig.handler = () => { + signal.states.redOpen = false; + signal.states.greenOpen = true; + signal.doRepaint(); + }; + signalFleetConfig.handler = () => { + signal.states.fleetMode = true; + signal.doRepaint(); + }; + humanControlConfig.handler = () => { + signal.states.autoRouteDisable = true; + signal.doRepaint(); + }; + logicConfig.handler = () => { + signal.states.extinguish = true; + signal.doRepaint(); + }; + signalRedFlashConfig.handler = () => { + signal.states.redFlash = true; + signal.states.redOpen = false; + signal.states.greenOpen = false; + signal.doRepaint(); + }; + + SignalOperateMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/StationInteraction.ts b/src/drawApp/graphics/StationInteraction.ts new file mode 100644 index 0000000..398cd24 --- /dev/null +++ b/src/drawApp/graphics/StationInteraction.ts @@ -0,0 +1,178 @@ +import * as pb_1 from 'google-protobuf'; +import { + IStationData, + IStationState, + Station, +} from 'src/graphics/station/Station'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase'; +import { state } from 'src/protos/device_status'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { + GraphicApp, + GraphicInteractionPlugin, + JlGraphic, +} from 'src/jl-graphic'; +import { DisplayObject, FederatedMouseEvent } from 'pixi.js'; +import { KilometerSystem } from 'src/graphics/signal/Signal'; + +export class StationData extends GraphicDataBase implements IStationData { + constructor(data?: graphicData.Station) { + let station; + if (!data) { + station = new graphicData.Station({ + common: GraphicDataBase.defaultCommonInfo(Station.Type), + }); + } else { + station = data; + } + super(station); + } + + public get data(): graphicData.Station { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get kilometerSystem(): KilometerSystem { + return this.data.kilometerSystem; + } + set kilometerSystem(v: KilometerSystem) { + this.data.kilometerSystem = new graphicData.KilometerSystem(v); + } + get hasControl(): boolean { + return this.data.hasControl; + } + set hasControl(v: boolean) { + this.data.hasControl = v; + } + get concentrationStations(): boolean { + return this.data.concentrationStations; + } + set concentrationStations(v: boolean) { + this.data.concentrationStations = v; + } + clone(): StationData { + return new StationData(this.data.cloneMessage()); + } + copyFrom(data: StationData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: StationData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export class StationState extends GraphicStateBase implements IStationState { + constructor(proto?: state.Rtu) { + let states; + if (proto) { + states = proto; + } else { + states = new state.Station(); + } + super(states, Station.Type); + } + + get ipRtuStusDown(): boolean { + return this.states.ipRtuStusDown; + } + set ipRtuStusDown(v: boolean) { + this.states.ipRtuStusDown = v; + } + get ipRtuStusInLocalCtrl(): boolean { + return this.states.ipRtuStusInLocalCtrl; + } + set ipRtuStusInLocalCtrl(v: boolean) { + this.states.ipRtuStusInLocalCtrl = v; + } + get ipRtuStusInCentralCtrl(): boolean { + return this.states.ipRtuStusInCentralCtrl; + } + set ipRtuStusInCentralCtrl(v: boolean) { + this.states.ipRtuStusInCentralCtrl = v; + } + get ipRtuStusInEmergencyCtrl(): boolean { + return this.states.ipRtuStusInEmergencyCtrl; + } + set ipRtuStusInEmergencyCtrl(v: boolean) { + this.states.ipRtuStusInEmergencyCtrl = v; + } + get states(): state.Rtu { + return this.getState(); + } + + clone(): StationState { + return new StationState(this.states.cloneMessage()); + } +} + +const powerUnlockConfig: MenuItemOptions = { + name: '上电解锁', +}; + +const chainConfig: MenuItemOptions = { + name: '全站设置连锁自动触发', +}; +const removeChainConfig: MenuItemOptions = { + name: '全站取消连锁自动触发', +}; +const StationOperateMenu: ContextMenu = ContextMenu.init({ + name: '车站操作菜单', + groups: [ + { + items: [powerUnlockConfig, chainConfig, removeChainConfig], + }, + ], +}); + +export class StationOperateInteraction extends GraphicInteractionPlugin { + static Name = 'station_operate_menu'; + constructor(app: GraphicApp) { + super(StationOperateInteraction.Name, app); + app.registerMenu(StationOperateMenu); + } + static init(app: GraphicApp) { + return new StationOperateInteraction(app); + } + filter(...grahpics: JlGraphic[]): Station[] | undefined { + return grahpics + .filter((g) => g.type === Station.Type) + .map((g) => g as Station); + } + bind(g: Station): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.selectable = true; + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: Station): void { + g.selectable = false; + g.eventMode = 'none'; + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const station = target.getGraphic() as Station; + this.app.updateSelected(station); + powerUnlockConfig.handler = () => { + station.states.ipRtuStusInLocalCtrl = true; + station.doRepaint(); + }; + chainConfig.handler = () => { + station.states.ipRtuStusDown = true; + station.doRepaint(); + }; + removeChainConfig.handler = () => { + console.log(2222); + }; + StationOperateMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/StationLineInteraction.ts b/src/drawApp/graphics/StationLineInteraction.ts new file mode 100644 index 0000000..14a22ca --- /dev/null +++ b/src/drawApp/graphics/StationLineInteraction.ts @@ -0,0 +1,55 @@ +import * as pb_1 from 'google-protobuf'; +import { + IStationLineData, + StationLine, +} from 'src/graphics/stationLine/StationLine'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class StationLineData + extends GraphicDataBase + implements IStationLineData +{ + constructor(data?: graphicData.StationLine) { + let stationLine; + if (!data) { + stationLine = new graphicData.StationLine({ + common: GraphicDataBase.defaultCommonInfo(StationLine.Type), + }); + } else { + stationLine = data; + } + super(stationLine); + } + + public get data(): graphicData.StationLine { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get hasTransfer(): boolean { + return this.data.hasTransfer; + } + set hasTransfer(v: boolean) { + this.data.hasTransfer = v; + } + get hideName(): boolean { + return this.data.hideName; + } + set hideName(v: boolean) { + this.data.hideName = v; + } + clone(): StationLineData { + return new StationLineData(this.data.cloneMessage()); + } + copyFrom(data: StationLineData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: StationLineData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/TrainInteraction.ts b/src/drawApp/graphics/TrainInteraction.ts new file mode 100644 index 0000000..95d7f42 --- /dev/null +++ b/src/drawApp/graphics/TrainInteraction.ts @@ -0,0 +1,296 @@ +import * as pb_1 from 'google-protobuf'; +import { ITrainData, ITrainState, Train } from 'src/graphics/train/Train'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase'; +import { state } from 'src/protos/device_status'; +import { train } from 'src/protos/train'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { + GraphicApp, + GraphicInteractionPlugin, + JlGraphic, +} from 'src/jl-graphic'; +import { DisplayObject, FederatedMouseEvent } from 'pixi.js'; + +export class TrainData extends GraphicDataBase implements ITrainData { + constructor(data?: graphicData.Train) { + let train; + if (!data) { + train = new graphicData.Train({ + common: GraphicDataBase.defaultCommonInfo(Train.Type), + }); + } else { + train = data; + } + super(train); + } + + public get data(): graphicData.Train { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + clone(): TrainData { + return new TrainData(this.data.cloneMessage()); + } + copyFrom(data: TrainData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: TrainData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export class TrainState extends GraphicStateBase implements ITrainState { + constructor(proto?: StateTrain) { + let states; + if (proto) { + states = proto; + } else { + states = new StateTrain(); + } + super(states, Train.Type); + } + + get states(): StateTrain { + return this.getState(); + } + + get lineId(): number { + return this.states.lineId; + } + set lineId(v: number) { + this.states.lineId = v; + } + get rtuId(): number { + return this.states.rtuId; + } + set rtuId(v: number) { + this.states.rtuId = v; + } + get window(): train.NccWindow { + if (!this.states.window) { + this.states.window = new train.NccWindow(); + } + return this.states.window; + } + set window(v: train.NccWindow) { + this.states.window = v; + } + get devType(): number { + return this.states.devType; + } + set devType(v: number) { + this.states.devType = v; + } + get devName(): string { + return this.states.devName; + } + set devName(v: string) { + this.states.devName = v; + } + get id(): string { + return this.states.id; + } + set id(v: string) { + this.states.id = v; + } + get groupId(): string { + return this.states.groupId; + } + set groupId(v: string) { + this.states.groupId = v; + } + get trainId(): string { + return this.states.trainId; + } + set trainId(v: string) { + this.states.trainId = v; + } + get globalId(): string { + return this.states.globalId; + } + set globalId(v: string) { + this.states.globalId = v; + } + get destinationId(): number { + return this.states.destinationId; + } + set destinationId(v: number) { + this.states.destinationId = v; + } + get rollingStock(): number { + return this.states.rollingStock; + } + set rollingStock(v: number) { + this.states.rollingStock = v; + } + get driverId(): string { + return this.states.driverId; + } + set driverId(v: string) { + this.states.driverId = v; + } + get otpTime(): number { + return this.states.otpTime; + } + set otpTime(v: number) { + this.states.otpTime = v; + } + get mode(): state.TrainMode { + if (!this.states.mode) { + this.states.mode = new state.TrainMode(); + } + return this.states.mode; + } + set mode(v: state.TrainMode) { + this.states.mode = v; + } + get arriveTime(): number { + return this.states.arriveTime; + } + set arriveTime(v: number) { + this.states.arriveTime = v; + } + get departTime(): number { + return this.states.departTime; + } + set departTime(v: number) { + this.states.departTime = v; + } + get speed(): number { + return this.states.speed; + } + set speed(v: number) { + this.states.speed = v; + } + get show(): boolean { + return this.states.show; + } + set show(v: boolean) { + this.states.show = v; + } + get type(): boolean { + return this.states.type; + } + set type(v: boolean) { + this.states.type = v; + } + get routeId(): number { + return this.states.routeId; + } + set routeId(v: number) { + this.states.routeId = v; + } + get rate(): number { + return this.states.rate; + } + set rate(v: number) { + this.states.rate = v; + } + + clone(): TrainState { + return new TrainState(this.states.cloneMessage()); + } +} + +class StateTrain extends train.TrainInfo { + id: string; + constructor(data?: train.TrainInfo) { + super(data); + if (data?.trainIndex) { + this.id = data?.trainIndex; + } else { + this.id = ''; + } + } +} + +const negativeDirectionConfig: MenuItemOptions = { + name: '反方向运行', +}; +const HoldTrainConfig: MenuItemOptions = { + name: '扣车', +}; +const openDoorConfig: MenuItemOptions = { + name: '开门', +}; +const editGroupConfig: MenuItemOptions = { + name: '修改车组号', +}; +const TrainOperateMenu: ContextMenu = ContextMenu.init({ + name: '列车操作菜单', + groups: [ + { + items: [ + negativeDirectionConfig, + HoldTrainConfig, + openDoorConfig, + editGroupConfig, + ], + }, + ], +}); + +export class TrainOperateInteraction extends GraphicInteractionPlugin { + static Name = 'train_operate_menu'; + constructor(app: GraphicApp) { + super(TrainOperateInteraction.Name, app); + app.registerMenu(TrainOperateMenu); + } + static init(app: GraphicApp) { + return new TrainOperateInteraction(app); + } + filter(...grahpics: JlGraphic[]): Train[] | undefined { + return grahpics.filter((g) => g.type === Train.Type).map((g) => g as Train); + } + bind(g: Train): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.selectable = true; + g.on('_rightclick', this.onContextMenu, this); + } + + unbind(g: Train): void { + g.selectable = false; + g.eventMode = 'none'; + g.off('_rightclick', this.onContextMenu, this); + } + + onContextMenu(e: FederatedMouseEvent) { + const target = e.target as DisplayObject; + const train = target.getGraphic() as Train; + this.app.updateSelected(train); + negativeDirectionConfig.handler = () => { + const mode = train.states.mode; + if (!train.states.mode.ipModeTrainDirUp) { + mode.ipModeTrainDirUp = true; + mode.ipModeTrainDirDown = false; + } else if (!train.states.mode.ipModeTrainDirDown) { + mode.ipModeTrainDirUp = false; + mode.ipModeTrainDirDown = true; + } + train.chagneDirection(); + }; + HoldTrainConfig.handler = () => { + train.states.mode.ipModeTrainHolded = + !train.states.mode.ipModeTrainHolded; + train.chagneState(); + }; + openDoorConfig.handler = () => { + train.states.mode.ipModeTrainDoorOpen = + !train.states.mode.ipModeTrainDoorOpen; + train.chagneState(); + }; + editGroupConfig.handler = () => { + train.states.trainId = '022'; + train.doRepaint(); + }; + TrainOperateMenu.open(e.global); + } +} diff --git a/src/drawApp/graphics/TrainLineInteraction.ts b/src/drawApp/graphics/TrainLineInteraction.ts new file mode 100644 index 0000000..b263865 --- /dev/null +++ b/src/drawApp/graphics/TrainLineInteraction.ts @@ -0,0 +1,110 @@ +import * as pb_1 from 'google-protobuf'; +import { + ITrainLineData, + TrainLine, + ITrainLineState, +} from 'src/graphics/trainLine/TrainLine'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase, GraphicStateBase } from './GraphicDataBase'; +import { state } from 'src/protos/ws_message'; + +export class TrainLineData extends GraphicDataBase implements ITrainLineData { + constructor(data?: graphicData.TrainLine) { + let fan; + if (data) { + fan = data; + } else { + fan = new graphicData.TrainLine({ + common: GraphicDataBase.defaultCommonInfo(TrainLine.Type), + }); + } + super(fan); + } + + public get data(): graphicData.TrainLine { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + clone(): TrainLineData { + return new TrainLineData(this.data.cloneMessage()); + } + copyFrom(data: TrainLineData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: TrainLineData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} + +export class TrainLineState + extends GraphicStateBase + implements ITrainLineState +{ + constructor(proto?: state.WsLineNetTrainOffsetMessage) { + let states; + if (proto) { + states = proto; + } else { + states = new state.WsLineNetTrainOffsetMessage(); + } + super(states, TrainLine.Type); + } + get code(): string { + return this.states.groupId; + } + get lineId(): number { + return this.states.lineId; + } + set lineId(v: number) { + this.states.lineId = v; + } + get trainIndex(): string { + return this.states.trainIndex; + } + set trainIndex(v: string) { + this.states.trainIndex = v; + } + get groupId(): string { + return this.states.groupId; + } + set groupId(v: string) { + this.states.groupId = v; + } + get show(): boolean { + return this.states.show; + } + set show(v: boolean) { + this.states.show = v; + } + get kilometerCode(): number { + return this.states.kilometerCode; + } + set kilometerCode(v: number) { + this.states.kilometerCode = v; + } + get dir(): number { + return this.states.dir; + } + set dir(v: number) { + this.states.dir = v; + } + + get states(): state.WsLineNetTrainOffsetMessage { + return this.getState(); + } + clone(): TrainLineState { + return new TrainLineState(this.states.cloneMessage()); + } + copyFrom(data: GraphicStateBase): void { + pb_1.Message.copyInto(data._state, this._state); + } + eq(data: GraphicStateBase): boolean { + return pb_1.Message.equals(this._state, data._state); + } +} diff --git a/src/drawApp/graphics/TrainWindowInteraction.ts b/src/drawApp/graphics/TrainWindowInteraction.ts new file mode 100644 index 0000000..bab5372 --- /dev/null +++ b/src/drawApp/graphics/TrainWindowInteraction.ts @@ -0,0 +1,49 @@ +import * as pb_1 from 'google-protobuf'; +import { + ITrainWindowData, + TrainWindow, +} from 'src/graphics/trainWindow/TrainWindow'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { GraphicDataBase } from './GraphicDataBase'; + +export class TrainWindowData + extends GraphicDataBase + implements ITrainWindowData +{ + constructor(data?: graphicData.TrainWindow) { + let trainWindow; + if (!data) { + trainWindow = new graphicData.TrainWindow({ + common: GraphicDataBase.defaultCommonInfo(TrainWindow.Type), + }); + } else { + trainWindow = data; + } + super(trainWindow); + } + + public get data(): graphicData.TrainWindow { + return this.getData(); + } + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get sectionId(): string { + return this.data.sectionId; + } + set sectionId(v: string) { + this.data.sectionId = v; + } + clone(): TrainWindowData { + return new TrainWindowData(this.data.cloneMessage()); + } + copyFrom(data: TrainWindowData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: TrainWindowData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/graphics/TurnoutInteraction.ts b/src/drawApp/graphics/TurnoutInteraction.ts new file mode 100644 index 0000000..0fa716e --- /dev/null +++ b/src/drawApp/graphics/TurnoutInteraction.ts @@ -0,0 +1,93 @@ +import { ITurnoutData, Turnout } from 'src/graphics/turnout/Turnout'; +import * as pb_1 from 'google-protobuf'; +import { GraphicDataBase } from './GraphicDataBase'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { IPointData } from 'pixi.js'; +import { KilometerSystem } from 'src/graphics/signal/Signal'; + +function getDefaultEndPoint() { + return { + pointA: [new graphicData.Point([50, 0])], + pointB: [new graphicData.Point([-50, 0])], + pointC: [new graphicData.Point([-50, -50])], + }; +} + +export class TurnoutData extends GraphicDataBase implements ITurnoutData { + constructor(data?: graphicData.Turnout) { + let turnout = new graphicData.Turnout(); + if (!data) { + turnout.common = GraphicDataBase.defaultCommonInfo(Turnout.Type); + const p = getDefaultEndPoint(); + turnout.pointA = p.pointA; + turnout.pointB = p.pointB; + turnout.pointC = p.pointC; + } else { + turnout = data; + } + super(turnout); + } + get data(): graphicData.Turnout { + return this.getData(); + } + + get code(): string { + return this.data.code; + } + set code(v: string) { + this.data.code = v; + } + get pointA(): IPointData[] { + return this.data.pointA; + } + set pointA(v: IPointData[]) { + this.data.pointA = v.map((p) => new graphicData.Point({ x: p.x, y: p.y })); + } + get pointB(): IPointData[] { + return this.data.pointB; + } + set pointB(v: IPointData[]) { + this.data.pointB = v.map((p) => new graphicData.Point({ x: p.x, y: p.y })); + } + get pointC(): IPointData[] { + return this.data.pointC; + } + set pointC(v: IPointData[]) { + this.data.pointC = v.map((p) => new graphicData.Point({ x: p.x, y: p.y })); + } + get paRef(): graphicData.RelatedRef { + return this.data.paRef; + } + set paRef(ref: graphicData.RelatedRef) { + this.data.paRef = ref; + } + get pbRef(): graphicData.RelatedRef { + return this.data.pbRef; + } + set pbRef(ref: graphicData.RelatedRef) { + this.data.pbRef = ref; + } + get pcRef(): graphicData.RelatedRef { + return this.data.pcRef; + } + set pcRef(ref: graphicData.RelatedRef) { + this.data.pcRef = ref; + } + get kilometerSystem(): KilometerSystem[] { + return this.data.kilometerSystem; + } + set kilometerSystem(value: KilometerSystem[]) { + this.data.kilometerSystem = value.map( + (v) => new graphicData.KilometerSystem(v) + ); + } + clone(): TurnoutData { + return new TurnoutData(this.data.cloneMessage()); + } + copyFrom(data: TurnoutData): void { + pb_1.Message.copyInto(data.data, this.data); + } + eq(other: TurnoutData): boolean { + return pb_1.Message.equals(this.data, other.data); + } +} diff --git a/src/drawApp/index.ts b/src/drawApp/index.ts new file mode 100644 index 0000000..b45f48e --- /dev/null +++ b/src/drawApp/index.ts @@ -0,0 +1,393 @@ +import { fromUint8Array, toUint8Array } from 'js-base64'; +import { IPointData, Point } from 'pixi.js'; +import { IscsFan } from 'src/graphics/iscs-fan/IscsFan'; +import { Link } from 'src/graphics/link/Link'; +import { LinkDraw } from 'src/graphics/link/LinkDrawAssistant'; +import { Train, TrainTemplate } from 'src/graphics/train/Train'; +import { TrainDraw } from 'src/graphics/train/TrainDrawAssistant'; +import { Signal, SignalTemplate } from 'src/graphics/signal/Signal'; +import { SignalDraw } from 'src/graphics/signal/SignalDrawAssistant'; +import { + CombinationKey, + GraphicApp, + GraphicData, + GraphicTransform, + JlDrawApp, + KeyListener, +} from 'src/jl-graphic'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; +import { IscsFanData } from './graphics/IscsFanInteraction'; +import { LinkData } from './graphics/LinkInteraction'; +import { TrainData, TrainState } from './graphics/TrainInteraction'; +import { + SignalData, + DrawSignalInteraction, + SignalState, +} from './graphics/SignalInteraction'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { Rect, RectTemplate } from 'src/graphics/rect/Rect'; +import { RectDraw } from 'src/graphics/rect/RectDrawAssistant'; +import { RectData } from './graphics/RectInteraction'; +import { Platform, PlatformTemplate } from 'src/graphics/platform/Platform'; +import { PlatformData, PlatformState } from './graphics/PlatformInteraction'; +import { PlatformDraw } from 'src/graphics/platform/PlatformDrawAssistant'; +import { Station, StationTemplate } from 'src/graphics/station/Station'; +import { StationDraw } from 'src/graphics/station/StationDrawAssistant'; +import { StationData, StationState } from './graphics/StationInteraction'; +import { + StationLine, + StationLineTemplate, +} from 'src/graphics/stationLine/StationLine'; +import { StationLineDraw } from 'src/graphics/stationLine/StationLineDrawAssistant'; +import { StationLineData } from './graphics/StationLineInteraction'; +import { + ItrainLineTemplate, + TrainLine, +} from 'src/graphics/trainLine/TrainLine'; +import { TrainLineDraw } from 'src/graphics/trainLine/TrainLineAssistant'; +import { TrainLineData } from './graphics/TrainLineInteraction'; +import { + OneClickGenerateDraw, + OneClickGenerateTemplate, +} from 'src/graphics/trainWindow/oneClickDrawAssistant'; +import { + TrainWindow, + TrainWindowTemplate, +} from 'src/graphics/trainWindow/TrainWindow'; +import { TrainWindowDraw } from 'src/graphics/trainWindow/TrainWindowDrawAssistant'; +import { TrainWindowData } from './graphics/TrainWindowInteraction'; +import { + AxleCounting, + AxleCountingTemplate, +} from 'src/graphics/axleCounting/AxleCounting'; +import { AxleCountingDraw } from 'src/graphics/axleCounting/AxleCountingDrawAssistant'; +import { AxleCountingData } from './graphics/AxleCountingInteraction'; +import { Turnout, TurnoutTemplate } from 'src/graphics/turnout/Turnout'; +import { TurnoutDraw } from 'src/graphics/turnout/TurnoutDrawAssistant'; +import { TurnoutData } from './graphics/TurnoutInteraction'; +import { RunLine, RunLineTemplate } from 'src/graphics/runLine/RunLine'; +import { RunLineDraw } from 'src/graphics/runLine/RunLineDrawAssistant'; +import { RunLineData, DrawRunLinePlugin } from './graphics/RunLineInteraction'; +import { saveDraft, getDraft } from 'src/api/DraftApi'; +import { useDrawStore } from 'src/stores/draw-store'; +import { successNotify, errorNotify } from '../utils/CommonNotify'; +import { Section, SectionTemplate } from 'src/graphics/section/Section'; +import { SectionDraw } from 'src/graphics/section/SectionDrawAssistant'; +import { SectionData } from './graphics/SectionInteraction'; +import { PathLine, PathLineTemplate } from 'src/graphics/pathLine/PathLine'; +import { PathLineDraw } from 'src/graphics/pathLine/PathLineDrawAssistant'; +import { PathLineData } from './graphics/PathLineInteraction'; +import { toStorageTransform } from './graphics/GraphicDataBase'; +import { SeparatorDraw } from 'src/graphics/separator/SeparatorDrawAssistant'; +import { Separator, SeparatorTemplate } from 'src/graphics/separator/Separator'; +import { SeparatorData } from './graphics/SeparatorInteraction'; + +// export function fromStoragePoint(p: graphicData.Point): Point { +// return new Point(p.x, p.y); +// } + +// export function toStoragePoint(p: IPointData): graphicData.Point { +// return new graphicData.Point({ x: p.x, y: p.y }); +// } + +// export function fromStorageTransfrom( +// transfrom: graphicData.Transform +// ): GraphicTransform { +// return new GraphicTransform( +// fromStoragePoint(transfrom.position), +// fromStoragePoint(transfrom.scale), +// transfrom.rotation, +// fromStoragePoint(transfrom.skew) +// ); +// } + +// export function toStorageTransform( +// transform: GraphicTransform +// ): graphicData.Transform { +// return new graphicData.Transform({ +// position: toStoragePoint(transform.position), +// scale: toStoragePoint(transform.scale), +// rotation: transform.rotation, +// skew: toStoragePoint(transform.skew), +// }); +// } + +const UndoOptions: MenuItemOptions = { + name: '撤销', +}; +const RedoOptions: MenuItemOptions = { + name: '重做', +}; +const SelectAllOptions: MenuItemOptions = { + name: '全选', +}; + +export const DefaultCanvasMenu = new ContextMenu({ + name: '绘制-画布菜单', + groups: [ + { + items: [UndoOptions, RedoOptions], + }, + { + items: [SelectAllOptions], + }, + ], +}); + +let drawApp: JlDrawApp | null = null; + +export function getDrawApp(): JlDrawApp | null { + return drawApp; +} + +export function destroyDrawApp(): void { + if (drawApp) { + drawApp.destroy(); + drawApp = null; + } +} + +export function initDrawApp(dom: HTMLElement): JlDrawApp { + drawApp = new JlDrawApp(dom); + const app = drawApp; + //根据草稿图类型加载绘图工具 + const draftType = useDrawStore().$state.draftType; + let drawAssistants: ( + | PlatformDraw + | StationDraw + | SignalDraw + | TurnoutDraw + | RunLineDraw + | SectionDraw + | StationLineDraw + | RectDraw + | TrainLineDraw + | PathLineDraw + | TrainWindowDraw + | TrainDraw + | OneClickGenerateDraw + | AxleCountingDraw + | SeparatorDraw + )[] = []; + if (draftType === 'Line') { + drawAssistants = [ + new PlatformDraw( + app, + new PlatformTemplate(new PlatformData(), new PlatformState()) + ), + new StationDraw( + app, + new StationTemplate(new StationData(), new StationState()) + ), + new SignalDraw( + app, + new SignalTemplate(new SignalData(), new SignalState()) + ), + new TrainDraw(app, new TrainTemplate(new TrainData(), new TrainState())), + new SectionDraw(app, new SectionTemplate(new SectionData())), + new TurnoutDraw(app, new TurnoutTemplate(new TurnoutData())), + new TrainWindowDraw(app, new TrainWindowTemplate(new TrainWindowData())), + new OneClickGenerateDraw(app, new OneClickGenerateTemplate()), + new AxleCountingDraw( + app, + new AxleCountingTemplate(new AxleCountingData()) + ), + new SeparatorDraw(app, new SeparatorTemplate(new SeparatorData())), + ]; + DrawSignalInteraction.init(app); + } else { + drawAssistants = [ + new StationLineDraw(app, new StationLineTemplate(new StationLineData())), + new RectDraw(app, new RectTemplate(new RectData())), + new RunLineDraw(app, new RunLineTemplate(new RunLineData())), + new TrainLineDraw(app, new ItrainLineTemplate(new TrainLineData())), + new PathLineDraw(app, new PathLineTemplate(new PathLineData())), + ]; + DrawRunLinePlugin.init(app); + } + + app.setOptions({ drawAssistants: drawAssistants }); + + // 画布右键菜单 + app.registerMenu(DefaultCanvasMenu); + app.canvas.on('_rightclick', (e) => { + if (app._drawing) return; + UndoOptions.disabled = !app.opRecord.hasUndo; + RedoOptions.disabled = !app.opRecord.hasRedo; + UndoOptions.handler = () => { + app.opRecord.undo(); + }; + RedoOptions.handler = () => { + app.opRecord.redo(); + }; + SelectAllOptions.handler = () => { + app.selectAllGraphics(); + }; + DefaultCanvasMenu.open(e.global); + }); + app.addKeyboardListener( + new KeyListener({ + value: 'KeyS', + global: true, + combinations: [CombinationKey.Ctrl], + onPress: () => { + saveDrawToServer(app); + }, + }) + ); + return drawApp; +} + +export function saveDrawToServer(app: JlDrawApp) { + const base64 = saveDrawDatas(app); + const drawStore = useDrawStore(); + const id = drawStore.draftId; + if (!id) { + return; + } + saveDraft(id as number, { proto: base64 }) + .then(() => { + successNotify('保存数据成功!'); + }) + .catch((err) => { + errorNotify(err.message, err); + }); +} + +// const StorageKey = 'graphic-storage'; +export function saveDrawDatas(app: JlDrawApp) { + const storage = new graphicData.RtssGraphicStorage(); + const canvasData = app.canvas.saveData(); + storage.canvas = new graphicData.Canvas({ + ...canvasData, + viewportTransform: toStorageTransform(canvasData.viewportTransform), + }); + const graphics = app.queryStore.getAllGraphics(); + graphics.forEach((g) => { + if (Link.Type === g.type) { + const linkData = (g as Link).saveData(); + storage.links.push((linkData as LinkData).data); + } else if (Rect.Type === g.type) { + const rectData = (g as Rect).saveData(); + storage.rects.push((rectData as RectData).data); + } else if (IscsFan.Type === g.type) { + const IscsFanData = (g as IscsFan).saveData(); + storage.iscsFans.push((IscsFanData as IscsFanData).data); + } else if (Platform.Type === g.type) { + const platformData = (g as Platform).saveData(); + storage.Platforms.push((platformData as PlatformData).data); + } else if (Station.Type === g.type) { + const stationData = (g as Station).saveData(); + storage.stations.push((stationData as StationData).data); + } else if (Train.Type === g.type) { + const trainData = (g as Train).saveData(); + storage.train.push((trainData as TrainData).data); + } else if (Turnout.Type === g.type) { + const turnoutData = (g as Turnout).saveData(); + storage.turnouts.push((turnoutData as TurnoutData).data); + } else if (Signal.Type === g.type) { + const signalData = (g as Signal).saveData(); + storage.signals.push((signalData as SignalData).data); + } else if (RunLine.Type === g.type) { + const runLineData = (g as RunLine).saveData(); + storage.runLines.push((runLineData as RunLineData).data); + } else if (Section.Type === g.type) { + const sectionData = (g as Section).saveData(); + storage.section.push((sectionData as SectionData).data); + } else if (StationLine.Type === g.type) { + const stationLineData = (g as StationLine).saveData(); + storage.stationLines.push((stationLineData as StationLineData).data); + } else if (TrainLine.Type === g.type) { + const trainLineData = (g as TrainLine).saveData(); + storage.trainLines.push((trainLineData as TrainLineData).data); + } else if (PathLine.Type === g.type) { + const pathLineData = (g as PathLine).saveData(); + storage.pathLines.push((pathLineData as PathLineData).data); + } else if (TrainWindow.Type === g.type) { + const trainWindowData = (g as TrainWindow).saveData(); + storage.trainWindows.push((trainWindowData as TrainWindowData).data); + } else if (AxleCounting.Type === g.type) { + const axleCountingData = (g as AxleCounting).saveData(); + storage.axleCountings.push((axleCountingData as AxleCountingData).data); + } else if (Separator.Type === g.type) { + const separatorData = (g as Separator).saveData(); + storage.separators.push((separatorData as SeparatorData).data); + } + }); + const base64 = fromUint8Array(storage.serialize()); + console.log('保存数据', storage); + // localStorage.setItem(StorageKey, base64); + return base64; +} + +export async function loadDrawDatas(app: GraphicApp) { + // localStorage.removeItem(StorageKey); + // const base64 = localStorage.getItem(StorageKey); + // console.log('加载数据', base64); + const drawStore = useDrawStore(); + const id = drawStore.draftId; + if (!id) { + return; + } + const { proto: base64 } = await getDraft(id); + if (base64) { + const storage = graphicData.RtssGraphicStorage.deserialize( + toUint8Array(base64) + ); + console.log('加载数据', storage); + app.updateCanvas(storage.canvas); + const datas: GraphicData[] = []; + storage.links.forEach((link) => { + datas.push(new LinkData(link)); + }); + storage.rects.forEach((rect) => { + datas.push(new RectData(rect)); + }); + storage.iscsFans.forEach((fan) => { + datas.push(new IscsFanData(fan)); + }); + storage.Platforms.forEach((platform) => { + datas.push(new PlatformData(platform)); + }); + storage.stations.forEach((station) => { + datas.push(new StationData(station)); + }); + storage.train.forEach((train) => { + datas.push(new TrainData(train)); + }); + storage.turnouts.forEach((turnout) => { + datas.push(new TurnoutData(turnout)); + }); + storage.signals.forEach((signal) => { + datas.push(new SignalData(signal)); + }); + storage.runLines.forEach((runLine) => { + datas.push(new RunLineData(runLine)); + }); + storage.section.forEach((section) => { + datas.push(new SectionData(section)); + }); + storage.stationLines.forEach((stationLine) => { + datas.push(new StationLineData(stationLine)); + }); + storage.trainLines.forEach((trainLine) => { + datas.push(new TrainLineData(trainLine)); + }); + storage.pathLines.forEach((pathLine) => { + datas.push(new PathLineData(pathLine)); + }); + storage.trainWindows.forEach((trainWindow) => { + datas.push(new TrainWindowData(trainWindow)); + }); + storage.axleCountings.forEach((axleCounting) => { + datas.push(new AxleCountingData(axleCounting)); + }); + storage.separators.forEach((separator) => { + datas.push(new SeparatorData(separator)); + }); + app.loadGraphic(datas); + } else { + app.loadGraphic([]); + } +} diff --git a/src/drawApp/lineApp.ts b/src/drawApp/lineApp.ts new file mode 100644 index 0000000..c8ac63c --- /dev/null +++ b/src/drawApp/lineApp.ts @@ -0,0 +1,137 @@ +import { + GraphicApp, + GraphicData, + StompCli, + AppWsMsgBroker, + GraphicState, +} from 'src/jl-graphic'; +import { TrainData, TrainState } from './graphics/TrainInteraction'; +import { TrainTemplate } from 'src/graphics/train/Train'; +import { + SignalData, + SignalOperateInteraction, + SignalState, +} from './graphics/SignalInteraction'; +import { SignalTemplate, Signal } from 'src/graphics/signal/Signal'; +import { + PlatformData, + PlatformOperateInteraction, + PlatformState, +} from './graphics/PlatformInteraction'; +import { PlatformTemplate, Platform } from 'src/graphics/platform/Platform'; +import { StationData, StationState } from './graphics/StationInteraction'; +import { StationTemplate } from 'src/graphics/station/Station'; +import { TurnoutData } from './graphics/TurnoutInteraction'; +import { TurnoutTemplate } from 'src/graphics/turnout/Turnout'; +import { SectionData } from './graphics/SectionInteraction'; +import { SectionTemplate } from 'src/graphics/section/Section'; +import { getPublishMapInfoByLineId } from 'src/api/PublishApi'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { useLineStore } from 'src/stores/line-store'; +import { toUint8Array } from 'js-base64'; +import { getWebsocketUrl } from 'src/configs/UrlManage'; +import { getJwtToken } from 'src/configs/TokenManage'; +import { state } from 'src/protos/ws_message'; + +let lineApp: GraphicApp | null = null; +let msgBroker: AppWsMsgBroker | null = null; + +export function getLineApp(): GraphicApp | null { + return lineApp; +} + +export function destroyLineApp(): void { + if (lineApp) { + lineApp.destroy(); + lineApp = null; + } + if (msgBroker) { + msgBroker.close(); + } +} + +export function initLineApp(dom: HTMLElement): GraphicApp { + lineApp = new GraphicApp(dom); + const graphicTemplate = [ + new TrainTemplate(new TrainData(), new TrainState()), + new SignalTemplate(new SignalData(), new SignalState()), + new PlatformTemplate(new PlatformData(), new PlatformState()), + new StationTemplate(new StationData(), new StationState()), + new TurnoutTemplate(new TurnoutData()), + new SectionTemplate(new SectionData()), + ]; + lineApp.registerGraphicTemplates(...graphicTemplate); + lineApp.setOptions({ + mouseToolOptions: { + boxSelect: false, + viewportDrag: true, + wheelZoom: true, + }, + interactiveTypeOptions: { + interactiveGraphicTypeIncludes: [Signal.Type, Platform.Type], + }, + }); + SignalOperateInteraction.init(lineApp); + PlatformOperateInteraction.init(lineApp); + return lineApp; +} + +export async function loadLineDatas(app: GraphicApp) { + const lineStore = useLineStore(); + const lineId = lineStore.lineId; + if (!lineId) { + return; + } + const { proto: base64, name: lineName } = await getPublishMapInfoByLineId( + lineId, + 'line' + ); + lineStore.setLineName(lineName); + if (base64) { + const storage = graphicData.RtssGraphicStorage.deserialize( + toUint8Array(base64) + ); + console.log('加载数据', storage); + app.updateCanvas(storage.canvas); + const datas: GraphicData[] = []; + storage.Platforms.forEach((platform) => { + const g = new PlatformData(platform); + datas.push(g); + }); + storage.stations.forEach((station) => { + datas.push(new StationData(station)); + }); + storage.train.forEach((train) => { + datas.push(new TrainData(train)); + }); + storage.turnouts.forEach((turnout) => { + datas.push(new TurnoutData(turnout)); + }); + storage.signals.forEach((signal) => { + datas.push(new SignalData(signal)); + }); + storage.section.forEach((section) => { + datas.push(new SectionData(section)); + }); + await app.loadGraphic(datas); + + StompCli.new({ + wsUrl: `${getWebsocketUrl()}`, + token: getJwtToken() as string, + }); + msgBroker = new AppWsMsgBroker(app); + const states: GraphicState[] = []; + msgBroker.subscribe({ + destination: `/queue/line/${lineId}/device`, + messageConverter: (message: Uint8Array) => { + const storage = state.WsLineMessage.deserialize(message); + storage.signal.forEach((item) => { + states.push(new SignalState(item)); + }); + return states; + }, + }); + } else { + app.loadGraphic([]); + } +} diff --git a/src/drawApp/lineNetApp.ts b/src/drawApp/lineNetApp.ts new file mode 100644 index 0000000..1b950dd --- /dev/null +++ b/src/drawApp/lineNetApp.ts @@ -0,0 +1,132 @@ +import { + GraphicApp, + GraphicData, + StompCli, + AppWsMsgBroker, + GraphicState, +} from 'src/jl-graphic'; +import { getPublishLineNet } from 'src/api/PublishApi'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { state } from 'src/protos/ws_message'; + +import { RunLine, RunLineTemplate } from 'src/graphics/runLine/RunLine'; +import { + RunLineData, + RunLineOperateInteraction, +} from './graphics/RunLineInteraction'; +import { PathLineTemplate, PathLine } from 'src/graphics/pathLine/PathLine'; +import { PathLineData } from './graphics/PathLineInteraction'; +import { + StationLineTemplate, + StationLine, +} from 'src/graphics/stationLine/StationLine'; +import { StationLineData } from './graphics/StationLineInteraction'; +import { ItrainLineTemplate } from 'src/graphics/trainLine/TrainLine'; +import { TrainLineData, TrainLineState } from './graphics/TrainLineInteraction'; +import { RectTemplate } from 'src/graphics/rect/Rect'; +import { RectData } from './graphics/RectInteraction'; + +import { useLineNetStore } from 'src/stores/line-net-store'; +import { toUint8Array } from 'js-base64'; +import { getWebsocketUrl } from 'src/configs/UrlManage'; +import { getJwtToken } from 'src/configs/TokenManage'; + +let lineNetApp: GraphicApp | null = null; +let msgBroker: AppWsMsgBroker | null = null; + +export function getLineNetApp(): GraphicApp | null { + return lineNetApp; +} + +export function destroyLineNetApp(): void { + if (lineNetApp) { + lineNetApp.destroy(); + lineNetApp = null; + } + if (msgBroker) { + msgBroker.close(); + } +} + +export function initLineNetApp(dom: HTMLElement): GraphicApp { + lineNetApp = new GraphicApp(dom); + const graphicTemplate = [ + new RunLineTemplate(new RunLineData()), + new PathLineTemplate(new PathLineData()), + new StationLineTemplate(new StationLineData()), + new ItrainLineTemplate(new TrainLineData(), new TrainLineState()), + new RectTemplate(new RectData()), + ]; + lineNetApp.registerGraphicTemplates(...graphicTemplate); + lineNetApp.setOptions({ + mouseToolOptions: { + boxSelect: false, + viewportDrag: true, + wheelZoom: true, + }, + interactiveTypeOptions: { + interactiveGraphicTypeIncludes: [RunLine.Type, StationLine.Type], + }, + }); + RunLineOperateInteraction.init(lineNetApp); + return lineNetApp; +} + +export async function loadLineNetDatas(app: GraphicApp) { + const lineNetStore = useLineNetStore(); + const { proto: base64, name: lineNetName } = await getPublishLineNet(); + lineNetStore.setLineNetName(lineNetName); + if (base64) { + const storage = graphicData.RtssGraphicStorage.deserialize( + toUint8Array(base64) + ); + console.log('加载数据', storage); + app.updateCanvas(storage.canvas); + const datas: GraphicData[] = []; + storage.runLines.forEach((runLine) => { + const g = new RunLineData(runLine); + datas.push(g); + }); + storage.pathLines.forEach((pathLine) => { + const g = new PathLineData(pathLine); + datas.push(g); + }); + storage.stationLines.forEach((stationLine) => { + const g = new StationLineData(stationLine); + datas.push(g); + }); + storage.trainLines.forEach((trainLine) => { + const g = new TrainLineData(trainLine); + datas.push(g); + }); + storage.rects.forEach((rect) => { + const g = new RectData(rect); + datas.push(g); + }); + await app.loadGraphic(datas); + const pathLineList = app.queryStore.queryByType(PathLine.Type); + pathLineList.forEach((pathLine) => { + pathLine.visible = false; + }); + + StompCli.new({ + wsUrl: `${getWebsocketUrl()}`, + token: getJwtToken() as string, + }); + msgBroker = new AppWsMsgBroker(app); + const states: GraphicState[] = []; + msgBroker.subscribe({ + destination: '/queue/lineNet', + messageConverter: (message: Uint8Array) => { + const storage = state.WsLineNetMessage.deserialize(message); + console.log(storage, 'storage'); + storage.offset.forEach((item) => { + states.push(new TrainLineState(item)); + }); + return states; + }, + }); + } else { + app.loadGraphic([]); + } +} diff --git a/src/env.d.ts b/src/env.d.ts new file mode 100644 index 0000000..dd757b1 --- /dev/null +++ b/src/env.d.ts @@ -0,0 +1,9 @@ +/* eslint-disable */ + +declare namespace NodeJS { + interface ProcessEnv { + NODE_ENV: string; + VUE_ROUTER_MODE: 'hash' | 'history' | 'abstract' | undefined; + VUE_ROUTER_BASE: string | undefined; + } +} diff --git a/src/graphics/CommonGraphics.ts b/src/graphics/CommonGraphics.ts new file mode 100644 index 0000000..58777ff --- /dev/null +++ b/src/graphics/CommonGraphics.ts @@ -0,0 +1,116 @@ +import { Graphics } from 'pixi.js'; +import { calculateMirrorPoint } from 'src/jl-graphic'; +import { graphicData } from 'src/protos/stationLayoutGraphics'; +import { Turnout, TurnoutPort } from './turnout/Turnout'; +import { Section, SectionPort } from './section/Section'; +import { TrainWindow } from './trainWindow/TrainWindow'; +import { AxleCounting } from './axleCounting/AxleCounting'; +/** + * + * @param polygon + * @param x 箭头顶点x坐标 + * @param y 箭头顶点y坐标 + * @param length 箭头长度 + * @param radius 箭头三角半径 + * @param lineWidth 箭头线宽 + * @param mirror 是否镜像翻转 (基于箭头顶点) + */ +export function drawArrow( + polygon: Graphics, + x: number, + y: number, + length: number, + radius: number, + lineWidth: number, + mirror: boolean +) { + const trianglAcme = { x, y }; + let triangleP1 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y + Math.cos(Math.PI / 6) * radius, + }; + let triangleP2 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y - Math.cos(Math.PI / 6) * radius, + }; + let lineP1 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y + lineWidth / 2, + }; + let lineP2 = { + x: x - length, + y: y + lineWidth / 2, + }; + let lineP3 = { + x: x - length, + y: y - lineWidth / 2, + }; + let lineP4 = { + x: x - radius - Math.sin(Math.PI / 6), + y: y - lineWidth / 2, + }; + if (mirror) { + triangleP1 = calculateMirrorPoint(trianglAcme, triangleP1); + triangleP2 = calculateMirrorPoint(trianglAcme, triangleP2); + lineP1 = calculateMirrorPoint(trianglAcme, lineP1); + lineP2 = calculateMirrorPoint(trianglAcme, lineP2); + lineP3 = calculateMirrorPoint(trianglAcme, lineP3); + lineP4 = calculateMirrorPoint(trianglAcme, lineP4); + } + polygon.drawPolygon( + trianglAcme.x, + trianglAcme.y, + triangleP1.x, + triangleP1.y, + lineP1.x, + lineP1.y, + lineP2.x, + lineP2.y, + lineP3.x, + lineP3.y, + lineP4.x, + lineP4.y, + triangleP2.x, + triangleP2.y + ); +} + +export function createRelatedRefProto( + type: string, + id: string, + port?: TurnoutPort | SectionPort +) { + const typeMap = new Map([ + [Section.Type, graphicData.RelatedRef.DeviceType.Section], + [Turnout.Type, graphicData.RelatedRef.DeviceType.Turnout], + [TrainWindow.Type, graphicData.RelatedRef.DeviceType.TrainWindow], + [AxleCounting.Type, graphicData.RelatedRef.DeviceType.AxleCounting], + ]); + const protoDeviceType = typeMap.get(type); + if (protoDeviceType === undefined) throw Error(`输入的type有误: ${type}`); + const protoData = new graphicData.RelatedRef({ + deviceType: protoDeviceType, + id, + }); + if (port) { + if (port === 'A') + protoData.devicePort = graphicData.RelatedRef.DevicePort.A; + if (port === 'B') + protoData.devicePort = graphicData.RelatedRef.DevicePort.B; + if (port === 'C') + protoData.devicePort = graphicData.RelatedRef.DevicePort.C; + } + return protoData; +} + +export function protoPort2Data(port: graphicData.RelatedRef.DevicePort) { + if (port === graphicData.RelatedRef.DevicePort.A) return 'A'; + if (port === graphicData.RelatedRef.DevicePort.B) return 'B'; + if (port === graphicData.RelatedRef.DevicePort.C) return 'C'; +} + +export interface IRelatedRefData { + deviceType: graphicData.RelatedRef.DeviceType; //关联的设备类型 + id: string; //关联的设备ID + devicePort: graphicData.RelatedRef.DevicePort; //关联的设备端口 +} diff --git a/src/graphics/axleCounting/AxleCounting.ts b/src/graphics/axleCounting/AxleCounting.ts new file mode 100644 index 0000000..5538fb9 --- /dev/null +++ b/src/graphics/axleCounting/AxleCounting.ts @@ -0,0 +1,116 @@ +import { Color, Container, Graphics } from 'pixi.js'; +import { + GraphicData, + GraphicRelationParam, + JlGraphic, + JlGraphicTemplate, + VectorText, +} from 'src/jl-graphic'; +import { IRelatedRefData, protoPort2Data } from '../CommonGraphics'; +import { KilometerSystem } from '../signal/Signal'; + +export interface IAxleCountingData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get kilometerSystem(): KilometerSystem; + set kilometerSystem(v: KilometerSystem); + get axleCountingRef(): IRelatedRefData[]; //关联的设备 + set axleCountingRef(ref: IRelatedRefData[]); + clone(): IAxleCountingData; + copyFrom(data: IAxleCountingData): void; + eq(other: IAxleCountingData): boolean; +} + +export const AxleCountingConsts = { + radius: 6, + borderWidth: 1, + circleColorBlue: '0x08F80D', + codeColor: '0xF48815', + codeFontSize: 22, + codeOffsetY: 30, + kilometerCodeColor: '0xFFFFFF', + kilometerCodeFontSize: 14, + kilometerCodeOffsetY: 95, + offsetSection: 50, +}; +class TwoCircleGraphic extends Container { + circleA: Graphics = new Graphics(); + circleB: Graphics = new Graphics(); + line: Graphics = new Graphics(); + constructor() { + super(); + this.addChild(this.circleA); + this.addChild(this.circleB); + this.addChild(this.line); + } + draw(): void { + this.drawCircle(this.circleA); + this.drawCircle(this.circleB); + this.circleA.position.set(-12, 0); + this.circleB.position.set(12, 0); + this.line.clear(); + this.line.lineStyle(1, new Color(AxleCountingConsts.circleColorBlue)); + this.line.moveTo(-24, 0); + this.line.lineTo(24, 0); + } + drawCircle(circle: Graphics): void { + circle.clear(); + circle.lineStyle( + AxleCountingConsts.borderWidth, + new Color(AxleCountingConsts.circleColorBlue) + ); + circle.beginFill(AxleCountingConsts.circleColorBlue, 1); + circle.drawCircle(0, 0, AxleCountingConsts.radius); + circle.endFill; + } + clear(): void { + this.circleA.clear(); + this.circleB.clear(); + } +} +export class AxleCounting extends JlGraphic { + static Type = 'AxleCounting'; + twoCircle: TwoCircleGraphic = new TwoCircleGraphic(); + kilometerGraph: VectorText = new VectorText(''); //公里标 + direction: number; + constructor(direction: number) { + super(AxleCounting.Type); + this.addChild(this.twoCircle); + this.addChild(this.kilometerGraph); + this.kilometerGraph.name = 'kilometer'; + this.direction = direction; + } + + get datas(): IAxleCountingData { + return this.getDatas(); + } + doRepaint(): void { + this.twoCircle.draw(); + } + loadRelations(): void { + if (this.datas.axleCountingRef.length) { + this.datas.axleCountingRef.forEach((device) => { + this.relationManage.addRelation( + new GraphicRelationParam(this, 'A'), + new GraphicRelationParam( + this.queryStore.queryById(device.id), + protoPort2Data(device.devicePort) + ) + ); + }); + } + } +} + +export class AxleCountingTemplate extends JlGraphicTemplate { + constructor(dataTemplate: IAxleCountingData) { + super(AxleCounting.Type, { + dataTemplate, + }); + } + new(): AxleCounting { + const axleCounting = new AxleCounting(1); + axleCounting.loadData(this.datas); + return axleCounting; + } +} diff --git a/src/graphics/axleCounting/AxleCountingDrawAssistant.ts b/src/graphics/axleCounting/AxleCountingDrawAssistant.ts new file mode 100644 index 0000000..b7b38b7 --- /dev/null +++ b/src/graphics/axleCounting/AxleCountingDrawAssistant.ts @@ -0,0 +1,394 @@ +import { FederatedPointerEvent, IPoint, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicIdGenerator, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, + distance2, +} from 'src/jl-graphic'; + +import { + IAxleCountingData, + AxleCounting, + AxleCountingTemplate, + AxleCountingConsts, +} from './AxleCounting'; +import { Section, SectionPort, SectionType } from '../section/Section'; +import { Turnout, TurnoutPort } from '../turnout/Turnout'; +import { IRelatedRefData, createRelatedRefProto } from '../CommonGraphics'; +import { Signal } from '../signal/Signal'; + +export interface IAxleCountingDrawOptions { + newData: () => IAxleCountingData; +} + +enum DevicePort { + A = 0, + B = 1, + C = 2, +} + +enum DevicePortN { + A, + B, + C, +} + +export class AxleCountingDraw extends GraphicDrawAssistant< + AxleCountingTemplate, + IAxleCountingData +> { + codeGraph: AxleCounting; + constructor(app: JlDrawApp, template: AxleCountingTemplate) { + super(app, template, 'sym_o_circle', '不展示'); + this.codeGraph = this.graphicTemplate.new(); + this.container.addChild(this.codeGraph); + AxleCountingInteraction.init(app); + } + + bind(): void { + super.bind(); + this.codeGraph.loadData(this.graphicTemplate.datas); + this.codeGraph.doRepaint(); + } + + clearCache(): void { + //this.codeGraph.destroy(); + } + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + prepareData(data: IAxleCountingData): boolean { + data.transform = this.container.saveTransform(); + return true; + } + draw( + ps: IPoint, + direction: number, + graphic: Section | Turnout, + port: TurnoutPort | SectionPort, + map: Map, + reftype: string, + refGraphic: Section | Turnout, + refPort: TurnoutPort | SectionPort + ) { + if ( + graphic.type == 'Turnout' && + reftype == 'Turnout' && + port == TurnoutPort.B && + refPort == TurnoutPort.B + ) { + const points = (graphic as Turnout).getPortPoints(); + const portPs = graphic.localToCanvasPoints(points[1][0])[0]; + let hasSingle = false; + const singles = this.app.queryStore.queryByType(Signal.Type); + singles.forEach((single) => { + if (distance2(portPs, single.position) < 50) { + hasSingle = true; + } + }); + if (!hasSingle) { + map.set(`${graphic.id}-${port}`, 1); + map.set(`${refGraphic.id}-${refPort}`, 1); + return; + } + } + + if ( + !map.has(`${refGraphic.id}-${refPort}`) && + !map.has(`${graphic.id}-${port}`) + ) { + map.set(`${graphic.id}-${port}`, 1); + map.set(`${refGraphic.id}-${refPort}`, 1); + const refData1 = createRelatedRefProto(reftype, refGraphic.id, refPort); + const refData2 = createRelatedRefProto(graphic.type, graphic.id, port); + const axleCounting = new AxleCounting(direction); + axleCounting.loadData(this.graphicTemplate.datas); + if (graphic.type == 'Turnout') { + axleCounting.position.set(ps.x, ps.y); + } else { + axleCounting.position.set( + ps.x, + ps.y - AxleCountingConsts.offsetSection * direction + ); + } + axleCounting.id = GraphicIdGenerator.next(); + axleCounting.datas.axleCountingRef = [refData2, refData1]; + axleCounting.datas.code = `${graphic.datas.code}-${port}+${refGraphic.datas.code}-${refPort}`; + this.storeGraphic(axleCounting); + axleCounting.loadRelations(); + } + } + drawAdd( + ps: IPoint, + direction: number, + graphic: Section | Turnout, + port: TurnoutPort | SectionPort, + map: Map + ) { + if (!map.has(`${graphic.id}-${port}`)) { + map.set(`${graphic.id}-${port}`, 1); + const refData = createRelatedRefProto(graphic.type, graphic.id, port); + const axleCounting = new AxleCounting(direction); + axleCounting.loadData(this.graphicTemplate.datas); + if (graphic.type == 'Turnout') { + axleCounting.position.set(ps.x, ps.y); + } else { + axleCounting.position.set( + ps.x, + ps.y - AxleCountingConsts.offsetSection * direction + ); + } + axleCounting.id = GraphicIdGenerator.next(); + axleCounting.datas.axleCountingRef = [refData]; + axleCounting.datas.code = `${graphic.datas.code}-${port}`; + this.storeGraphic(axleCounting); + axleCounting.loadRelations(); + } + } + oneGenerates(height: Point) { + const map = new Map(); + const axleCountings = this.app.queryStore.queryByType( + AxleCounting.Type + ); + const axleCountingRefs: IRelatedRefData[] = []; + axleCountings.forEach((axleCounting) => { + axleCountingRefs.push(...axleCounting.datas.axleCountingRef); + }); + axleCountingRefs.forEach((axleCountingRef) => { + map.set( + `${axleCountingRef.id}-${DevicePortN[axleCountingRef.devicePort]}`, + 1 + ); + }); + //由区段生成计轴--区段和区段 + const sections = this.app.queryStore + .queryByType
(Section.Type) + .filter((section) => { + return ( + section.relationManage.getRelationsOfGraphicAndOtherType( + section, + AxleCounting.Type + ).length < 2 + ); + }); + + sections.forEach((section) => { + const sectionRelations = + section.relationManage.getRelationsOfGraphic(section); + const ps = section.localToCanvasPoint(section.getStartPoint()); + const pe = section.localToCanvasPoint(section.getEndPoint()); + sectionRelations.forEach((relation) => { + const port = relation.getRelationParam(section).param; + const refDevice = relation.getOtherGraphic
(section); + const refDevicePort = relation.getOtherRelationParam(section).param; + let direction = 1; + let axleCountingPs = ps; + if (port == 'B') { + axleCountingPs = pe; + } + if (axleCountingPs.y > height.y) { + direction = -1; + } + if ( + section.datas.sectionType === SectionType.Logic || + section.datas.children.includes(refDevice.id) + ) { + return; + } + if (refDevice.type == Section.Type || refDevice.type == Turnout.Type) + this.draw( + axleCountingPs, + direction, + section, + port, + map, + refDevice.type, + refDevice, + refDevicePort + ); + }); + }); + //由区段生成计轴--单独区段 + sections.forEach((section) => { + const axleCountingRelations = + section.relationManage.getRelationsOfGraphicAndOtherType( + section, + AxleCounting.Type + ); + const ps = section.localToCanvasPoint(section.getStartPoint()); + const pe = section.localToCanvasPoint(section.getEndPoint()); + if (axleCountingRelations.length < 2) { + axleCountingRelations.forEach((relation) => { + const port = relation.getRelationParam(section).param; + let addPort = SectionPort.A; + let direction = 1; + let axleCountingPs = ps; + if (port == 'A') { + axleCountingPs = pe; + addPort = SectionPort.B; + } + if (axleCountingPs.y > height.y) { + direction = -1; + } + if (axleCountingPs.y > height.y) { + direction = -1; + } + this.drawAdd(axleCountingPs, direction, section, addPort, map); + }); + } + }); + + //由道岔生成计轴--道岔和道岔 + const turnouts = this.app.queryStore + .queryByType(Turnout.Type) + .filter((turnout) => { + return ( + turnout.relationManage.getRelationsOfGraphicAndOtherType( + turnout, + AxleCounting.Type + ).length < 3 + ); + }); + turnouts.forEach((turnout) => { + const points = turnout.getPortPoints(); + //道岔关联的道岔 + const turnoutRelations = + turnout.relationManage.getRelationsOfGraphicAndOtherType( + turnout, + Turnout.Type + ); + turnoutRelations.forEach((relation) => { + const port = relation.getRelationParam(turnout).param; + const portIndex = DevicePort[port] as unknown as number; + const refTurnout = relation.getOtherGraphic(turnout); + const refTurnoutPort = relation.getOtherRelationParam(turnout).param; + const portPs = turnout.localToCanvasPoints(...points[portIndex])[ + points[portIndex].length - 1 + ]; + this.draw( + portPs, + 1, + turnout, + port, + map, + Turnout.Type, + refTurnout, + refTurnoutPort + ); + }); + }); + //由道岔生成计轴--单独道岔 + turnouts.forEach((turnout) => { + const axleCountingRelations = + turnout.relationManage.getRelationsOfGraphicAndOtherType( + turnout, + AxleCounting.Type + ); + const points = turnout.getPortPoints(); + const turnoutPort = [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C]; + if (axleCountingRelations.length == 1) { + const port = axleCountingRelations[0].getRelationParam(turnout).param; + const otherPort = turnoutPort.filter((p) => { + return p !== port && p; + }); + otherPort.forEach((port) => { + const portIndex = DevicePort[port] as unknown as number; + const axleCountingPs1 = turnout.localToCanvasPoints( + ...points[portIndex] + )[points[portIndex].length - 1]; + this.drawAdd(axleCountingPs1, 1, turnout, port, map); + }); + } else if (axleCountingRelations.length == 2) { + const port = axleCountingRelations.map( + (item) => item.getRelationParam(turnout).param + ); + const otherPort = turnoutPort.filter((p) => { + return p !== port[0] && p !== port[1] && p; + }); + if (otherPort.length) { + const portIndex = DevicePort[otherPort[0]] as unknown as number; + const axleCountingPs1 = turnout.localToCanvasPoints( + ...points[portIndex] + )[points[portIndex].length - 1]; + this.drawAdd(axleCountingPs1, 1, turnout, otherPort[0], map); + } + } else if (axleCountingRelations.length == 0) { + const axleCountingPsA = turnout.localToCanvasPoints(points[0][0])[0]; + const axleCountingPsC = turnout.localToCanvasPoints(points[2][0])[0]; + this.drawAdd(axleCountingPsA, 1, turnout, TurnoutPort.A, map); + this.drawAdd(axleCountingPsC, 1, turnout, TurnoutPort.C, map); + } + }); + } +} + +function buildAbsorbablePositions( + axleCounting: AxleCounting +): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const axleCountings = axleCounting.queryStore.queryByType( + AxleCounting.Type + ); + const { width } = axleCounting.getGraphicApp().canvas; + axleCountings.forEach((other) => { + if (other.id == axleCounting.id) { + return; + } + const ps = other.datas.transform.position; + const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y }); + aps.push(xs); + }); + return aps; +} + +export class AxleCountingInteraction extends GraphicInteractionPlugin { + static Name = 'AxleCounting_transform'; + constructor(app: JlDrawApp) { + super(AxleCountingInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new AxleCountingInteraction(app); + } + filter(...grahpics: JlGraphic[]): AxleCounting[] | undefined { + return grahpics + .filter((g) => g.type === AxleCounting.Type) + .map((g) => g as AxleCounting); + } + bind(g: AxleCounting): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.kilometerGraph.eventMode = 'static'; + g.kilometerGraph.cursor = 'pointer'; + g.kilometerGraph.draggable = true; + g.kilometerGraph.selectable = true; + g.kilometerGraph.transformSave = true; + g.on('selected', this.onSelected, this); + } + unbind(g: AxleCounting): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.kilometerGraph.eventMode = 'none'; + g.kilometerGraph.draggable = false; + g.kilometerGraph.selectable = false; + g.kilometerGraph.transformSave = false; + g.off('selected', this.onSelected, this); + } + onSelected(): void { + const AxleCounting = this.app.selectedGraphics[0] as AxleCounting; + this.app.setOptions({ + absorbablePositions: buildAbsorbablePositions(AxleCounting), + }); + } +} diff --git a/src/graphics/iscs-fan/IscsFan.ts b/src/graphics/iscs-fan/IscsFan.ts new file mode 100644 index 0000000..1c2df37 --- /dev/null +++ b/src/graphics/iscs-fan/IscsFan.ts @@ -0,0 +1,125 @@ +import { + GraphicAnimation, + GraphicData, + JlGraphic, + JlGraphicTemplate, +} from 'src/jl-graphic'; +import ISCS_FAN_Assets from './iscs-fan-spritesheet.png'; +import ISCS_FAN_JSON from './iscs-fan-data.json'; + +import { Assets, Sprite, Spritesheet, Texture } from 'pixi.js'; + +interface FanTextures { + border: Texture; + blue: Texture; + gray: Texture; + green: Texture; + red: Texture; + yellow: Texture; +} + +export interface IIscsFanData extends GraphicData { + get code(): string; + set code(v: string); +} + +export class IscsFan extends JlGraphic { + static Type = 'IscsFan'; + _border: Sprite; + _fan: Sprite; + fanTextures: FanTextures; + __state = 0; + + constructor(fanTextures: FanTextures) { + super(IscsFan.Type); + this.fanTextures = fanTextures; + this._border = new Sprite(); + this._border.texture = this.fanTextures.border; + this._border.anchor.set(0.5); + this._fan = new Sprite(); + this._fan.texture = this.fanTextures.gray; + this._fan.anchor.set(0.5); + this.addChild(this._border); + this.addChild(this._fan); + } + doRepaint(): void { + if (this.__state === 0) { + // 停止 + this.stopFanRun(); + this._fan.rotation = 0; + this._fan.texture = this.fanTextures.gray; + } else if (this.__state === 1) { + // 正常运行 + this._fan.texture = this.fanTextures.green; + // 动画 + this.initFanRun(); + } else if (this.__state === 2) { + // 报警运行 + this._fan.texture = this.fanTextures.yellow; + // 动画 + this.initFanRun(); + } else if (this.__state === 3) { + // 故障 + this.stopFanRun(); + this._fan.rotation = 0; + this._fan.texture = this.fanTextures.red; + } else if (this.__state === 4) { + // 通信故障 + // 停止 + this.stopFanRun(); + this._fan.rotation = 0; + this._fan.texture = this.fanTextures.blue; + } + } + initFanRun() { + // 动画 + const name = 'fan_run'; + let fanRun = this.animation(name); + if (!fanRun) { + fanRun = GraphicAnimation.init({ + name: 'fan_run', + run: (dt: number) => { + this._fan.angle = (this._fan.angle + dt) % 360; + }, + }); + this.addAnimation(fanRun); + } + const speed = Math.round(Math.random() * 10) + 1; + fanRun.xSpeed = speed; + fanRun.resume(); + } + stopFanRun() { + const name = 'fan_run'; + const fanRun = this.animation(name); + if (fanRun) { + fanRun.pause(); + } + } +} + +export class IscsFanTemplate extends JlGraphicTemplate { + fanTextures?: FanTextures; + constructor() { + super(IscsFan.Type, {}); + } + new(): IscsFan { + if (this.fanTextures) { + return new IscsFan(this.fanTextures); + } + throw new Error('资源未加载/加载失败'); + } + async loadAssets(): Promise { + const texture = await Assets.load(ISCS_FAN_Assets); + const iscsFanSheet = new Spritesheet(texture, ISCS_FAN_JSON); + const result = await iscsFanSheet.parse(); + this.fanTextures = { + border: result['fan-border.png'], + blue: result['fan-blue.png'], + gray: result['fan-gray.png'], + green: result['fan-green.png'], + red: result['fan-red.png'], + yellow: result['fan-yellow.png'], + }; + return this.fanTextures as FanTextures; + } +} diff --git a/src/graphics/iscs-fan/IscsFanDrawAssistant.ts b/src/graphics/iscs-fan/IscsFanDrawAssistant.ts new file mode 100644 index 0000000..709a37a --- /dev/null +++ b/src/graphics/iscs-fan/IscsFanDrawAssistant.ts @@ -0,0 +1,77 @@ +import { FederatedMouseEvent, Point } from 'pixi.js'; +import { + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; +import { IIscsFanData, IscsFan, IscsFanTemplate } from './IscsFan'; + +export class IscsFanDraw extends GraphicDrawAssistant< + IscsFanTemplate, + IIscsFanData +> { + _iscsFan: IscsFan | null = null; + + constructor(app: JlDrawApp) { + const template = new IscsFanTemplate(); + super(app, template, 'svguse:../drawIcon.svg#icon-fans', '风机'); + IscsFanInteraction.init(app); + } + + bind(): void { + super.bind(); + if (!this._iscsFan) { + this._iscsFan = this.graphicTemplate.new(); + this.container.addChild(this._iscsFan); + } + } + + public get iscsFan(): IscsFan { + if (!this._iscsFan) { + throw new Error('风机绘制逻辑异常'); + } + return this._iscsFan; + } + + redraw(cp: Point): void { + this.iscsFan.position.copyFrom(cp); + } + onLeftUp(e: FederatedMouseEvent): void { + this.iscsFan.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(false); + } + prepareData(data: IIscsFanData): boolean { + data.transform = this.iscsFan.saveTransform(); + return true; + } + onEsc(): void { + this.finish(); + } +} + +export class IscsFanInteraction extends GraphicInteractionPlugin { + static Name = 'iscs_fan_transform'; + constructor(app: JlDrawApp) { + super(IscsFanInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new IscsFanInteraction(app); + } + filter(...grahpics: JlGraphic[]): IscsFan[] | undefined { + return grahpics + .filter((g) => g.type === IscsFan.Type) + .map((g) => g as IscsFan); + } + bind(g: IscsFan): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + } + unbind(g: IscsFan): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + } +} diff --git a/src/graphics/iscs-fan/iscs-fan-data.json b/src/graphics/iscs-fan/iscs-fan-data.json new file mode 100644 index 0000000..5d2c674 --- /dev/null +++ b/src/graphics/iscs-fan/iscs-fan-data.json @@ -0,0 +1,66 @@ +{"frames": { + +"fan-blue.png": +{ + "frame": {"x":0,"y":0,"w":41,"h":41}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":41,"h":41}, + "sourceSize": {"w":41,"h":41}, + "anchor": {"x":0.5,"y":0.5} +}, +"fan-border.png": +{ + "frame": {"x":41,"y":0,"w":41,"h":41}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":41,"h":41}, + "sourceSize": {"w":41,"h":41}, + "anchor": {"x":0.5,"y":0.5} +}, +"fan-gray.png": +{ + "frame": {"x":82,"y":0,"w":41,"h":41}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":41,"h":41}, + "sourceSize": {"w":41,"h":41}, + "anchor": {"x":0.5,"y":0.5} +}, +"fan-green.png": +{ + "frame": {"x":123,"y":0,"w":41,"h":41}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":41,"h":41}, + "sourceSize": {"w":41,"h":41}, + "anchor": {"x":0.5,"y":0.5} +}, +"fan-red.png": +{ + "frame": {"x":164,"y":0,"w":41,"h":41}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":41,"h":41}, + "sourceSize": {"w":41,"h":41}, + "anchor": {"x":0.5,"y":0.5} +}, +"fan-yellow.png": +{ + "frame": {"x":205,"y":0,"w":41,"h":41}, + "rotated": false, + "trimmed": false, + "spriteSourceSize": {"x":0,"y":0,"w":41,"h":41}, + "sourceSize": {"w":41,"h":41}, + "anchor": {"x":0.5,"y":0.5} +}}, +"meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "1.1", + "image": "test-iscs-fan.png", + "format": "RGBA8888", + "size": {"w":246,"h":41}, + "scale": "1", + "smartupdate": "$TexturePacker:SmartUpdate:e7620bd2d73cc0b3e2deea9704e7eefc:f129a1d9e4b9ba57720b3861c22b155b:eb2d421f7759984b7713aa4aa5354134$" +} +} diff --git a/src/graphics/iscs-fan/iscs-fan-spritesheet.png b/src/graphics/iscs-fan/iscs-fan-spritesheet.png new file mode 100644 index 0000000000000000000000000000000000000000..adec75a7eeb1947842bad720e4c05c218c9584cd GIT binary patch literal 15944 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 jOTcyCEHyV0JQV(); + } + doRepaint(): void { + if (this.datas.points.length < 2) { + throw new Error('Link坐标数据异常'); + } + this.lineGraphic.clear(); + this.lineGraphic.lineStyle( + this.datas.lineWidth, + new Color(this.datas.lineColor) + ); + if (this.datas.curve) { + // 曲线 + const bps = convertToBezierParams(this.datas.points); + bps.forEach((bp) => { + this.lineGraphic.drawBezierCurve( + bp.p1, + bp.p2, + bp.cp1, + bp.cp2, + this.datas.segmentsCount + ); + }); + } else { + // 直线 + const start = this.getStartPoint(); + this.lineGraphic.moveTo(start.x, start.y); + for (let i = 0; i < this.datas.points.length; i++) { + const p = this.datas.points[i]; + this.lineGraphic.lineTo(p.x, p.y); + } + } + } + get linePoints(): IPointData[] { + return this.datas.points; + } + set linePoints(points: IPointData[]) { + const old = this.datas.clone(); + old.points = points; + this.updateData(old); + } + getStartPoint(): IPointData { + return this.datas.points[0]; + } + getEndPoint(): IPointData { + return this.datas.points[this.datas.points.length - 1]; + } +} + +export class LinkTemplate extends JlGraphicTemplate { + curve: boolean; + lineWidth: number; + lineColor: string; + segmentsCount: number; + constructor() { + super(Link.Type, {}); + this.lineWidth = 2; + this.lineColor = '#000000'; + this.curve = false; + this.segmentsCount = 10; + } + new(): Link { + return new Link(); + } +} diff --git a/src/graphics/link/LinkDrawAssistant.ts b/src/graphics/link/LinkDrawAssistant.ts new file mode 100644 index 0000000..353af5f --- /dev/null +++ b/src/graphics/link/LinkDrawAssistant.ts @@ -0,0 +1,336 @@ +import { + Color, + DisplayObject, + FederatedMouseEvent, + FederatedPointerEvent, + Graphics, + IHitArea, + Point, +} from 'pixi.js'; +import { + AbsorbablePosition, + DraggablePoint, + GraphicApp, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + JlDrawApp, + JlGraphic, + KeyListener, + calculateMirrorPoint, + convertToBezierParams, + linePoint, + pointPolygon, +} from 'src/jl-graphic'; +import AbsorbablePoint, { + AbsorbableCircle, +} from 'src/jl-graphic/graphic/AbsorbablePosition'; +import { + BezierCurveEditPlugin, + ILineGraphic, + PolylineEditPlugin, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import { ILinkData, Link, LinkTemplate } from './Link'; + +export interface ILinkDrawOptions { + newData: () => ILinkData; +} + +export class LinkDraw extends GraphicDrawAssistant { + points: Point[] = []; + graphic: Graphics = new Graphics(); + + // 快捷切曲线绘制 + keyqListener: KeyListener = new KeyListener({ + value: 'KeyQ', + global: true, + onPress: () => { + if (this.points.length == 0) { + this.graphicTemplate.curve = true; + } + }, + }); + // 快捷切直线绘制 + keyzListener: KeyListener = new KeyListener({ + value: 'KeyZ', + global: true, + onPress: () => { + if (this.points.length == 0) { + this.graphicTemplate.curve = false; + } + }, + }); + + constructor(app: JlDrawApp) { + super(app, new LinkTemplate(), 'sym_o_horizontal_rule', '轨道Link'); + this.container.addChild(this.graphic); + this.graphicTemplate.curve = true; + + LinkPointsEditPlugin.init(app); + } + + bind(): void { + super.bind(); + this.app.addKeyboardListener(this.keyqListener, this.keyzListener); + } + unbind(): void { + super.unbind(); + this.app.removeKeyboardListener(this.keyqListener, this.keyzListener); + } + + clearCache(): void { + this.points = []; + this.graphic.clear(); + } + onRightClick(): void { + this.createAndStore(true); + } + onLeftDown(e: FederatedPointerEvent): void { + const { x, y } = this.toCanvasCoordinates(e.global); + const p = new Point(x, y); + if (this.graphicTemplate.curve) { + if (this.points.length == 0) { + this.points.push(p); + } else { + this.points.push(p, p.clone()); + } + } else { + this.points.push(p); + } + } + onLeftUp(e: FederatedMouseEvent): void { + const template = this.graphicTemplate; + if (template.curve) { + const mp = this.toCanvasCoordinates(e.global); + if (this.points.length == 1) { + this.points.push(new Point(mp.x, mp.y)); + } else if (this.points.length > 1) { + const cp2 = this.points[this.points.length - 2]; + const p = this.points[this.points.length - 1]; + cp2.copyFrom(calculateMirrorPoint(p, mp)); + this.points.push(mp); + } + } + } + + redraw(p: Point): void { + if (this.points.length < 1) return; + this.graphic.clear(); + const template = this.graphicTemplate; + this.graphic.lineStyle(template.lineWidth, new Color(template.lineColor)); + const ps = [...this.points]; + if (template.curve) { + // 曲线 + if (ps.length == 1) { + this.graphic.moveTo(ps[0].x, ps[0].y); + this.graphic.lineTo(p.x, p.y); + } else { + if ((ps.length + 1) % 3 == 0) { + ps.push(p.clone(), p.clone()); + } else { + const cp = ps[ps.length - 2]; + const p1 = ps[ps.length - 1]; + const mp = calculateMirrorPoint(p1, p); + cp.copyFrom(mp); + } + + const bps = convertToBezierParams(ps); + bps.forEach((bp) => + this.graphic.drawBezierCurve( + bp.p1, + bp.p2, + bp.cp1, + bp.cp2, + template.segmentsCount + ) + ); + } + } else { + ps.push(p); + // 直线 + this.graphic.moveTo(ps[0].x, ps[0].y); + for (let i = 1; i < ps.length; i++) { + const p = ps[i]; + this.graphic.lineTo(p.x, p.y); + } + } + } + prepareData(data: ILinkData): boolean { + const template = this.graphicTemplate; + if ( + (!template.curve && this.points.length < 2) || + (template.curve && this.points.length < 4) + ) { + console.log('Link绘制因点不够取消绘制'); + return false; + } + if (template.curve) { + this.points.pop(); + } + data.curve = template.curve; + data.segmentsCount = template.segmentsCount; + data.points = this.points; + data.lineWidth = template.lineWidth; + data.lineColor = template.lineColor; + data.segmentsCount = template.segmentsCount; + return true; + } +} + +export class LinkGraphicHitArea implements IHitArea { + link: Link; + constructor(link: Link) { + this.link = link; + } + contains(x: number, y: number): boolean { + const p = new Point(x, y); + if (this.link.datas.curve) { + // 曲线 + const bps = convertToBezierParams(this.link.datas.points); + for (let i = 0; i < bps.length; i++) { + const bp = bps[i]; + if ( + pointPolygon( + p, + [bp.p1, bp.cp1, bp.cp2, bp.p2], + this.link.datas.lineWidth + ) + ) { + return true; + } + } + } else { + // 直线 + for (let i = 1; i < this.link.datas.points.length; i++) { + const p1 = this.link.datas.points[i - 1]; + const p2 = this.link.datas.points[i]; + if (linePoint(p1, p2, p, this.link.datas.lineWidth)) { + return true; + } + } + } + return false; + } +} + +/** + * 构建吸附位置 + * @param link + * @returns + */ +function buildAbsorbablePositions(link: Link): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const links = link.queryStore.queryByType(Link.Type); + links.forEach((other) => { + if (other.id == link.id) { + return; + } + const apa = new AbsorbablePoint( + other.localToCanvasPoint(other.getStartPoint()) + ); + const apb = new AbsorbablePoint( + other.localToCanvasPoint(other.getEndPoint()) + ); + aps.push(apa, apb); + }); + + aps.push(new AbsorbableCircle(new Point(450, 410), 30)); + + return aps; +} + +/** + * 端点拖拽添加吸附位置 + * @param g + * @param dp + * @param index + */ +function onEditPointCreate( + g: ILineGraphic, + dp: DraggablePoint, + index: number +): void { + const link = g as Link; + if (index === 0 || index == link.datas.points.length - 1) { + // 端点 + dp.on('transformstart', (e: GraphicTransformEvent) => { + if (e.isShift()) { + link.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(link), + }); + } + }); + } +} + +/** + * link路径编辑 + */ +export class LinkPointsEditPlugin extends GraphicInteractionPlugin { + static Name = 'LinkPointsDrag'; + constructor(app: GraphicApp) { + super(LinkPointsEditPlugin.Name, app); + } + static init(app: GraphicApp): LinkPointsEditPlugin { + return new LinkPointsEditPlugin(app); + } + filter(...grahpics: JlGraphic[]): Link[] | undefined { + return grahpics.filter((g) => g.type == Link.Type) as Link[]; + } + bind(g: Link): void { + g.lineGraphic.eventMode = 'static'; + g.lineGraphic.cursor = 'pointer'; + g.lineGraphic.hitArea = new LinkGraphicHitArea(g); + g.on('selected', this.onSelected, this); + g.on('unselected', this.onUnselected, this); + } + unbind(g: Link): void { + g.off('selected', this.onSelected, this); + g.off('unselected', this.onUnselected, this); + } + + onSelected(g: DisplayObject): void { + const link = g as Link; + let lep; + if (link.datas.curve) { + // 曲线 + lep = link.getAssistantAppend( + BezierCurveEditPlugin.Name + ); + if (!lep) { + lep = new BezierCurveEditPlugin(link, { + onEditPointCreate, + }); + link.addAssistantAppend(lep); + } + } else { + // 直线 + lep = link.getAssistantAppend( + PolylineEditPlugin.Name + ); + if (!lep) { + lep = new PolylineEditPlugin(link, { onEditPointCreate }); + link.addAssistantAppend(lep); + } + } + lep.showAll(); + } + onUnselected(g: DisplayObject): void { + const link = g as Link; + let lep; + if (link.datas.curve) { + // 曲线 + lep = link.getAssistantAppend( + BezierCurveEditPlugin.Name + ); + } else { + // 直线 + lep = link.getAssistantAppend( + PolylineEditPlugin.Name + ); + } + if (lep) { + lep.hideAll(); + } + } +} diff --git a/src/graphics/pathLine/PathLine.ts b/src/graphics/pathLine/PathLine.ts new file mode 100644 index 0000000..edfafd7 --- /dev/null +++ b/src/graphics/pathLine/PathLine.ts @@ -0,0 +1,159 @@ +import { JlGraphic, GraphicData, JlGraphicTemplate } from 'src/jl-graphic'; +import { Graphics, IPointData, Point } from 'pixi.js'; +import { RunLine } from '../runLine/RunLine'; +import { getDrawApp } from 'src/drawApp'; +// calculateDistanceFromPointToLine +import { calculateFootPointFromPointToLine, distance } from 'src/jl-graphic'; +import { StationLine } from '../stationLine/StationLine'; +export interface KilometerPoint { + get point(): IPointData; + set point(point: IPointData); + get kilometer(): number; + set kilometer(kilometer: number); + get stName(): string; + set stName(stName: string); +} +export interface IPathLineData extends GraphicData { + get code(): string; + set code(v: string); + get points(): IPointData[]; // 线坐标点 + set points(points: IPointData[]); + get isUp(): boolean; + set isUp(v: boolean); + get kilometerPoints(): KilometerPoint[]; + set kilometerPoints(kilometerPoints: KilometerPoint[]); + clone(): IPathLineData; + copyFrom(data: IPathLineData): void; + eq(other: IPathLineData): boolean; +} + +export const pathLineConsts = { + pathLineWidth: 1, + pathLineColor: '0Xff0000', +}; + +export class PathLine extends JlGraphic { + static Type = 'PathLine'; + pathLine: Graphics = new Graphics(); + constructor() { + super(PathLine.Type); + this.addChild(this.pathLine); + } + + get datas(): IPathLineData { + return this.getDatas(); + } + doRepaint(): void { + if (this.datas.points.length < 2) { + throw new Error('RunLine坐标数据异常'); + } + this.pathLine.clear(); + this.pathLine.lineStyle({ + width: pathLineConsts.pathLineWidth, + color: pathLineConsts.pathLineColor, + }); + const start = this.getStartPoint(); + this.pathLine.moveTo(start.x, start.y); + for (let i = 0; i < this.datas.points.length; i++) { + const p = this.datas.points[i]; + this.pathLine.lineTo(p.x, p.y); + } + } + + get linePoints(): IPointData[] { + return this.datas.points; + } + set linePoints(points: IPointData[]) { + const old = this.datas.clone(); + old.points = points; + this.updateData(old); + } + getStartPoint(): IPointData { + return this.datas.points[0]; + } + getEndPoint(): IPointData { + return this.datas.points[this.datas.points.length - 1]; + } + onDelete(): void { + super.onDelete(); + const pathLineId = this.datas.id; + const app = getDrawApp(); + if (!app) return; + const runLineList = app.queryStore.queryByType(RunLine.Type) as RunLine[]; + runLineList.find((runLine) => { + if (runLine.datas.linkPathLines.includes(pathLineId)) { + const list = [...runLine.datas.linkPathLines]; + const index = list.findIndex((item) => item === pathLineId); + list.splice(index, 1); + runLine.datas.linkPathLines = list; + return true; + } + }); + } + /** + * 计算stationLine在轨迹线上的垂足距离,计算stationLine与轨迹点距离,寻求最短且垂足在线段上 + * @param stas stationLine列表 + */ + generatePathLineKilometerPoints(stas: string[]) { + const kilometerPoints: KilometerPoint[] = []; + stas.forEach((stasId) => { + const sta = this.queryStore.queryById(stasId) as StationLine; + let fp: IPointData | null = null; + const sp = sta.position; + let minDistance = Number.MAX_SAFE_INTEGER; + this.datas.points.forEach((p, index) => { + if (index) { + const prep = this.datas.points[index - 1]; + const fpn = calculateFootPointFromPointToLine(prep, p, sp); + const distanceS = distance(prep.x, prep.y, p.x, p.y); + const fln = distance(fpn.x, fpn.y, sp.x, sp.y); + const distanceP = distance(p.x, p.y, sp.x, sp.y); + if ( + distance(fpn.x, fpn.y, prep.x, prep.y) <= distanceS && + distance(fpn.x, fpn.y, p.x, p.y) <= distanceS && + fln <= minDistance + ) { + minDistance = fln; + fp = fpn; + } + if (distanceP < minDistance) { + if (distanceP < minDistance) { + minDistance = distanceP; + fp = p; + } + } + } else { + const distanceP = distance(p.x, p.y, sp.x, sp.y); + if (distanceP < minDistance) { + minDistance = distanceP; + fp = p; + } + } + }); + if (sta.datas.code === '延平门') { + console.log(fp); + } + if (fp) { + kilometerPoints.push({ + point: new Point(fp?.['x'], fp?.['y']), + kilometer: 0, + stName: sta.datas.code, + }); + } + }); + this.datas.kilometerPoints = kilometerPoints; + } +} + +export class PathLineTemplate extends JlGraphicTemplate { + pathLineColor: string; + pathLineWidth: number; + constructor(dataTemplate: IPathLineData) { + super(PathLine.Type, { dataTemplate }); + this.pathLineColor = pathLineConsts.pathLineColor; + this.pathLineWidth = pathLineConsts.pathLineWidth; + } + new(): PathLine { + return new PathLine(); + } +} diff --git a/src/graphics/pathLine/PathLineDrawAssistant.ts b/src/graphics/pathLine/PathLineDrawAssistant.ts new file mode 100644 index 0000000..f1e000d --- /dev/null +++ b/src/graphics/pathLine/PathLineDrawAssistant.ts @@ -0,0 +1,219 @@ +import { + GraphicDrawAssistant, + JlDrawApp, + linePoint, + GraphicInteractionPlugin, + GraphicApp, + JlGraphic, + DraggablePoint, + GraphicTransformEvent, + calculateFootPointFromPointToLine, + calculateDistanceFromPointToLine, + distance, +} from 'src/jl-graphic'; +import { + IPathLineData, + PathLineTemplate, + PathLine, + pathLineConsts, +} from './PathLine'; +import { + Point, + Graphics, + LINE_JOIN, + IHitArea, + DisplayObject, + IPointData, +} from 'pixi.js'; +export interface IPathLineDrawOptions { + newData: () => IPathLineData; +} + +export class PathLineDraw extends GraphicDrawAssistant< + PathLineTemplate, + IPathLineData +> { + points: Point[] = []; + code = ''; + graphic: Graphics = new Graphics(); + + constructor(app: JlDrawApp, template: PathLineTemplate) { + super(app, template, 'sym_o_horizontal_rule', '不展示'); + this.container.addChild(this.graphic); + PathLinePointsEditPlugin.init(app); + } + clearCache(): void { + this.points = []; + this.code = ''; + this.graphic.clear(); + } + // onRightClick(): void { + // this.createAndStore(true); + // } + + // onLeftDown(e: FederatedPointerEvent): void { + // const { x, y } = this.toCanvasCoordinates(e.global); + // const p = new Point(x, y); + // this.points.push(p); + // } + quickCreate(points: Point[], lineId: string) { + this.points = [...points]; + this.code = lineId; + return this.createAndStore(true); + } + + redraw(p: Point): void { + if (this.points.length < 1) return; + this.graphic.clear(); + const template = this.graphicTemplate; + this.graphic.lineStyle({ + width: template.pathLineWidth, + color: template.pathLineColor, + join: LINE_JOIN.ROUND, + }); + const ps = [...this.points]; + ps.push(p); + // 直线 + this.graphic.moveTo(ps[0].x, ps[0].y); + for (let i = 1; i < ps.length; i++) { + const p = ps[i]; + this.graphic.lineTo(p.x, p.y); + } + } + prepareData(data: IPathLineData): boolean { + data.points = this.points; + return true; + } +} + +export class PathLineGraphicHitArea implements IHitArea { + pathLine: PathLine; + constructor(pathLine: PathLine) { + this.pathLine = pathLine; + } + contains(x: number, y: number): boolean { + const p = new Point(x, y); + for (let i = 1; i < this.pathLine.datas.points.length; i++) { + const p1 = this.pathLine.datas.points[i - 1]; + const p2 = this.pathLine.datas.points[i]; + if (linePoint(p1, p2, p, pathLineConsts.pathLineWidth)) { + return true; + } + } + return false; + } +} + +export class PathLinePointsEditPlugin extends GraphicInteractionPlugin { + static Name = 'LinkPointsDrag'; + constructor(app: GraphicApp) { + super(PathLinePointsEditPlugin.Name, app); + } + static init(app: GraphicApp): PathLinePointsEditPlugin { + return new PathLinePointsEditPlugin(app); + } + filter(...grahpics: JlGraphic[]): PathLine[] | undefined { + return grahpics.filter((g) => g.type == PathLine.Type) as PathLine[]; + } + bind(g: PathLine): void { + g.pathLine.eventMode = 'static'; + g.pathLine.cursor = 'pointer'; + g.pathLine.draggable = false; + g.pathLine.scalable = false; + g.pathLine.rotatable = false; + g.pathLine.hitArea = new PathLineGraphicHitArea(g); + g.on('selected', this.onSelected, this); + g.on('unselected', this.onUnselected, this); + } + unbind(g: PathLine): void { + g.off('selected', this.onSelected, this); + g.off('unselected', this.onUnselected, this); + } + + onSelected(g: DisplayObject): void { + const pathLine = g as PathLine; + pathLine.draggable = false; + pathLine.scalable = false; + pathLine.rotatable = false; + pathLine.datas.kilometerPoints.forEach((kp, index) => { + const dp = new DraggablePoint(kp.point); + dp.on( + 'transforming', + (e: GraphicTransformEvent) => { + this.movePointOnLine(pathLine.datas.points, e); + }, + this + ); + dp.on( + 'transformend', + (e: GraphicTransformEvent) => { + const kilometerPoints = [...pathLine.datas.kilometerPoints]; + kilometerPoints[index] = { + point: new Point(e.target.position.x, e.target.position.y), + kilometer: kilometerPoints[index].kilometer, + stName: kilometerPoints[index].stName, + }; + pathLine.datas.kilometerPoints = kilometerPoints; + }, + this + ); + pathLine.addChild(dp); + }); + } + onUnselected(g: DisplayObject): void { + const pathLine = g as PathLine; + if (pathLine.children.length > 1) { + pathLine.removeChildren(1); + } + } + kpTransforming(e: GraphicTransformEvent) { + console.log(e, '----'); + } + movePointOnLine(points: IPointData[], e: GraphicTransformEvent) { + let minDistance = Number.MAX_SAFE_INTEGER; + let fp = null; + const np = e.target.position; + for (let i = 0; i < points.length; i++) { + const distancep = distance(np.x, np.y, points[i].x, points[i].y); + if (i !== 0) { + const distanceF = calculateDistanceFromPointToLine( + points[i - 1], + points[i], + np + ); + const fpn = calculateFootPointFromPointToLine( + points[i - 1], + points[i], + np + ); + const distance1 = distance( + fpn.x, + fpn.y, + points[i - 1].x, + points[i - 1].y + ); + const distance2 = distance(fpn.x, fpn.y, points[i].x, points[i].y); + const distance3 = distance( + points[i - 1].x, + points[i - 1].y, + points[i].x, + points[i].y + ); + if (distancep < minDistance) { + minDistance = distancep; + fp = points[i]; + } + if (distanceF < minDistance && distance1 + distance2 <= distance3 + 1) { + minDistance = distanceF; + fp = fpn; + } + } else { + minDistance = distancep; + fp = points[i]; + } + } + if (fp) { + e.target.position.set(fp.x, fp.y); + } + } +} diff --git a/src/graphics/platform/Platform.ts b/src/graphics/platform/Platform.ts new file mode 100644 index 0000000..0b40a29 --- /dev/null +++ b/src/graphics/platform/Platform.ts @@ -0,0 +1,429 @@ +import { Color, Container, Graphics, Rectangle } from 'pixi.js'; +import { + GraphicData, + GraphicState, + JlGraphic, + JlGraphicTemplate, + VectorText, + getRectangleCenter, +} from 'src/jl-graphic'; + +export interface IPlatformData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get hasdoor(): boolean; // 是否有屏蔽门 + set hasdoor(v: boolean); + get direction(): string; // 屏蔽门上下 + set direction(v: string); + clone(): IPlatformData; + copyFrom(data: IPlatformData): void; + eq(other: IPlatformData): boolean; +} +export interface IPlatformState extends GraphicState { + get emergstop(): boolean; + set emergstop(v: boolean); + get trainberth(): boolean; + set trainberth(v: boolean); + get close(): boolean; + set close(v: boolean); + get upHold(): boolean; + set upHold(v: boolean); + get downHold(): boolean; + set downHold(v: boolean); + get upOccHold(): boolean; + set upOccHold(v: boolean); + get downOccHold(): boolean; + set downOccHold(v: boolean); + get psdOpen(): boolean; + set psdOpen(v: boolean); + get psdCut(): boolean; + set psdCut(v: boolean); + get upSkipstop(): boolean; + set upSkipstop(v: boolean); + get downSkipstop(): boolean; + set downSkipstop(v: boolean); + get upTrainSkipstop(): boolean; + set upTrainSkipstop(v: boolean); + get downTrainSkipstop(): boolean; + set downTrainSkipstop(v: boolean); + get nextSectionRunTime(): number; //下一区间运行时间 + set nextSectionRunTime(v: number); + get nextSectionRunLevel(): number; //下一区间运行等级 + set nextSectionRunLevel(v: number); + get stopTime(): number; //停站时间 + set stopTime(v: number); +} + +//站台颜色 +export enum PlatformColorEnum { + grey = '0x7F7F7F', //站台没有列车停站 + yellow = '0xfbff00', //列车在站台停站 + blue = '0xC0C0FE', //列车在站台跳停 + lozengeRed = '0xff0000', //站台旁的菱形图标 + whiteNumbers = '0xffffff', //站台旁白色数字 + whiteCircle = '0xffffff', //H字符旁的圆圈 + HCharYellow = '0xfbff00', //站台旁的H字符 + HCharWhite = '0xffffff', + HCharRed = '0xff0000', + doorGreen = '0x00FF00', //屏蔽门的颜色 + doorRed = '0xff0000', + doorBlue = '0x4048C4', +} + +const platformConsts = { + width: 90, + height: 20, + lineWidth: 3, + besideFontSize: 12, + doorOpenSpacing: 15, + doorPlatformSpacing: 10, + besideSpacing: 10, + circleRadius: 1, +}; + +//子元素--矩形 +export class rectGraphic extends Container { + static Type = 'RectPlatForm'; + rectGraphic: Graphics; + constructor() { + super(); + this.rectGraphic = new Graphics(); + this.addChild(this.rectGraphic); + } + draw(state: IPlatformState): void { + const rectGraphic = this.rectGraphic; + rectGraphic.clear(); + let fillColor = PlatformColorEnum.grey; + if (state.trainberth) { + fillColor = PlatformColorEnum.yellow; + } + if (state.upSkipstop || state.downSkipstop) { + fillColor = PlatformColorEnum.blue; + } + rectGraphic.lineStyle(platformConsts.lineWidth, new Color(fillColor)); + rectGraphic.beginFill(fillColor, 1); + rectGraphic.drawRect(0, 0, platformConsts.width, platformConsts.height); + rectGraphic.endFill; + const rectP = new Rectangle( + 0, + 0, + platformConsts.width, + platformConsts.height + ); + rectGraphic.pivot = getRectangleCenter(rectP); + } + clear(): void { + this.rectGraphic.clear(); + } +} +//子元素--门 +export class doorGraphic extends Container { + static Type = 'Door'; + doorGraphic: Graphics; + doorCloseGraphic: Graphics; + constructor() { + super(); + this.doorGraphic = new Graphics(); + this.doorCloseGraphic = new Graphics(); + this.addChild(this.doorGraphic); + this.addChild(this.doorCloseGraphic); + } + draw(stateData: IPlatformState): void { + const doorGraphic = this.doorGraphic; + const doorCloseGraphic = this.doorCloseGraphic; + doorGraphic.clear(); + doorCloseGraphic.clear(); + let lineColor = PlatformColorEnum.doorGreen; + if (stateData.psdCut) { + lineColor = PlatformColorEnum.doorRed; + } + doorGraphic.lineStyle(platformConsts.lineWidth, new Color(lineColor)); + doorGraphic.moveTo( + -platformConsts.width / 2 - platformConsts.lineWidth / 2, + 0 + ); + doorGraphic.lineTo(-platformConsts.doorOpenSpacing, 0); + doorGraphic.moveTo(platformConsts.doorOpenSpacing, 0); + doorGraphic.lineTo( + platformConsts.width / 2 + platformConsts.lineWidth / 2, + 0 + ); + //屏蔽门闭合 + doorCloseGraphic.lineStyle(platformConsts.lineWidth, new Color(lineColor)); + doorCloseGraphic.moveTo(-platformConsts.doorOpenSpacing, 0); + doorCloseGraphic.lineTo(platformConsts.doorOpenSpacing, 0); + doorGraphic.position.set( + 0, + -platformConsts.height / 2 - platformConsts.doorPlatformSpacing + ); + doorCloseGraphic.position.set( + 0, + -platformConsts.height / 2 - platformConsts.doorPlatformSpacing + ); + } + clear(): void { + this.doorGraphic.clear(); + this.doorCloseGraphic.clear(); + } + changeState(stateData: IPlatformState): void { + if (stateData.psdOpen) { + this.doorCloseGraphic.visible = false; + } else { + this.doorCloseGraphic.visible = true; + } + } +} +//子元素--字符 +class codeGraph extends Container { + static Type = 'Code'; + character: VectorText = new VectorText(''); //扣车H + runTime: VectorText = new VectorText(''); //运行时间 + stopTime: VectorText = new VectorText(''); //停站时间 + circle: Graphics = new Graphics(); + constructor() { + super(); + this.addChild(this.character); + this.addChild(this.runTime); + this.addChild(this.circle); + this.addChild(this.stopTime); + this.character.setVectorFontSize(platformConsts.besideFontSize); + this.runTime.setVectorFontSize(platformConsts.besideFontSize); + this.stopTime.setVectorFontSize(platformConsts.besideFontSize); + } + draw(): void { + //扣车 + const character = this.character; + character.text = 'H'; + character.anchor.set(0.5); + character.position.set( + -platformConsts.width / 2 - + platformConsts.lineWidth / 2 - + (platformConsts.besideSpacing * 2) / 3, + (platformConsts.height * 3) / 4 + ); + character.style.fill = PlatformColorEnum.whiteNumbers; + const circle = this.circle; + circle.clear(); + circle.lineStyle(0.5, PlatformColorEnum.whiteCircle); + circle.drawCircle(0, 0, platformConsts.circleRadius); + circle.position.set( + -platformConsts.width / 2 - + platformConsts.lineWidth / 2 - + (platformConsts.besideSpacing * 4) / 3, + (platformConsts.height * 3) / 5 + ); + //区间运行等级状态 + const runTime = this.runTime; + runTime.anchor.set(0.5); + runTime.position.set( + platformConsts.width / 2 + + platformConsts.lineWidth / 2 + + platformConsts.besideSpacing, + -platformConsts.besideSpacing + ); + runTime.style.fill = PlatformColorEnum.whiteNumbers; + //停站时间 + const stopTime = this.stopTime; + stopTime.anchor.set(0.5); + stopTime.position.set( + platformConsts.width / 2 + + platformConsts.lineWidth / 2 + + platformConsts.besideSpacing, + platformConsts.besideSpacing + ); + stopTime.style.fill = PlatformColorEnum.whiteNumbers; + character.visible = false; + circle.visible = false; + runTime.visible = false; + stopTime.visible = false; + } + clear(): void { + this.character.destroy(); + } + changeState(stateData: IPlatformState): void { + if ( + stateData.upHold || + stateData.upOccHold || + stateData.downHold || + stateData.downOccHold + ) { + this.character.text = 'H'; + this.character.visible = true; + this.circle.visible = true; + //上行扣车 + if (stateData.upHold) { + this.character.style.fill = PlatformColorEnum.HCharYellow; + } + if (stateData.upOccHold) { + this.character.style.fill = PlatformColorEnum.HCharWhite; + } + if (stateData.upHold && stateData.upOccHold) { + this.character.style.fill = PlatformColorEnum.HCharRed; + } + //下行扣车 + if (stateData.downHold) { + this.character.style.fill = PlatformColorEnum.HCharYellow; + } + if (stateData.downOccHold) { + this.character.style.fill = PlatformColorEnum.HCharWhite; + } + if (stateData.downHold && stateData.downOccHold) { + this.character.style.fill = PlatformColorEnum.HCharRed; + } + //运行等级 + if (stateData.nextSectionRunTime) { + this.runTime.visible = true; + this.runTime.text = stateData.nextSectionRunTime; + } + //停站时间 + if (stateData.stopTime) { + this.stopTime.visible = true; + this.stopTime.text = stateData.stopTime; + } + } + } +} +//子元素--站台旁菱形图标 +class besideGraphic extends Container { + static Type = 'BesideGraphic'; + besideGraphic: Graphics; + constructor() { + super(); + this.besideGraphic = new Graphics(); + this.addChild(this.besideGraphic); + } + draw(): void { + const besideGraphic = this.besideGraphic; + besideGraphic.clear(); + besideGraphic.lineStyle(1, new Color(PlatformColorEnum.lozengeRed)); + besideGraphic.beginFill(PlatformColorEnum.lozengeRed, 1); + besideGraphic.drawRect( + 0, + 0, + platformConsts.height / 4, + platformConsts.height / 4 + ); + besideGraphic.endFill(); + const rect = new Rectangle( + 0, + 0, + platformConsts.height / 4, + platformConsts.height / 4 + ); + besideGraphic.pivot = getRectangleCenter(rect); + besideGraphic.rotation = Math.PI / 4; + besideGraphic.position.set( + 0, + -platformConsts.height / 2 - + platformConsts.doorPlatformSpacing - + platformConsts.height / 3 + ); + besideGraphic.visible = false; + } + clear(): void { + this.besideGraphic.clear(); + } + changeState(stateData: IPlatformState): void { + if (stateData.emergstop) { + this.besideGraphic.visible = true; + } else { + this.besideGraphic.visible = false; + } + } +} + +export class Platform extends JlGraphic { + static Type = 'Platform'; + platformGraphic: rectGraphic = new rectGraphic(); + doorGraphic: doorGraphic = new doorGraphic(); + besideGraphic: besideGraphic = new besideGraphic(); + codeGraph: codeGraph = new codeGraph(); + constructor() { + super(Platform.Type); + this.addChild(this.platformGraphic); + this.addChild(this.doorGraphic); + this.addChild(this.besideGraphic); + this.addChild(this.codeGraph); + } + + get datas(): IPlatformData { + return this.getDatas(); + } + get states(): IPlatformState { + return this.getStates(); + } + doRepaint(): void { + this.doorGraphic.clear(); + if (this.datas.hasdoor) { + this.doorGraphic.draw(this.states); + } + this.platformGraphic.draw(this.states); + this.besideGraphic.draw(); + this.codeGraph.draw(); + this.doorGraphic.position.set(0, 0); + this.besideGraphic.position.set(0, 0); + this.codeGraph.position.set(0, 0); + //站台方向 + if (this.datas.direction == 'down') { + this.doorGraphic.position.set( + 0, + platformConsts.height + platformConsts.doorPlatformSpacing * 2 + ); + this.besideGraphic.position.set( + 0, + platformConsts.height + + platformConsts.doorPlatformSpacing * 2 + + (platformConsts.height * 2) / 3 + ); + this.codeGraph.children[0].position.set( + platformConsts.width / 2 + + platformConsts.lineWidth / 2 + + (platformConsts.besideSpacing * 2) / 3, + -(platformConsts.height * 3) / 4 + ); + this.codeGraph.children[1].position.set( + -platformConsts.width / 2 - + platformConsts.lineWidth / 2 - + platformConsts.besideSpacing, + platformConsts.besideSpacing + ); + this.codeGraph.children[2].position.set( + platformConsts.width / 2 + + platformConsts.lineWidth / 2 + + (platformConsts.besideSpacing * 4) / 3, + (-platformConsts.height * 10) / 11 + ); + this.codeGraph.children[3].position.set( + -platformConsts.width / 2 - + platformConsts.lineWidth / 2 - + platformConsts.besideSpacing, + -platformConsts.besideSpacing + ); + } + this.changeState(); + } + changeState(): void { + this.doorGraphic.changeState(this.states); + this.besideGraphic.changeState(this.states); + this.codeGraph.changeState(this.states); + } +} + +export class PlatformTemplate extends JlGraphicTemplate { + hasdoor: boolean; + direction: string; + constructor(dataTemplate: IPlatformData, stateTemplate: IPlatformState) { + super(Platform.Type, { + dataTemplate, + stateTemplate, + }); + this.hasdoor = true; + this.direction = 'up'; + } + new(): Platform { + const platform = new Platform(); + platform.loadData(this.datas); + platform.loadState(this.states); + return platform; + } +} diff --git a/src/graphics/platform/PlatformDrawAssistant.ts b/src/graphics/platform/PlatformDrawAssistant.ts new file mode 100644 index 0000000..b3dd181 --- /dev/null +++ b/src/graphics/platform/PlatformDrawAssistant.ts @@ -0,0 +1,119 @@ +import { FederatedPointerEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; + +import { + IPlatformData, + Platform, + PlatformTemplate, + rectGraphic, + doorGraphic, + IPlatformState, +} from './Platform'; + +export interface IPlatformDrawOptions { + newData: () => IPlatformData; +} + +export class PlatformDraw extends GraphicDrawAssistant< + PlatformTemplate, + IPlatformData +> { + platformGraphic: rectGraphic = new rectGraphic(); + doorGraphic: doorGraphic = new doorGraphic(); + + constructor(app: JlDrawApp, template: PlatformTemplate) { + super( + app, + template, + 'svguse:../../drawIcon.svg#icon-platform', + '站台Platform' + ); + this.container.addChild(this.platformGraphic); + this.container.addChild(this.doorGraphic); + platformInteraction.init(app); + } + + bind(): void { + super.bind(); + this.platformGraphic.draw(this.graphicTemplate.states as IPlatformState); + this.doorGraphic.draw(this.graphicTemplate.states as IPlatformState); + } + + clearCache(): void { + this.platformGraphic.clear(); + this.doorGraphic.clear(); + } + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + + prepareData(data: IPlatformData): boolean { + const template = this.graphicTemplate; + data.hasdoor = template.hasdoor; + data.direction = template.direction; + data.transform = this.container.saveTransform(); + return true; + } +} + +function buildAbsorbablePositions(platform: Platform): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const platforms = platform.queryStore.queryByType(Platform.Type); + const { width, height } = platform.getGraphicApp().canvas; + platforms.forEach((other) => { + if (other.id == platform.id) { + return; + } + const ps = other.datas.transform.position; + const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y }); + const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height }); + aps.push(xs, ys); + }); + return aps; +} + +export class platformInteraction extends GraphicInteractionPlugin { + static Name = 'platform_transform'; + constructor(app: JlDrawApp) { + super(platformInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new platformInteraction(app); + } + filter(...grahpics: JlGraphic[]): Platform[] | undefined { + return grahpics + .filter((g) => g.type === Platform.Type) + .map((g) => g as Platform); + } + bind(g: Platform): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.on('selected', this.onSelected, this); + } + unbind(g: Platform): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('selected', this.onSelected, this); + } + onSelected(): void { + const platform = this.app.selectedGraphics[0] as Platform; + this.app.setOptions({ + absorbablePositions: buildAbsorbablePositions(platform), + }); + } +} diff --git a/src/graphics/polygon/Polygon.ts b/src/graphics/polygon/Polygon.ts new file mode 100644 index 0000000..2b7be19 --- /dev/null +++ b/src/graphics/polygon/Polygon.ts @@ -0,0 +1,72 @@ +import { Color, Graphics, IPointData } from 'pixi.js'; +import { GraphicData, JlGraphic, JlGraphicTemplate } from 'src/jl-graphic'; + +export interface IPolygonData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get lineWidth(): number; // 线宽 + set lineWidth(v: number); + get lineColor(): string; // 线色 + set lineColor(v: string); + get points(): IPointData[]; // 多边形坐标点 + set points(points: IPointData[]); + clone(): IPolygonData; + copyFrom(data: IPolygonData): void; + eq(other: IPolygonData): boolean; +} + +const polygonConsts = { + lineWidth: 2, + lineColor: '0xff0000', +}; + +export class Polygon extends JlGraphic { + static Type = 'Polygon'; + polygonGraphic: Graphics; + constructor() { + super(Polygon.Type); + this.polygonGraphic = new Graphics(); + this.addChild(this.polygonGraphic); + } + + get datas(): IPolygonData { + return this.getDatas(); + } + doRepaint(): void { + const polygonGraphic = this.polygonGraphic; + polygonGraphic.clear(); + polygonGraphic.lineStyle( + this.datas.lineWidth, + new Color(this.datas.lineColor) + ); + polygonGraphic.drawPolygon(this.datas.points); + } + get linePoints(): IPointData[] { + return this.datas.points; + } + set linePoints(points: IPointData[]) { + const old = this.datas.clone(); + old.points = points; + this.updateData(old); + } + addOnePoints(): IPointData[] { + const ps = [...this.datas.points]; + ps.push(this.datas.points[0]); + return ps; + } +} + +export class PolygonTemplate extends JlGraphicTemplate { + lineWidth: number; + lineColor: string; + constructor(dataTemplate: IPolygonData) { + super(Polygon.Type, { + dataTemplate, + }); + this.lineWidth = polygonConsts.lineWidth; + this.lineColor = polygonConsts.lineColor; + } + new(): Polygon { + return new Polygon(); + } +} diff --git a/src/graphics/polygon/PolygonDrawAssistant.ts b/src/graphics/polygon/PolygonDrawAssistant.ts new file mode 100644 index 0000000..34b853e --- /dev/null +++ b/src/graphics/polygon/PolygonDrawAssistant.ts @@ -0,0 +1,195 @@ +import { + FederatedPointerEvent, + Graphics, + Point, + IHitArea, + DisplayObject, +} from 'pixi.js'; +import { + DraggablePoint, + GraphicApp, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + JlDrawApp, + JlGraphic, + linePoint, +} from 'src/jl-graphic'; + +import AbsorbablePoint, { + AbsorbablePosition, +} from 'src/jl-graphic/graphic/AbsorbablePosition'; +import { + ILineGraphic, + PolylineEditPlugin, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; + +import { IPolygonData, Polygon, PolygonTemplate } from './Polygon'; + +export interface IPolygonDrawOptions { + newData: () => IPolygonData; +} + +export class PolygonDraw extends GraphicDrawAssistant< + PolygonTemplate, + IPolygonData +> { + points: Point[] = []; + polygonGraphic: Graphics = new Graphics(); + + constructor(app: JlDrawApp, template: PolygonTemplate) { + super(app, template, 'sym_o_square', '多边形Polygon'); + this.container.addChild(this.polygonGraphic); + PolygonPointsEditPlugin.init(app); + } + + clearCache(): void { + this.points = []; + this.polygonGraphic.clear(); + } + onLeftDown(e: FederatedPointerEvent): void { + const { x, y } = this.toCanvasCoordinates(e.global); + const p = new Point(x, y); + this.points.push(p); + } + onRightClick(): void { + this.createAndStore(true); + } + redraw(p: Point): void { + if (this.points.length < 1) return; + const polygonGraphic = this.polygonGraphic; + const template = this.graphicTemplate; + const ps = [...this.points]; + ps.push(p); + polygonGraphic.clear(); + polygonGraphic.lineStyle(template.lineWidth, template.lineColor); + polygonGraphic.drawPolygon(ps); + } + + prepareData(data: IPolygonData): boolean { + if (this.points.length < 2) { + console.log('Polygon绘制因点不够取消绘制'); + return false; + } + const template = this.graphicTemplate; + data.lineWidth = template.lineWidth; + data.lineColor = template.lineColor; + data.points = this.points; + return true; + } +} + +//碰撞检测 +export class PolygonGraphicHitArea implements IHitArea { + polygon: Polygon; + constructor(polygon: Polygon) { + this.polygon = polygon; + } + contains(x: number, y: number): boolean { + let contains = false; + const p = new Point(x, y); + const polygonData = this.polygon.datas; + //contains = pointPolygon(p, polygonData.points, polygonData.lineWidth);是否包含多边形内部 + const ps = this.polygon.addOnePoints(); + const tolerance = polygonData.lineWidth; + for (let i = 0; i < ps.length - 1; i++) { + const p1 = ps[i]; + const p2 = ps[i + 1]; + contains = contains || linePoint(p1, p2, p, tolerance); + if (contains) { + break; + } + } + return contains; + } +} + +/** + * 构建吸附位置 + * @param polygon + * @returns + */ +function buildAbsorbablePositions(polygon: Polygon): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const polygons = polygon.queryStore.queryByType(Polygon.Type); + + polygons.forEach((other) => { + if (other.id == polygon.id) { + return; + } + other.linePoints.forEach((point) => { + const absorbablePoint = new AbsorbablePoint( + other.localToCanvasPoint(point) + ); + aps.push(absorbablePoint); + }); + }); + + return aps; +} + +/** + * 端点拖拽添加吸附位置 + * @param g + * @param dp + * @param index + */ +function onEditPointCreate(g: ILineGraphic, dp: DraggablePoint): void { + const polygon = g as Polygon; + // 端点 + dp.on('transformstart', (e: GraphicTransformEvent) => { + if (e.isShift()) { + polygon.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(polygon), + }); + } + }); +} + +/** + * polygon路径编辑 + */ +export class PolygonPointsEditPlugin extends GraphicInteractionPlugin { + static Name = 'PolygonPointsDrag'; + constructor(app: GraphicApp) { + super(PolygonPointsEditPlugin.Name, app); + } + static init(app: GraphicApp): PolygonPointsEditPlugin { + return new PolygonPointsEditPlugin(app); + } + filter(...grahpics: JlGraphic[]): Polygon[] | undefined { + return grahpics.filter((g) => g.type == Polygon.Type) as Polygon[]; + } + bind(g: Polygon): void { + g.polygonGraphic.eventMode = 'static'; + g.polygonGraphic.cursor = 'pointer'; + g.polygonGraphic.hitArea = new PolygonGraphicHitArea(g); + g.on('selected', this.onSelected, this); + g.on('unselected', this.onUnselected, this); + } + unbind(g: Polygon): void { + g.off('selected', this.onSelected, this); + g.off('unselected', this.onUnselected, this); + } + + onSelected(g: DisplayObject): void { + const polygon = g as Polygon; + let lep = polygon.getAssistantAppend( + PolylineEditPlugin.Name + ); + if (!lep) { + lep = new PolylineEditPlugin(polygon, { onEditPointCreate }); + polygon.addAssistantAppend(lep); + } + lep.showAll(); + } + onUnselected(g: DisplayObject): void { + const polygon = g as Polygon; + const lep = polygon.getAssistantAppend( + PolylineEditPlugin.Name + ); + if (lep) { + lep.hideAll(); + } + } +} diff --git a/src/graphics/polygon/PolygonUtils.ts b/src/graphics/polygon/PolygonUtils.ts new file mode 100644 index 0000000..a98f92d --- /dev/null +++ b/src/graphics/polygon/PolygonUtils.ts @@ -0,0 +1,90 @@ +import { IPointData, Point } from 'pixi.js'; +import { + calculateDistanceFromPointToLine, + calculateFootPointFromPointToLine, +} from 'src/jl-graphic'; +import { Polygon } from './Polygon'; + +//计算线段细分坐标--线段分成几份 +export function getLineSegmentPoints( + startPoint: IPointData, + endPoint: IPointData, + knife: number +) { + const segmentLength = Math.sqrt( + Math.pow(endPoint.x - startPoint.x, 2) + + Math.pow(endPoint.y - startPoint.y, 2) + ); + const segmentIncrement = segmentLength / knife; + const segmentAngle = Math.atan2( + endPoint.y - startPoint.y, + endPoint.x - startPoint.x + ); + + const points: IPointData[] = []; + for (let i = 1; i < knife; i++) { + const segmentPosition = i * segmentIncrement; + const x = startPoint.x + segmentPosition * Math.cos(segmentAngle); + const y = startPoint.y + segmentPosition * Math.sin(segmentAngle); + points.push(new Point(x, y)); + } + + return points; +} + +//获取所选线段的索引 +export function getWayLineIndex( + points: IPointData[], + p: IPointData +): { start: number; end: number } { + let start = 0; + let end = 0; + let minDistance = 0; + for (let i = 1; i < points.length; i++) { + const sp = points[i - 1]; + const ep = points[i]; + let distance = calculateDistanceFromPointToLine(sp, ep, p); + distance = Math.round(distance * 100) / 100; + if (i == 1) { + minDistance = distance; + } + if (distance == minDistance) { + const minX = Math.min(sp.x, ep.x); + const maxX = Math.max(sp.x, ep.x); + const minY = Math.min(sp.y, ep.y); + const maxY = Math.max(sp.y, ep.y); + const point = calculateFootPointFromPointToLine(sp, ep, p); + if ( + point.x >= minX && + point.x <= maxX && + point.y >= minY && + point.y <= maxY + ) { + start = i - 1; + } + } + if (distance < minDistance) { + minDistance = distance; + start = i - 1; + } + } + end = start + 1; + return { start, end }; +} + +//添加细分的点的坐标 +export function addPolygonSegmentingPoint( + graphic: Polygon, + start: number, + end: number, + knife = 2 +) { + const linePoints = graphic.addOnePoints(); + const points = linePoints.slice(0, start + 1); + points.push( + ...getLineSegmentPoints(linePoints[start], linePoints[end], knife) + ); + points.push(...linePoints.slice(end)); + points.pop(); + graphic.linePoints = points; +} diff --git a/src/graphics/rect/Rect.ts b/src/graphics/rect/Rect.ts new file mode 100644 index 0000000..feac981 --- /dev/null +++ b/src/graphics/rect/Rect.ts @@ -0,0 +1,99 @@ +import { Color, Graphics, IPointData, Point, Rectangle } from 'pixi.js'; +import { + GraphicData, + JlGraphic, + JlGraphicTemplate, + getRectangleCenter, +} from 'src/jl-graphic'; + +export interface IRectData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get lineWidth(): number; // 线宽 + set lineWidth(v: number); + get lineColor(): string; // 线色 + set lineColor(v: string); + get point(): IPointData; // 位置坐标 + set point(point: IPointData); + get width(): number; // 宽度 + set width(v: number); + get height(): number; // 高度 + set height(v: number); + get radius(): number; // 圆角半径 + set radius(v: number); + clone(): IRectData; + copyFrom(data: IRectData): void; + eq(other: IRectData): boolean; +} + +const rectConsts = { + lineWidth: 2, + lineColor: '0xff0000', +}; + +export class Rect extends JlGraphic { + static Type = 'Rect'; + rectGraphic: Graphics = new Graphics(); + constructor() { + super(Rect.Type); + this.addChild(this.rectGraphic); + } + + get datas(): IRectData { + return this.getDatas(); + } + doRepaint(): void { + const rectGraphic = this.rectGraphic; + rectGraphic.clear(); + rectGraphic.lineStyle( + this.datas.lineWidth, + new Color(this.datas.lineColor) + ); + const radius = this.datas?.radius || 0; + rectGraphic.drawRoundedRect( + 0, + 0, + this.datas.width, + this.datas.height, + radius + ); + rectGraphic.pivot = getRectangleCenter( + new Rectangle(0, 0, this.datas.width, this.datas.height) + ); + const transformPos = this.datas.transform.position; + if (transformPos.x == 0 && transformPos.y == 0) { + this.position.set( + this.datas.point.x + this.datas.width / 2, + this.datas.point.y + this.datas.height / 2 + ); + } else { + this.position.set( + this.datas.transform.position.x, + this.datas.transform.position.y + ); + } + } + rectPoints(): IPointData[] { + const r1 = new Point(this.datas.point.x, this.datas.point.y); + const r2 = new Point(r1.x + this.datas.width, r1.y); + const r3 = new Point(r1.x + this.datas.width, r1.y + this.datas.height); + const r4 = new Point(r1.x, r1.y + this.datas.height); + const rectPoints = [r1, r2, r3, r4, r1]; + return rectPoints; + } +} + +export class RectTemplate extends JlGraphicTemplate { + lineWidth: number; + lineColor: string; + constructor(dataTemplate: IRectData) { + super(Rect.Type, { + dataTemplate, + }); + this.lineWidth = rectConsts.lineWidth; + this.lineColor = rectConsts.lineColor; + } + new(): Rect { + return new Rect(); + } +} diff --git a/src/graphics/rect/RectDrawAssistant.ts b/src/graphics/rect/RectDrawAssistant.ts new file mode 100644 index 0000000..ea454e4 --- /dev/null +++ b/src/graphics/rect/RectDrawAssistant.ts @@ -0,0 +1,120 @@ +import { FederatedPointerEvent, Graphics, Point, IHitArea } from 'pixi.js'; +import { + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, + linePoint, +} from 'src/jl-graphic'; + +import { IRectData, Rect, RectTemplate } from './Rect'; + +export interface IRectDrawOptions { + newData: () => IRectData; +} + +export class RectDraw extends GraphicDrawAssistant { + point1: Point | null = null; + point2: Point | null = null; + rectGraphic: Graphics = new Graphics(); + + constructor(app: JlDrawApp, template: RectTemplate) { + super(app, template, 'sym_o_square', '矩形Rect'); + this.container.addChild(this.rectGraphic); + rectInteraction.init(app); + } + + clearCache(): void { + this.rectGraphic.clear(); + } + onLeftDown(e: FederatedPointerEvent): void { + const { x, y } = this.toCanvasCoordinates(e.global); + const p = new Point(x, y); + if (this.point1 === null) { + this.point1 = p; + } else { + this.point2 = p; + this.createAndStore(true); + this.point1 = null; + this.point2 = null; + } + } + + redraw(p: Point): void { + const template = this.graphicTemplate; + if (this.point1 === null) return; + const rectGraphic = this.rectGraphic; + rectGraphic.clear(); + rectGraphic.lineStyle(template.lineWidth, template.lineColor); + rectGraphic.drawRect(...this.normalize(this.point1, p)); + } + //根据画的两个点确定左上角的点的坐标和矩形宽高 + private normalize(p1: Point, p2: Point): [number, number, number, number] { + const { abs } = Math; + const x = p1.x < p2.x ? p1.x : p2.x; + const y = p1.y < p2.y ? p1.y : p2.y; + const w = abs(p1.x - p2.x); + const h = abs(p1.y - p2.y); + return [x, y, w, h]; + } + prepareData(data: IRectData): boolean { + const p1 = this.point1 as Point; + const p2 = this.point2 as Point; + const [x, y, width, height] = this.normalize(p1, p2); + const template = this.graphicTemplate; + data.point = new Point(x, y); + data.lineWidth = template.lineWidth; + data.lineColor = template.lineColor; + data.width = width; + data.height = height; + return true; + } +} + +//碰撞检测 +export class RectGraphicHitArea implements IHitArea { + rect: Rect; + constructor(rect: Rect) { + this.rect = rect; + } + contains(x: number, y: number): boolean { + let contains = false; + const datas = this.rect.datas; + const tolerance = datas.lineWidth; + const p1 = new Point(0, 0); + const p2 = new Point(p1.x + datas.width, p1.y); + const p3 = new Point(p1.x + datas.width, p1.y + datas.height); + const p4 = new Point(p1.x, p1.y + datas.height); + const p = new Point(x, y); + contains = contains || linePoint(p1, p2, p, tolerance); + contains = contains || linePoint(p2, p3, p, tolerance); + contains = contains || linePoint(p3, p4, p, tolerance); + contains = contains || linePoint(p4, p1, p, tolerance); + return contains; + } +} + +export class rectInteraction extends GraphicInteractionPlugin { + static Name = 'platform_transform'; + constructor(app: JlDrawApp) { + super(rectInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new rectInteraction(app); + } + filter(...grahpics: JlGraphic[]): Rect[] | undefined { + return grahpics.filter((g) => g.type === Rect.Type).map((g) => g as Rect); + } + bind(g: Rect): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.rectGraphic.hitArea = new RectGraphicHitArea(g); + } + unbind(g: Rect): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + } +} diff --git a/src/graphics/runLine/RunLine.ts b/src/graphics/runLine/RunLine.ts new file mode 100644 index 0000000..d202292 --- /dev/null +++ b/src/graphics/runLine/RunLine.ts @@ -0,0 +1,292 @@ +import { Graphics, IPointData, LINE_JOIN, Point } from 'pixi.js'; +import { + GraphicData, + JlGraphic, + JlGraphicTemplate, + getNormalVector, + movePointAlongNormal, + getIntersectionPoint, + distance, +} from 'src/jl-graphic'; +import { RunLineName } from './RunLineName'; +import { PathLine } from '../pathLine/PathLine'; +import { PathLineDraw } from '../pathLine/PathLineDrawAssistant'; +import { getDrawApp } from 'src/drawApp'; +import { StationLine } from '../stationLine/StationLine'; +import { calculateDistanceFromPointToLine } from 'src/jl-graphic'; + +export interface IRunLineData extends GraphicData { + get code(): string; + set code(v: string); + get points(): IPointData[]; // 线坐标点 + set points(points: IPointData[]); + get nameColor(): string; + set nameColor(v: string); + get nameBgColor(): string; + set nameBgColor(v: string); + get containSta(): string[]; + set containSta(v: string[]); + get linkPathLines(): string[]; + set linkPathLines(v: string[]); + get lineId(): string; + set lineId(v: string); + + clone(): IRunLineData; + copyFrom(data: IRunLineData): void; + eq(other: IRunLineData): boolean; +} + +export enum RunLineColorEnum { + runLineColor = '0XC1F467', +} + +export const runLineConsts = { + runLineWidth: 6, + nameFontSize: 16, + nameOffsetX: 40, + pathLineDistance: 10, +}; + +export class RunLine extends JlGraphic { + static Type = 'RunLine'; + lineBody: Graphics = new Graphics(); + leftRunLineName: RunLineName = new RunLineName(); + rightRunLineName: RunLineName = new RunLineName(); + + constructor() { + super(RunLine.Type); + this.leftRunLineName.name = 'leftRunLineName'; + this.rightRunLineName.name = 'rightRunLineName'; + this.addChild(this.lineBody); + this.addChild(this.leftRunLineName); + this.addChild(this.rightRunLineName); + } + get datas(): IRunLineData { + return this.getDatas(); + } + + doRepaint(): void { + if (this.datas.points.length < 2) { + throw new Error('RunLine坐标数据异常'); + } + this.lineBody.clear(); + this.lineBody.lineStyle({ + width: runLineConsts.runLineWidth, + color: RunLineColorEnum.runLineColor, + join: LINE_JOIN.ROUND, + }); + const start = this.getStartPoint(); + this.lineBody.moveTo(start.x, start.y); + for (let i = 0; i < this.datas.points.length; i++) { + const p = this.datas.points[i]; + this.lineBody.lineTo(p.x, p.y); + } + + this.leftRunLineName.paint( + this.getStartPoint().x - runLineConsts.nameOffsetX, + this.getStartPoint().y, + this.datas + ); + + this.rightRunLineName.paint( + this.getEndPoint().x + runLineConsts.nameOffsetX, + this.getEndPoint().y, + this.datas + ); + } + get linePoints(): IPointData[] { + return this.datas.points; + } + set linePoints(points: IPointData[]) { + const old = this.datas.clone(); + old.points = points; + this.updateData(old); + } + + generatePathLine(points: Point[]) { + const pointsUp: Point[] = []; + const pointsDown: Point[] = []; + points.forEach((p, index) => { + // 起始点终止点计算两点法向量 做平移计算,中间点做线段法向量平移就交点 + if (index === 0) { + const normalVector = getNormalVector(p, points[index + 1]); + const resverNormalVector = [-normalVector[0], -normalVector[1]]; + pointsUp.push( + movePointAlongNormal(p, normalVector, runLineConsts.pathLineDistance) + ); + pointsDown.push( + movePointAlongNormal( + p, + resverNormalVector, + runLineConsts.pathLineDistance + ) + ); + } else if (index === points.length - 1) { + const normalVector = getNormalVector(points[index - 1], p); + const resverNormalVector = [-normalVector[0], -normalVector[1]]; + pointsUp.push( + movePointAlongNormal(p, normalVector, runLineConsts.pathLineDistance) + ); + pointsDown.push( + movePointAlongNormal( + p, + resverNormalVector, + runLineConsts.pathLineDistance + ) + ); + } else { + const normalVector1 = getNormalVector(p, points[index + 1]); + const resverNormalVector1 = [-normalVector1[0], -normalVector1[1]]; + const curP1 = movePointAlongNormal( + p, + normalVector1, + runLineConsts.pathLineDistance + ); + const nextP1 = movePointAlongNormal( + points[index + 1], + normalVector1, + runLineConsts.pathLineDistance + ); + const resverCurP1 = movePointAlongNormal( + p, + resverNormalVector1, + runLineConsts.pathLineDistance + ); + const resverNextP1 = movePointAlongNormal( + points[index + 1], + resverNormalVector1, + runLineConsts.pathLineDistance + ); + + const normalVector2 = getNormalVector(points[index - 1], p); + const resverNormalVector2 = [-normalVector2[0], -normalVector2[1]]; + + const curP2 = movePointAlongNormal( + p, + normalVector2, + runLineConsts.pathLineDistance + ); + const nextP2 = movePointAlongNormal( + points[index - 1], + normalVector2, + runLineConsts.pathLineDistance + ); + const resverCurP2 = movePointAlongNormal( + p, + resverNormalVector2, + runLineConsts.pathLineDistance + ); + const resverNextP2 = movePointAlongNormal( + points[index - 1], + resverNormalVector2, + runLineConsts.pathLineDistance + ); + pointsUp.push( + getIntersectionPoint( + [curP1.x, curP1.y, nextP1.x, nextP1.y], + [curP2.x, curP2.y, nextP2.x, nextP2.y] + ) + ); + pointsDown.push( + getIntersectionPoint( + [resverCurP1.x, resverCurP1.y, resverNextP1.x, resverNextP1.y], + [resverCurP2.x, resverCurP2.y, resverNextP2.x, resverNextP2.y] + ) + ); + } + }); + const app = getDrawApp(); + if (!app) return; + const pathLineDrawAssistant = app.getDrawAssistant( + PathLine.Type + ) as PathLineDraw; + if (this.datas.linkPathLines.length) { + } + this.datas.linkPathLines.forEach((item) => { + const oldUp = app.queryStore.queryById(item); + if (oldUp) { + app.deleteGraphics(oldUp); + } + }); + const pathLineUp = pathLineDrawAssistant.quickCreate( + pointsUp, + this.datas.lineId + ); + const pathLineDown = pathLineDrawAssistant.quickCreate( + pointsDown, + this.datas.lineId + ); + this.datas.linkPathLines = [pathLineUp?.id || '', pathLineDown?.id || '']; + this.generatePathLineKilometerPoints(); + } + + getStartPoint(): IPointData { + return this.datas.points[0]; + } + getEndPoint(): IPointData { + return this.datas.points[this.datas.points.length - 1]; + } + onDelete(): void { + super.onDelete(); + const app = getDrawApp(); + if (!app) return; + this.datas.linkPathLines.forEach((item) => { + const oldUp = app.queryStore.queryById(item); + if (oldUp) { + app.deleteGraphics(oldUp); + } + }); + } + generateContainSta(): void { + const app = getDrawApp(); + if (!app) return; + const stations = app.queryStore.queryByType(StationLine.Type); + const containSta: string[] = []; + this.datas.points.forEach((p, index) => { + if (index) { + stations.forEach((station) => { + const sp = station.position; + const prep = this.datas.points[index - 1]; + const distanceF = calculateDistanceFromPointToLine( + p, + this.datas.points[index - 1], + station.position + ); + const distance1 = distance(sp.x, sp.y, prep.x, prep.y); + const distance2 = distance(sp.x, sp.y, p.x, p.y); + const distance3 = distance(p.x, p.y, prep.x, prep.y); + if ( + distanceF < 4 && + distance1 <= distance3 + distanceF && + distance2 <= distance3 + distanceF && + !containSta.includes(station.id) + ) { + containSta.push(station.id); + } + }); + } + }); + this.datas.containSta = containSta; + } + generatePathLineKilometerPoints(): void { + const app = getDrawApp(); + if (!app) return; + this.datas.linkPathLines.forEach((item) => { + const pathLine = app.queryStore.queryById(item) as PathLine; + pathLine.generatePathLineKilometerPoints(this.datas.containSta); + }); + } +} + +export class RunLineTemplate extends JlGraphicTemplate { + runLineColor: string; + runLineWidth: number; + constructor(dataTemplate: IRunLineData) { + super(RunLine.Type, { dataTemplate }); + this.runLineColor = RunLineColorEnum.runLineColor; + this.runLineWidth = runLineConsts.runLineWidth; + } + new(): RunLine { + return new RunLine(); + } +} diff --git a/src/graphics/runLine/RunLineDrawAssistant.ts b/src/graphics/runLine/RunLineDrawAssistant.ts new file mode 100644 index 0000000..914e690 --- /dev/null +++ b/src/graphics/runLine/RunLineDrawAssistant.ts @@ -0,0 +1,232 @@ +import { + GraphicDrawAssistant, + JlDrawApp, + JlGraphic, + GraphicInteractionPlugin, + linePoint, + GraphicApp, + AbsorbablePosition, + DraggablePoint, + GraphicTransformEvent, +} from 'src/jl-graphic'; +import { + IRunLineData, + RunLine, + RunLineTemplate, + runLineConsts, +} from './RunLine'; +import { + PolylineEditPlugin, + ILineGraphic, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import { + FederatedPointerEvent, + Point, + Graphics, + LINE_JOIN, + IHitArea, + DisplayObject, +} from 'pixi.js'; +import { AbsorbableLine } from 'src/jl-graphic/graphic/AbsorbablePosition'; + +export interface IRunLineDrawOptions { + newData: () => IRunLineData; +} + +export class RunLineDraw extends GraphicDrawAssistant< + RunLineTemplate, + IRunLineData +> { + points: Point[] = []; + graphic: Graphics = new Graphics(); + + constructor(app: JlDrawApp, template: RunLineTemplate) { + super(app, template, 'sym_o_horizontal_rule', '运行线RunLine'); + this.container.addChild(this.graphic); + RunLinePointsEditPlugin.init(app); + } + + clearCache(): void { + this.points = []; + this.graphic.clear(); + } + onRightClick(): void { + if (this.points.length > 1) this.createAndStore(true); + } + onEsc() { + if (this.points.length > 1) this.createAndStore(true); + } + // createAndStore(); + onLeftDown(e: FederatedPointerEvent): void { + const { x, y } = this.toCanvasCoordinates(e.global); + const p = new Point(x, y); + this.points.push(p); + } + redraw(p: Point): void { + if (this.points.length < 1) return; + this.graphic.clear(); + const template = this.graphicTemplate; + this.graphic.lineStyle({ + width: template.runLineWidth, + color: template.runLineColor, + join: LINE_JOIN.ROUND, + }); + const ps = [...this.points]; + ps.push(p); + // 直线 + this.graphic.moveTo(ps[0].x, ps[0].y); + for (let i = 1; i < ps.length; i++) { + const p = ps[i]; + this.graphic.lineTo(p.x, p.y); + } + } + prepareData(data: IRunLineData): boolean { + data.points = this.points; + return true; + } +} + +export class RunLineGraphicHitArea implements IHitArea { + runLine: RunLine; + constructor(runLine: RunLine) { + this.runLine = runLine; + } + contains(x: number, y: number): boolean { + const p = new Point(x, y); + for (let i = 1; i < this.runLine.datas.points.length; i++) { + const p1 = this.runLine.datas.points[i - 1]; + const p2 = this.runLine.datas.points[i]; + if (linePoint(p1, p2, p, runLineConsts.runLineWidth)) { + return true; + } + } + return false; + } +} + +function buildAbsorbablePositions( + runLine: RunLine, + dpIndex: number +): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const canvas = runLine.getCanvas(); + if (runLine.linePoints[dpIndex - 1]) { + const preP = runLine.localToCanvasPoint(runLine.linePoints[dpIndex - 1]); + const ala = new AbsorbableLine( + new Point(preP.x, 0), + new Point(preP.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, preP.y), + new Point(canvas.width, preP.y) + ); + aps.push(ala); + aps.push(alb); + } + if (runLine.linePoints[dpIndex + 1]) { + const nextP = runLine.localToCanvasPoint(runLine.linePoints[dpIndex + 1]); + const ala = new AbsorbableLine( + new Point(nextP.x, 0), + new Point(nextP.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, nextP.y), + new Point(canvas.width, nextP.y) + ); + aps.push(ala); + aps.push(alb); + } + return aps; +} + +/** + * 端点拖拽添加吸附位置 + * @param g + * @param dp + * @param index + */ +function onEditPointCreate( + g: ILineGraphic, + dp: DraggablePoint, + index: number +): void { + const runLine = g as RunLine; + dp.on('transformstart', (e: GraphicTransformEvent) => { + if (e.isShift()) { + runLine.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(runLine, index), + }); + } + }); +} + +export class RunLinePointsEditPlugin extends GraphicInteractionPlugin { + static Name = 'LinkPointsDrag'; + constructor(app: GraphicApp) { + super(RunLinePointsEditPlugin.Name, app); + } + static init(app: GraphicApp): RunLinePointsEditPlugin { + return new RunLinePointsEditPlugin(app); + } + filter(...grahpics: JlGraphic[]): RunLine[] | undefined { + return grahpics.filter((g) => g.type == RunLine.Type) as RunLine[]; + } + bind(g: RunLine): void { + g.lineBody.eventMode = 'static'; + g.lineBody.cursor = 'pointer'; + g.leftRunLineName.draggable = true; + g.leftRunLineName.selectable = true; + g.leftRunLineName.rotatable = true; + g.leftRunLineName.transformSave = true; + g.leftRunLineName.eventMode = 'static'; + g.leftRunLineName.cursor = 'pointer'; + + g.rightRunLineName.draggable = true; + g.rightRunLineName.selectable = true; + g.rightRunLineName.rotatable = true; + g.rightRunLineName.transformSave = true; + g.rightRunLineName.eventMode = 'static'; + g.rightRunLineName.cursor = 'pointer'; + g.lineBody.hitArea = new RunLineGraphicHitArea(g); + g.on('selected', this.onSelected, this); + g.on('unselected', this.onUnselected, this); + } + unbind(g: RunLine): void { + g.leftRunLineName.draggable = false; + g.leftRunLineName.selectable = false; + g.leftRunLineName.rotatable = false; + g.leftRunLineName.transformSave = false; + g.leftRunLineName.eventMode = 'none'; + + g.rightRunLineName.draggable = false; + g.rightRunLineName.selectable = false; + g.rightRunLineName.rotatable = false; + g.rightRunLineName.transformSave = false; + g.rightRunLineName.eventMode = 'none'; + + g.off('selected', this.onSelected, this); + g.off('unselected', this.onUnselected, this); + } + + onSelected(g: DisplayObject): void { + const runLine = g as RunLine; + let lep; + lep = runLine.getAssistantAppend( + PolylineEditPlugin.Name + ); + if (!lep) { + lep = new PolylineEditPlugin(runLine, { onEditPointCreate }); + runLine.addAssistantAppend(lep); + } + lep.showAll(); + } + onUnselected(g: DisplayObject): void { + const runLine = g as RunLine; + const lep = runLine.getAssistantAppend( + PolylineEditPlugin.Name + ); + if (lep) { + lep.hideAll(); + } + } +} diff --git a/src/graphics/runLine/RunLineName.ts b/src/graphics/runLine/RunLineName.ts new file mode 100644 index 0000000..6a60f06 --- /dev/null +++ b/src/graphics/runLine/RunLineName.ts @@ -0,0 +1,46 @@ +import { Container } from '@pixi/display'; +import { Graphics } from 'pixi.js'; +import { VectorText } from 'src/jl-graphic'; +import { IRunLineData } from './RunLine'; + +const nameConsts = { + padding: 8, + nameFontSize: 16, + defaultNameColor: '0X000000', + defaultBgColor: '0X0ff000', + bgRadius: 6, +}; + +export class RunLineName extends Container { + nameBg: Graphics = new Graphics(); + runLineName: VectorText = new VectorText(); + + constructor() { + super(); + this.addChild(this.nameBg); + this.addChild(this.runLineName); + } + paint(x: number, y: number, data: IRunLineData) { + this.runLineName.text = data.code || '运行线'; + this.runLineName.style.fill = data.nameColor || nameConsts.defaultNameColor; + this.runLineName.setVectorFontSize(nameConsts.nameFontSize); + this.runLineName.anchor.set(0.5); + this.runLineName.position.set(x, y); + + const nameRect = this.runLineName.getLocalBounds(); + this.nameBg.clear(); + if (!this.nameBg.drawRoundedRect) { + return; + } + this.nameBg.beginFill(data.nameBgColor || nameConsts.defaultBgColor, 1); + this.nameBg + .drawRoundedRect( + nameRect.x - nameConsts.padding / 2 + x, + nameRect.y - nameConsts.padding / 2 + y, + nameRect.width + nameConsts.padding, + nameRect.height + nameConsts.padding, + nameConsts.bgRadius + ) + .endFill(); + } +} diff --git a/src/graphics/section/Section.ts b/src/graphics/section/Section.ts new file mode 100644 index 0000000..7d0ade5 --- /dev/null +++ b/src/graphics/section/Section.ts @@ -0,0 +1,256 @@ +import { Graphics, IPointData } from 'pixi.js'; +import { + GraphicData, + GraphicRelationParam, + JlGraphic, + JlGraphicTemplate, + VectorText, + distance2, + splitLineEvenly, +} from 'src/jl-graphic'; +import { ILineGraphic } from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import { epsilon } from 'src/jl-graphic/math'; +import { + IRelatedRefData, + createRelatedRefProto, + protoPort2Data, +} from '../CommonGraphics'; +import { Turnout } from '../turnout/Turnout'; +import { SectionData } from 'src/drawApp/graphics/SectionInteraction'; + +export enum SectionType { + Physical = 0, + Logic = 1, + TurnoutPhysical = 2, +} + +export enum SectionPort { + A = 'A', + B = 'B', +} + +export interface ISectionData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get points(): IPointData[]; // 线坐标点 + set points(points: IPointData[]); + get paRef(): IRelatedRefData | undefined; + set paRef(ref: IRelatedRefData | undefined); + get pbRef(): IRelatedRefData | undefined; + set pbRef(ref: IRelatedRefData | undefined); + get sectionType(): SectionType; + set sectionType(type: SectionType); + get children(): string[]; + set children(children: string[]); + clone(): ISectionData; + copyFrom(data: ISectionData): void; + eq(other: ISectionData): boolean; +} + +export const SectionConsts = { + lineColor: '#5578b6', + lineWidth: 5, +}; + +export class Section extends JlGraphic implements ILineGraphic { + static Type = 'Section'; + lineGraphic: Graphics; + labelGraphic: VectorText; + childSections: Section[] = []; + + constructor() { + super(Section.Type); + this.lineGraphic = new Graphics(); + this.labelGraphic = new VectorText(); + this.labelGraphic.setVectorFontSize(14); + this.labelGraphic.anchor.set(0.5); + this.labelGraphic.style.fill = '#0f0'; + this.labelGraphic.transformSave = true; + this.labelGraphic.name = 'label'; + this.transformSave = true; + this.addChild(this.lineGraphic); + this.addChild(this.labelGraphic); + } + + doRepaint() { + if (this.datas.points.length < 2) { + throw new Error('Link坐标数据异常'); + } + + this.lineGraphic.clear(); + if ( + (this.datas.sectionType === SectionType.Physical && + this.datas.children.length === 0) /* 未拆分的物理区段 */ || + this.datas.sectionType === SectionType.Logic /* 逻辑区段 */ + ) { + this.lineGraphic.lineStyle( + SectionConsts.lineWidth, + SectionConsts.lineColor + ); + + this.datas.points.forEach((p, i) => { + if (i !== 0) { + this.lineGraphic.lineTo(p.x, p.y); + } else { + this.lineGraphic.moveTo(p.x, p.y); + } + }); + } + + this.labelGraphic.text = this.datas.code; + const labelPosition = this.datas.childTransforms?.find( + (t) => t.name === this.labelGraphic.name + )?.transform.position; + if (labelPosition) { + this.labelGraphic.position.set(labelPosition.x, labelPosition.y); + } else { + this.labelGraphic.position.set( + this.datas.points[0].x, + this.datas.points[0].y + 20 + ); + } + } + + getStartPoint() { + return this.datas.points[0]; + } + getEndPoint(): IPointData { + return this.datas.points[this.datas.points.length - 1]; + } + + get datas(): ISectionData { + return this.getDatas(); + } + + get linePoints(): IPointData[] { + return this.datas.points; + } + set linePoints(points: IPointData[]) { + const old = this.datas.clone(); + old.points = points; + this.updateData(old); + } + + /** 获取拆分逻辑区段数据 */ + getSplitPoints(count: number): IPointData[][] { + if (this.datas.points.length !== 2) { + throw Error('多段分割待实现'); + } + return splitLineEvenly( + this.datas.points[0], + this.datas.points[this.datas.points.length - 1], + count + ); + } + + buildRelation() { + this.relationManage.deleteRelationOfGraphicAndOtherType(this, Section.Type); + /** 区段与区段 */ + this.queryStore.queryByType
(Section.Type).forEach((section) => { + if (section.id === this.id) return; + + let param: SectionPort[] = []; + if ( + distance2( + this.localToCanvasPoint(this.getStartPoint()), + section.localToCanvasPoint(section.getStartPoint()) + ) <= epsilon + ) { + param = [SectionPort.A, SectionPort.A]; + } + if ( + distance2( + this.localToCanvasPoint(this.getEndPoint()), + section.localToCanvasPoint(section.getStartPoint()) + ) <= epsilon + ) { + param = [SectionPort.B, SectionPort.A]; + } + if ( + distance2( + this.localToCanvasPoint(this.getStartPoint()), + section.localToCanvasPoint(section.getEndPoint()) + ) <= epsilon + ) { + param = [SectionPort.A, SectionPort.B]; + } + if ( + distance2( + this.localToCanvasPoint(this.getEndPoint()), + section.localToCanvasPoint(section.getEndPoint()) + ) <= epsilon + ) { + param = [SectionPort.B, SectionPort.B]; + } + if (param.length) { + this.relationManage.addRelation( + new GraphicRelationParam(this, param[0]), + new GraphicRelationParam(section, param[1]) + ); + } + }); + } + + saveRelations() { + const paRelation = this.relationManage + .getRelationsOfGraphic(this) + .find( + (relation) => relation.getRelationParam(this).param === SectionPort.A + ); + const paDevice = paRelation?.getOtherGraphic
(this); + if (paDevice) { + this.datas.paRef = createRelatedRefProto( + paDevice.type, + paDevice.id, + paRelation?.getOtherRelationParam(this).param + ); + } else { + this.datas.paRef = undefined; + } + const pbRelation = this.relationManage + .getRelationsOfGraphic(this) + .find( + (relation) => relation.getRelationParam(this).param === SectionPort.B + ); + const pbDevice = pbRelation?.getOtherGraphic
(this); + if (pbDevice) { + this.datas.pbRef = createRelatedRefProto( + pbDevice.type, + pbDevice.id, + pbRelation?.getOtherRelationParam(this).param + ); + } else { + this.datas.pbRef = undefined; + } + } + + loadRelations() { + if (this.datas?.paRef?.id) { + this.relationManage.addRelation( + new GraphicRelationParam(this, SectionPort.A), + new GraphicRelationParam( + this.queryStore.queryById(this.datas.paRef.id), + protoPort2Data(this.datas.paRef.devicePort) + ) + ); + } + if (this.datas?.pbRef?.id) { + this.relationManage.addRelation( + new GraphicRelationParam(this, SectionPort.B), + new GraphicRelationParam( + this.queryStore.queryById(this.datas.pbRef.id), + protoPort2Data(this.datas.pbRef.devicePort) + ) + ); + } + } +} + +export class SectionTemplate extends JlGraphicTemplate
{ + constructor(dataTemplate: ISectionData) { + super(Section.Type, { dataTemplate }); + } + new() { + return new Section(); + } +} diff --git a/src/graphics/section/SectionDrawAssistant.ts b/src/graphics/section/SectionDrawAssistant.ts new file mode 100644 index 0000000..c27d8da --- /dev/null +++ b/src/graphics/section/SectionDrawAssistant.ts @@ -0,0 +1,261 @@ +import { + ChildTransform, + DraggablePoint, + GraphicApp, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransform, + GraphicTransformEvent, + JlDrawApp, + JlGraphic, + VectorText, + linePoint, +} from 'src/jl-graphic'; +import { + ISectionData, + Section, + SectionConsts, + SectionTemplate, +} from './Section'; +import { + DisplayObject, + FederatedMouseEvent, + Graphics, + IHitArea, + Point, +} from 'pixi.js'; +import { + IEditPointOptions, + ILineGraphic, + PolylineEditPlugin, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import AbsorbablePoint, { + AbsorbableLine, + AbsorbablePosition, +} from 'src/jl-graphic/graphic/AbsorbablePosition'; +import { Turnout } from '../turnout/Turnout'; + +export class SectionDraw extends GraphicDrawAssistant< + SectionTemplate, + ISectionData +> { + points: Point[] = []; + graphic = new Graphics(); + + constructor(app: JlDrawApp, template: SectionTemplate) { + super(app, template, 'sym_o_timeline', '区段Section'); + this.container.addChild(this.graphic); + + SectionPointEditPlugin.init(app); + } + + onLeftDown(e: FederatedMouseEvent): void { + const { x, y } = this.toCanvasCoordinates(e.global); + const p = new Point(x, y); + this.points.push(p); + } + + onRightClick(): void { + if (this.points.length < 2) { + this.finish(); + return; + } + this.createAndStore(true); + } + + onEsc(): void { + if (this.points.length < 2) { + this.finish(); + return; + } + this.createAndStore(true); + } + + redraw(cp: Point): void { + if (this.points.length < 1) return; + this.graphic.clear(); + this.graphic.lineStyle(SectionConsts.lineWidth, SectionConsts.lineColor); + this.points.forEach((p, i) => { + if (i !== 0) { + this.graphic.lineTo(p.x, p.y); + } else { + this.graphic.moveTo(p.x, p.y); + } + }); + this.graphic.lineTo(cp.x, cp.y); + } + + prepareData(data: ISectionData): boolean { + data.points = this.points; + data.code = 'G000'; + data.childTransforms?.push( + new ChildTransform( + 'label', + new GraphicTransform( + { + x: data.points[1].x - data.points[0].x, + y: data.points[1].y - data.points[0].y + 20, + }, + { x: 0, y: 0 }, + 0, + { x: 0, y: 0 } + ) + ) + ); + + return true; + } + + clearCache(): void { + this.points = []; + this.graphic.clear(); + } +} + +class SectionGraphicHitArea implements IHitArea { + section: Section; + constructor(section: Section) { + this.section = section; + } + contains(x: number, y: number): boolean { + for (let i = 1; i < this.section.datas.points.length; i++) { + const p1 = this.section.datas.points[i - 1]; + const p2 = this.section.datas.points[i]; + if (linePoint(p1, p2, { x, y }, SectionConsts.lineWidth)) { + return true; + } + } + return false; + } +} + +function buildAbsorbablePositions(section: Section): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + + const sections = section.queryStore.queryByType
(Section.Type); + sections.forEach((other) => { + const [ps, pe] = [ + other.localToCanvasPoint(other.getStartPoint()), + other.localToCanvasPoint(other.getEndPoint()), + ]; + const { width, height } = section.getGraphicApp().canvas; + const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y }); + const ys = new AbsorbableLine({ x: ps.x, y: 0 }, { x: ps.x, y: height }); + const xe = new AbsorbableLine({ x: 0, y: pe.y }, { x: width, y: pe.y }); + const ye = new AbsorbableLine({ x: pe.x, y: 0 }, { x: pe.x, y: height }); + aps.push(xs, ys, xe, ye); + }); + + const turnouts = section.queryStore.queryByType(Turnout.Type); + turnouts.forEach((turnout) => { + turnout.getPortPoints().forEach((points) => { + turnout.localToCanvasPoints(...points).forEach((p) => { + aps.push(new AbsorbablePoint(p)); + }); + }); + }); + + return aps; +} + +function onEditPointCreate( + g: ILineGraphic, + dp: DraggablePoint, + index: number +): void { + const section = g as Section; + dp.on('transformstart', (e: GraphicTransformEvent) => { + if (e.isShift()) { + section.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(section), + }); + } + }); +} + +class SectionPolylineEditPlugin extends PolylineEditPlugin { + static Name = 'SectionPolylineEditPlugin'; + labels: VectorText[] = []; + constructor(g: ILineGraphic, options?: IEditPointOptions) { + super(g, options); + this.name = SectionPolylineEditPlugin.Name; + this.initLabels(); + } + + initLabels() { + this.labels = [new VectorText('A'), new VectorText('B')]; + this.labels.forEach((label) => { + label.setVectorFontSize(14); + this.addChild(label); + }); + this.updateEditedPointsPosition(); + } + + reset(): void { + super.reset(); + this.initLabels(); + } + + updateEditedPointsPosition() { + super.updateEditedPointsPosition(); + this.labels[0]?.position.set( + this.editedPoints[0].x, + this.editedPoints[0].y + 10 + ); + this.labels[1]?.position.set( + this.editedPoints[this.editedPoints.length - 1].x, + this.editedPoints[this.editedPoints.length - 1].y + 10 + ); + } +} + +export class SectionPointEditPlugin extends GraphicInteractionPlugin
{ + static Name = 'SectionPointDrag'; + + constructor(app: GraphicApp) { + super(SectionPointEditPlugin.Name, app); + } + static init(app: GraphicApp) { + return new SectionPointEditPlugin(app); + } + filter(...grahpics: JlGraphic[]): Section[] | undefined { + return grahpics.filter((g) => g.type == Section.Type) as Section[]; + } + bind(g: Section): void { + g.lineGraphic.eventMode = 'static'; + g.lineGraphic.cursor = 'pointer'; + g.lineGraphic.hitArea = new SectionGraphicHitArea(g); + g.transformSave = true; + g.labelGraphic.eventMode = 'static'; + g.labelGraphic.cursor = 'pointer'; + g.labelGraphic.selectable = true; + g.labelGraphic.draggable = true; + g.on('selected', this.onSelected, this); + g.on('unselected', this.onUnselected, this); + } + unbind(g: Section): void { + g.off('selected', this.onSelected, this); + g.off('unselected', this.onUnselected, this); + } + + onSelected(g: DisplayObject): void { + const section = g as Section; + let lep = section.getAssistantAppend( + SectionPolylineEditPlugin.Name + ); + if (!lep) { + lep = new SectionPolylineEditPlugin(section, { onEditPointCreate }); + section.addAssistantAppend(lep); + } + lep.showAll(); + } + onUnselected(g: DisplayObject): void { + const section = g as Section; + const lep = section.getAssistantAppend( + SectionPolylineEditPlugin.Name + ); + if (lep) { + lep.hideAll(); + } + } +} diff --git a/src/graphics/separator/Separator.ts b/src/graphics/separator/Separator.ts new file mode 100644 index 0000000..032ee1e --- /dev/null +++ b/src/graphics/separator/Separator.ts @@ -0,0 +1,94 @@ +import { Color, Graphics } from 'pixi.js'; +import { GraphicData, JlGraphic, JlGraphicTemplate } from 'src/jl-graphic'; + +export interface ISeparatorData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get separatorType(): string; // 类型 + set separatorType(v: string); + clone(): ISeparatorData; + copyFrom(data: ISeparatorData): void; + eq(other: ISeparatorData): boolean; +} + +export enum separatorTypeEnum { + turnout = 'turnout', // 道岔分隔符 + endA = 'endA', // A端尽头分隔符 + endB = 'endB', // B端尽头分隔符 + section = 'section', // 区段分隔符 +} + +export const SeparatorConsts = { + height: 15, + lineWidth: 2, + lineColor: '0x617799', + circleColor: '0xEF0200', + radius: 5, +}; + +export class Separator extends JlGraphic { + static Type = 'Separator'; + rectGraphic: Graphics = new Graphics(); + circleGraphic: Graphics = new Graphics(); + constructor() { + super(Separator.Type); + this.addChild(this.rectGraphic); + this.addChild(this.circleGraphic); + } + get datas(): ISeparatorData { + return this.getDatas(); + } + clear() { + this.rectGraphic.clear(); + this.circleGraphic.clear(); + } + doRepaint(): void { + this.clear(); + const rectGraphic = this.rectGraphic; + if (!this.datas.separatorType) { + this.datas.separatorType = separatorTypeEnum.endA; + } + const typeArr = ['section', 'turnout']; + if (typeArr.includes(this.datas.separatorType)) { + rectGraphic.lineStyle( + SeparatorConsts.lineWidth, + new Color(SeparatorConsts.lineColor) + ); + rectGraphic.moveTo(0, -SeparatorConsts.height / 2); + rectGraphic.lineTo(0, SeparatorConsts.height / 2); + if (this.datas.separatorType == 'turnout') { + this.circleGraphic.lineStyle(1, SeparatorConsts.circleColor); + this.circleGraphic.drawCircle(0, 0, SeparatorConsts.radius); + } + } + const endTypeArr = ['endA', 'endB']; + if (endTypeArr.includes(this.datas.separatorType)) { + let d = SeparatorConsts.radius; + if (this.datas.separatorType == 'endB') { + d = -d; + } + rectGraphic.lineStyle( + SeparatorConsts.lineWidth, + new Color(SeparatorConsts.lineColor) + ); + rectGraphic.moveTo(0, 0); + rectGraphic.lineTo(-d, 0); + rectGraphic.lineTo(-d, -d); + rectGraphic.lineTo(-d * 3, -d); + rectGraphic.moveTo(-d, 0); + rectGraphic.lineTo(-d, d); + rectGraphic.lineTo(-d * 3, d); + } + } +} + +export class SeparatorTemplate extends JlGraphicTemplate { + constructor(dataTemplate: ISeparatorData) { + super(Separator.Type, { + dataTemplate, + }); + } + new(): Separator { + return new Separator(); + } +} diff --git a/src/graphics/separator/SeparatorDrawAssistant.ts b/src/graphics/separator/SeparatorDrawAssistant.ts new file mode 100644 index 0000000..d1a1453 --- /dev/null +++ b/src/graphics/separator/SeparatorDrawAssistant.ts @@ -0,0 +1,269 @@ +import { FederatedPointerEvent, IHitArea, Point } from 'pixi.js'; +import { + GraphicDrawAssistant, + GraphicIdGenerator, + GraphicInteractionPlugin, + GraphicRelationParam, + JlDrawApp, + JlGraphic, + linePoint, +} from 'src/jl-graphic'; +import { Section, SectionType } from '../section/Section'; +import { + ISeparatorData, + Separator, + SeparatorConsts, + SeparatorTemplate, + separatorTypeEnum, +} from './Separator'; +import { SeparatorData } from 'src/drawApp/graphics/SeparatorInteraction'; +import { Turnout } from '../turnout/Turnout'; + +export class SeparatorDraw extends GraphicDrawAssistant< + SeparatorTemplate, + ISeparatorData +> { + SeparatorGraph: Separator; + constructor(app: JlDrawApp, template: SeparatorTemplate) { + super(app, template, 'sym_o_square', '不展示'); + this.SeparatorGraph = this.graphicTemplate.new(); + this.container.addChild(this.SeparatorGraph); + SeparatorInteraction.init(app); + } + + bind(): void { + super.bind(); + this.SeparatorGraph.loadData(this.graphicTemplate.datas); + this.SeparatorGraph.doRepaint(); + } + + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + + prepareData(data: ISeparatorData): boolean { + data.transform = this.container.saveTransform(); + return true; + } + oneGenerates() { + const SeparatorAll = this.app.queryStore.queryByType( + Separator.Type + ); + this.app.deleteGraphics(...SeparatorAll); + const rMap = new Map(); + const sections = this.app.queryStore.queryByType
(Section.Type); + const turnouts = this.app.queryStore.queryByType(Turnout.Type); + function setKey(gr: GraphicRelationParam): string { + let key = ''; + key = `${gr.g.id}_${gr.param}`; + return key; + } + const arrType = [Section.Type, Turnout.Type]; // 只统计关联关系是道岔和区段的 + sections.forEach((section) => { + const allR = section.relationManage + .getRelationsOfGraphic(section) + .filter((ref) => { + return arrType.includes(ref.getOtherGraphic(section).type); + }); + const port: string[] = []; + allR.forEach((relation, index) => { + const r = relation.getRelationParam(section); + const other = relation.getOtherRelationParam(section); + if (!section.datas.children.includes(other.g.id)) { + // 排除物理区段和自身逻辑区段的关联关系 + port.push(r.param); + } + if (!rMap.has(setKey(r))) { + rMap.set(setKey(r), { ...r }); + } + if (!rMap.has(setKey(other))) { + rMap.set(setKey(other), { ...other, repetition: true }); + } + if (section.datas.sectionType === SectionType.Logic) { + // 逻辑区段没有断路分隔符 + return; + } + if (index == allR.length - 1) { + if (!port.includes('A')) { + rMap.set(`${section.id}_A`, { + g: section, + param: 'A', + separatorType: separatorTypeEnum.endA, + }); + } + if (!port.includes('B')) { + rMap.set(`${section.id}_B`, { + g: section, + param: 'B', + separatorType: separatorTypeEnum.endB, + }); + } + } + }); + }); + turnouts.forEach((turnout) => { + const allR = turnout.relationManage + .getRelationsOfGraphic(turnout) + .filter((ref) => { + return arrType.includes(ref.getOtherGraphic(turnout).type); + }); + const port: string[] = []; + allR.forEach((relation, index) => { + const r = relation.getRelationParam(turnout); + port.push(r.param); + const other = relation.getOtherRelationParam(turnout); + let t = separatorTypeEnum.section; + if ( + (r.param == 'C' && other.param == 'C') || + (r.g.type == Turnout.Type && + other.g.type == Turnout.Type && + (r.param == 'C' || other.param == 'C')) + ) { + t = separatorTypeEnum.turnout; + } + if (!rMap.has(setKey(r))) { + rMap.set(setKey(r), { + ...r, + separatorType: t, + }); + } + if (!rMap.has(setKey(other))) { + rMap.set(setKey(other), { + ...other, + separatorType: t, + repetition: true, + }); + } + if (index == allR.length - 1) { + const ps = turnout.getPortPoints(); + let isALeft = true; // 判断A端在左还是右 + if (ps[0][ps[0].length - 1].x > ps[1][ps[1].length - 1].x) { + isALeft = false; + } + if (!port.includes('A')) { + rMap.set(`${turnout.id}_A`, { + g: turnout, + param: 'A', + separatorType: isALeft + ? separatorTypeEnum.endA + : separatorTypeEnum.endB, + }); + } + if (!port.includes('B')) { + rMap.set(`${turnout.id}_B`, { + g: turnout, + param: 'B', + separatorType: isALeft + ? separatorTypeEnum.endB + : separatorTypeEnum.endA, + }); + } + } + }); + }); + rMap.forEach((item) => { + if (!item.repetition) { + let p; + if (item.g.type == Section.Type) { + p = item.g.getStartPoint(); + if (item.param == 'B') { + p = item.g.getEndPoint(); + } + } else if (item.g.type == Turnout.Type) { + const ps = item.g.getPortPoints(); + let l = 2; + if (item.param == 'A') { + l = 0; + } else if (item.param == 'B') { + l = 1; + } + const lps = ps[l]; + p = lps[lps.length - 1]; + } + const tps = item.g.localToCanvasPoint(p); + const sType = item.separatorType || separatorTypeEnum.section; + this.createSeparator(sType, tps); + } + }); + } + createSeparator(separatorType: separatorTypeEnum, tps: Point) { + const separator = new Separator(); + const data = new SeparatorData(); + data.separatorType = separatorType; + separator.loadData(data); + separator.position.set(tps.x, tps.y); + separator.id = GraphicIdGenerator.next(); + this.storeGraphic(separator); + } +} + +//碰撞检测 +export class SeparatorGraphicHitArea implements IHitArea { + separator: Separator; + constructor(separator: Separator) { + this.separator = separator; + } + contains(x: number, y: number): boolean { + let contains = false; + const p = new Point(x, y); + const typeArr = ['section', 'turnout']; + const endTypeArr = ['endA', 'endB']; + let d = SeparatorConsts.radius; + if (typeArr.includes(this.separator.datas.separatorType)) { + const tolerance = SeparatorConsts.lineWidth; + const p1 = new Point(0, -SeparatorConsts.height / 2); + const p2 = new Point(0, SeparatorConsts.height / 2); + contains = contains || linePoint(p1, p2, p, tolerance); + return contains; + } else if (endTypeArr.includes(this.separator.datas.separatorType)) { + if (this.separator.datas.separatorType == 'endB') { + d = -d; + } + const tolerance = SeparatorConsts.lineWidth; + const p1 = new Point(0, 0); + const p2 = new Point(-d, 0); + const p3 = new Point(-d, -d); + const p4 = new Point(-d * 3, -d); + const p5 = new Point(-d, d); + const p6 = new Point(-d * 3, d); + contains = contains || linePoint(p1, p2, p, tolerance); + contains = contains || linePoint(p2, p3, p, tolerance); + contains = contains || linePoint(p3, p4, p, tolerance); + contains = contains || linePoint(p2, p5, p, tolerance); + contains = contains || linePoint(p5, p6, p, tolerance); + } + return contains; + } +} + +export class SeparatorInteraction extends GraphicInteractionPlugin { + static Name = 'Separator_transform'; + constructor(app: JlDrawApp) { + super(SeparatorInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new SeparatorInteraction(app); + } + filter(...grahpics: JlGraphic[]): Separator[] | undefined { + return grahpics + .filter((g) => g.type === Separator.Type) + .map((g) => g as Separator); + } + bind(g: Separator): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.rectGraphic.hitArea = new SeparatorGraphicHitArea(g); + } + unbind(g: Separator): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + } +} diff --git a/src/graphics/signal/Lamp.ts b/src/graphics/signal/Lamp.ts new file mode 100644 index 0000000..fecb912 --- /dev/null +++ b/src/graphics/signal/Lamp.ts @@ -0,0 +1,73 @@ +import { Container } from '@pixi/display'; +import { Graphics } from 'pixi.js'; + +const lampConsts = { + lampRadius: 8, + logicModeLineWidth: 2, + logicModeDistance: 5, + logicModeColor: '0x000000', + lampLineWidth: 1, + lampLineColor: '0x3149c3', +}; + +export class Lamp extends Container { + circleLamp: Graphics = new Graphics(); + logicMode: Graphics = new Graphics(); + radiusX = 0; + radiusY = 0; + + constructor() { + super(); + this.addChild(this.circleLamp); + this.addChild(this.logicMode); + } + paint(radiusX: number, radiusY: number) { + this.radiusX = radiusX; + this.radiusY = radiusY; + this.createLamp(); + } + createLamp(color?: string) { + this.circleLamp.clear(); + this.circleLamp.lineStyle( + lampConsts.lampLineWidth, + lampConsts.lampLineColor + ); + if (!color) { + color = '0X' + this.getCanvas().backgroundColor.substring(1); + } + this.circleLamp.beginFill(color, 1); + this.circleLamp.drawCircle( + this.radiusX, + this.radiusY, + lampConsts.lampRadius + ); + this.circleLamp.endFill(); + } + createLogicMode() { + this.logicMode + .clear() + .lineStyle(lampConsts.logicModeLineWidth, lampConsts.logicModeColor) + .moveTo( + this.radiusX - lampConsts.logicModeDistance, + this.radiusY + lampConsts.logicModeDistance + ) + .lineTo( + this.radiusX + lampConsts.logicModeDistance, + this.radiusY - lampConsts.logicModeDistance + ) + .moveTo( + this.radiusX - lampConsts.logicModeDistance, + this.radiusY - lampConsts.logicModeDistance + ) + .lineTo( + this.radiusX + lampConsts.logicModeDistance, + this.radiusY + lampConsts.logicModeDistance + ); + } + logicModeClear() { + this.logicMode.clear(); + } + lampClear() { + this.circleLamp.clear(); + } +} diff --git a/src/graphics/signal/LampMainBody.ts b/src/graphics/signal/LampMainBody.ts new file mode 100644 index 0000000..b4c3b63 --- /dev/null +++ b/src/graphics/signal/LampMainBody.ts @@ -0,0 +1,204 @@ +import { Graphics, Point } from 'pixi.js'; +import { + calculateMirrorPoint, + GraphicAnimation, + JlGraphic, +} from 'src/jl-graphic'; +import { Lamp } from './Lamp'; +import { ISignalState } from './Signal'; + +export enum LampEnum { + lampPostColor = '0x3149c3', + redLamp = '0XFF0000', + greenLamp = '0X00FF00', + yellowLamp = '0XFFFF00', + whiteLamp = '0XFFFFFF', + blueLamp = '0X0033FF', +} + +const lampConsts = { + verticalLampPostLength: 16, + levelLampPostLength: 4, + postLineWidth: 3, + lampRadius: 8, +}; + +const anmiationNameConst = { + signaRedFlash: 'signal_red_flash', + signalGreenFlash: 'signal_green_flash', + signalYellowFlash: 'signal_yellow_flash', + signalWhiteFlash: 'signal_white_flash', + signalBlueFlash: 'signal_blue_flash', +}; + +export class LampMainBody extends JlGraphic { + static Type = 'LampMainBody'; + lampNum = 1; + lampPost: Graphics = new Graphics(); + lamps: Lamp[] = []; + redFlashAnimation: GraphicAnimation | null = null; + mirror = false; + deltaTime = 0; + states: ISignalState | null = null; + + constructor() { + super(LampMainBody.Type); + } + paint(lampNum: number, mirror: boolean, states: ISignalState) { + this.mirror = mirror; + this.states = states; + if (lampNum < 1) { + throw new Error('信号机灯数量异常'); + } + this.lampNum = lampNum; + this.removeChildren(0); + this.lampPost = new Graphics(); + let lpp = new Point(lampConsts.levelLampPostLength, 0); + if (mirror) { + lpp = calculateMirrorPoint(new Point(0, 0), lpp); + } + this.lampPost + .lineStyle(lampConsts.postLineWidth, LampEnum.lampPostColor) + .moveTo(0, -lampConsts.verticalLampPostLength / 2) + .lineTo(0, lampConsts.verticalLampPostLength / 2) + .moveTo(0, 0) + .lineTo(lpp.x, lpp.y); + this.addChild(this.lampPost); + + this.lamps = []; + for (let i = 0; i < this.lampNum; i++) { + const lamp = new Lamp(); + this.addChild(lamp); + const radiusX = + (1 + i * 2) * lampConsts.lampRadius + lampConsts.levelLampPostLength; + let lrp = new Point(radiusX, 0); + if (mirror) { + lrp = calculateMirrorPoint(new Point(0, 0), lrp); + } + lamp.paint(lrp.x, lrp.y); + this.lamps.push(lamp); + } + this.chagneState(this.states); + } + doRepaint() { + // this.paint(this.lampNum, this.mirror, this.states); + } + stopAnmiation() { + const redFlashA = this.animation(anmiationNameConst.signaRedFlash); + const greenFlashA = this.animation(anmiationNameConst.signalGreenFlash); + const blueFlashA = this.animation(anmiationNameConst.signalBlueFlash); + const yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash); + const whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash); + if (redFlashA) { + redFlashA.pause(); + } + if (greenFlashA) { + greenFlashA.pause(); + } + if (blueFlashA) { + blueFlashA.pause(); + } + if (yellowFlashA) { + yellowFlashA.pause(); + } + if (whiteFlashA) { + whiteFlashA.pause(); + } + } + chagneState(states: ISignalState) { + this.stopAnmiation(); + if (states.extinguish) { + this.lamps.forEach((lamp) => lamp.createLogicMode()); + } else { + this.lamps.forEach((lamp) => lamp.logicModeClear()); + } + if (states.redOpen) { + this.lamps[0].createLamp(LampEnum.redLamp); + } else if (states.redFlash) { + let redFlashA = this.animation(anmiationNameConst.signaRedFlash); + if (!redFlashA) { + redFlashA = this.createFlashAnmiation( + anmiationNameConst.signaRedFlash, + LampEnum.redLamp, + 0 + ); + } + this.addAnimation(redFlashA); + redFlashA.resume(); + } else if (states.greenOpen) { + this.lamps.forEach((lamp) => lamp.createLamp(LampEnum.greenLamp)); + } else if (states.greenFlash) { + let greenFlashA = this.animation(anmiationNameConst.signalGreenFlash); + if (!greenFlashA) { + greenFlashA = this.createFlashAnmiation( + anmiationNameConst.signalGreenFlash, + LampEnum.greenLamp, + 1 + ); + } + this.addAnimation(greenFlashA); + greenFlashA.resume(); + } else if (states.yellowOpen) { + this.lamps.forEach((lamp) => lamp.createLamp(LampEnum.yellowLamp)); + } else if (states.yellowFlash) { + let yellowFlashA = this.animation(anmiationNameConst.signalYellowFlash); + if (!yellowFlashA) { + yellowFlashA = this.createFlashAnmiation( + anmiationNameConst.signalYellowFlash, + LampEnum.yellowLamp, + 1 + ); + } + this.addAnimation(yellowFlashA); + yellowFlashA.resume(); + } else if (states.blueOpen) { + this.lamps.forEach((lamp) => lamp.createLamp(LampEnum.blueLamp)); + } else if (states.blueFlash) { + let blueFlashA = this.animation(anmiationNameConst.signalBlueFlash); + if (!blueFlashA) { + blueFlashA = this.createFlashAnmiation( + anmiationNameConst.signalBlueFlash, + LampEnum.blueLamp, + 1 + ); + } + this.addAnimation(blueFlashA); + blueFlashA.resume(); + } else if (states.whiteOpen) { + this.lamps.forEach((lamp) => lamp.createLamp(LampEnum.whiteLamp)); + } else if (states.whiteFlash) { + let whiteFlashA = this.animation(anmiationNameConst.signalWhiteFlash); + if (!whiteFlashA) { + whiteFlashA = this.createFlashAnmiation( + anmiationNameConst.signalWhiteFlash, + LampEnum.whiteLamp, + 1 + ); + } + this.addAnimation(whiteFlashA); + whiteFlashA.resume(); + } + } + createFlashAnmiation( + name: string, + color: string, + lampIndex: number + ): GraphicAnimation { + const bgColor = '0X' + this.getCanvas().backgroundColor.substring(1); + const flashAnmiation = GraphicAnimation.init({ + name: name, + run: (dt: number) => { + this.deltaTime += dt; + if (this.deltaTime > 60) { + this.deltaTime = 0; + this.lamps[lampIndex].createLamp(color); + } else if (this.deltaTime > 30) { + this.lamps.forEach((lamp) => { + lamp.createLamp(bgColor); + }); + } + }, + }); + return flashAnmiation; + } +} diff --git a/src/graphics/signal/Signal.ts b/src/graphics/signal/Signal.ts new file mode 100644 index 0000000..4728e80 --- /dev/null +++ b/src/graphics/signal/Signal.ts @@ -0,0 +1,206 @@ +import { Graphics, Point } from 'pixi.js'; +import { + GraphicData, + GraphicState, + JlGraphic, + JlGraphicTemplate, +} from 'src/jl-graphic'; +import { calculateMirrorPoint } from 'src/jl-graphic'; +import { LampMainBody } from './LampMainBody'; +import { drawArrow } from '../CommonGraphics'; +import { SignalCode } from './SignalCode'; + +export interface KilometerSystem { + get coordinateSystem(): string; + set coordinateSystem(v: string); + get kilometer(): number; + set kilometer(v: number); +} + +export interface ISignalData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get mirror(): boolean; + set mirror(v: boolean); + get kilometerSystem(): KilometerSystem; + set kilometerSystem(v: KilometerSystem); + clone(): ISignalData; + copyFrom(data: ISignalData): void; + eq(other: ISignalData): boolean; +} + +export interface ISignalState extends GraphicState { + get redOpen(): boolean; + set redOpen(v: boolean); + get redFlash(): boolean; + set redFlash(v: boolean); + get greenOpen(): boolean; + set greenOpen(v: boolean); + get greenFlash(): boolean; + set greenFlash(v: boolean); + get yellowOpen(): boolean; + set yellowOpen(v: boolean); + get yellowFlash(): boolean; + set yellowFlash(v: boolean); + get whiteOpen(): boolean; + set whiteOpen(v: boolean); + get whiteFlash(): boolean; + set whiteFlash(v: boolean); + get blueOpen(): boolean; + set blueOpen(v: boolean); + get blueFlash(): boolean; + set blueFlash(v: boolean); + get fleetMode(): boolean; + set fleetMode(v: boolean); + get ctrlFleetMode(): boolean; + set ctrlFleetMode(v: boolean); + get autoMode(): boolean; + set autoMode(v: boolean); + get ctrlAutoMode(): boolean; + set ctrlAutoMode(v: boolean); + get extinguish(): boolean; + set extinguish(v: boolean); + get approachLock(): boolean; + set approachLock(v: boolean); + get protectRoute(): boolean; + set protectRoute(v: boolean); + get autoRouteDisable(): boolean; + set autoRouteDisable(v: boolean); + get callon(): boolean; + set callon(v: boolean); + get yellowYellow(): boolean; + set yellowYellow(v: boolean); + get yellowGreen(): boolean; + set yellowGreen(v: boolean); + get blocked(): boolean; + set blocked(v: boolean); + get lampFailure(): boolean; + set lampFailure(v: boolean); +} + +export enum SignalColorEnum { + humanControlColor = '0xffff00', + fleetModeColor = '0x00ff00', +} + +const signalConsts = { + lampNum: 2, + fleetModeLength: 24, + fleetModeRadius: 8, + fleetModeLineWidth: 6, + humanControlRadius: 8, + codeOffset: 20, +}; +export class Signal extends JlGraphic { + static Type = 'signal'; + signalCode: SignalCode = new SignalCode(); + humanControl: Graphics = new Graphics(); + fleetMode: Graphics = new Graphics(); + lampMainBody: LampMainBody = new LampMainBody(); + blockedMode: Graphics = new Graphics(); + + constructor() { + super(Signal.Type); + this.addChild(this.humanControl); + this.addChild(this.fleetMode); + this.addChild(this.lampMainBody); + this.addChild(this.signalCode); + } + + get datas(): ISignalData { + return this.getDatas(); + } + + get states(): ISignalState { + return this.getStates(); + } + + get mirror(): boolean { + return this.datas.mirror; + } + set mirror(v: boolean) { + const old = this.datas.clone(); + old.mirror = v; + this.updateData(old); + } + + paint(): void { + const mirror = this.datas.mirror; + this.lampMainBody.paint(signalConsts.lampNum, mirror, this.states); + this.signalCode.paint(this.datas, this.states); + const codeTransform = this.datas?.childTransforms?.find( + (item) => item.name === 'signalCode' + ); + if (codeTransform) { + const position = codeTransform?.transform.position; + const rotation = codeTransform?.transform?.rotation; + this.signalCode.position.set(position?.x, position?.y); + this.signalCode.rotation = rotation || 0; + } else { + this.signalCode.position.set(0, signalConsts.codeOffset); + } + } + + doRepaint(): void { + this.paint(); + this.fleetMode.clear(); + if (this.states.fleetMode) { + this.createFleetMode(); + } + this.humanControl.clear(); + if (this.states.autoRouteDisable) { + this.createHumanControl(); + } + } + createFleetMode(): void { + const mirror = this.datas.mirror; + this.fleetMode.beginFill(SignalColorEnum.fleetModeColor, 1); + let lmp = new Point( + this.lampMainBody.width + signalConsts.fleetModeLength, + 0 + ); + if (mirror) { + lmp = calculateMirrorPoint(new Point(0, 0), lmp); + } + drawArrow( + this.fleetMode, + lmp.x, + 0, + signalConsts.fleetModeLength, + signalConsts.fleetModeRadius, + signalConsts.fleetModeLineWidth, + mirror + ); + this.fleetMode.endFill(); + } + createHumanControl(): void { + const mirror = this.datas.mirror; + this.humanControl.beginFill(SignalColorEnum.humanControlColor, 1); + if (this.humanControl.drawRegularPolygon) { + let hmp = new Point(-signalConsts.humanControlRadius, 0); + if (mirror) { + hmp = calculateMirrorPoint(new Point(0, 0), hmp); + } + this.humanControl.drawRegularPolygon( + hmp.x, + hmp.y, + signalConsts.humanControlRadius, + 3, + (Math.PI / 2) * (mirror ? -1 : 1) + ); + } + this.humanControl.endFill(); + } +} + +export class SignalTemplate extends JlGraphicTemplate { + constructor(dataTemplate: ISignalData, stateTemplate: ISignalState) { + super(Signal.Type, { dataTemplate, stateTemplate }); + } + new(): Signal { + const g = new Signal(); + g.loadData(this.datas); + g.loadState(this.states); + return g; + } +} diff --git a/src/graphics/signal/SignalCode.ts b/src/graphics/signal/SignalCode.ts new file mode 100644 index 0000000..0b43a4d --- /dev/null +++ b/src/graphics/signal/SignalCode.ts @@ -0,0 +1,50 @@ +import { Container, Graphics, Point } from 'pixi.js'; +import { VectorText } from 'src/jl-graphic'; +import { ISignalData, ISignalState } from './Signal'; + +export enum CodeColorEnum { + defaultCodeColor = '0XFFFFFF', +} + +const signalCodeConsts = { + codeFontSize: 11, + blockedLineWidth: 1, + blockedColor: '0XFF0000', +}; + +export class SignalCode extends Container { + blockedMode: Graphics = new Graphics(); + codeGraph: VectorText = new VectorText(''); + name = 'signalCode'; + constructor() { + super(); + this.addChild(this.blockedMode); + this.addChild(this.codeGraph); + } + paint(datas: ISignalData, states: ISignalState) { + this.codeGraph.text = datas?.code || '信号机编号'; + this.codeGraph.style.fill = CodeColorEnum.defaultCodeColor; + this.codeGraph.setVectorFontSize(signalCodeConsts.codeFontSize); + this.codeGraph.anchor.set(0.5); + this.codeGraph.position.set(0, 0); + this.blockedMode.clear(); + if (states.blocked) { + this.createBlockedMode(); + } + } + createBlockedMode() { + const codeRect = this.codeGraph.getBounds(); + const rectP = this.screenToLocalPoint(new Point(codeRect.x, codeRect.y)); + this.blockedMode.clear(); + this.blockedMode.lineStyle( + signalCodeConsts.blockedLineWidth, + signalCodeConsts.blockedColor + ); + this.blockedMode.drawRect( + rectP.x, + rectP.y, + codeRect.width, + codeRect.height + ); + } +} diff --git a/src/graphics/signal/SignalDrawAssistant.ts b/src/graphics/signal/SignalDrawAssistant.ts new file mode 100644 index 0000000..2ca66e0 --- /dev/null +++ b/src/graphics/signal/SignalDrawAssistant.ts @@ -0,0 +1,167 @@ +import { DisplayObject, FederatedPointerEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; + +import { ISignalData, Signal, SignalTemplate } from './Signal'; + +export interface ISignalDrawOptions { + newData: () => ISignalData; +} + +export class SignalDraw extends GraphicDrawAssistant< + SignalTemplate, + ISignalData +> { + _signal: Signal | null = null; + + constructor(app: JlDrawApp, template: SignalTemplate) { + super( + app, + template, + 'svguse: ../../drawIcon.svg#icon-signal', + '信号机Signal' + ); + + signalInteraction.init(app); + } + + public get signal(): Signal { + if (!this._signal) { + this._signal = this.graphicTemplate.new(); + this.signal.loadData(this.graphicTemplate.datas); + this.container.addChild(this.signal); + } + return this._signal; + } + + onRightClick(): void { + this.createAndStore(true); + } + onLeftUp(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.signal.paint(); + this.container.position.set(p.x, p.y); + } + prepareData(data: ISignalData): boolean { + data.transform = this.container.saveTransform(); + return true; + } +} +/** + * 构建吸附线 + * @param signal + */ +function buildAbsorbablePositions(signal: Signal): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const signals = signal.queryStore.queryByType(Signal.Type); + const canvas = signal.getCanvas(); + signals.forEach((item) => { + if (item.id === signal.id) { + return; + } + const ala = new AbsorbableLine( + new Point(item.x, 0), + new Point(item.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, item.y), + new Point(canvas.width, item.y) + ); + aps.push(ala); + aps.push(alb); + }); + + return aps; +} +/** + * 信号机名称构建吸附线 + * @param signal + */ +function buildCodeAbsorbablePositions(signal: Signal): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const signals = signal.queryStore.queryByType(Signal.Type); + const canvas = signal.getCanvas(); + signals.forEach((item) => { + if (item.id === signal.id) { + return; + } + const codePoint = item.signalCode.getPositionOnCanvas(); + const ala = new AbsorbableLine( + new Point(codePoint.x, 0), + new Point(codePoint.x, canvas.height) + ); + const alb = new AbsorbableLine( + new Point(0, codePoint.y), + new Point(canvas.width, codePoint.y) + ); + aps.push(ala); + aps.push(alb); + }); + return aps; +} + +export class signalInteraction extends GraphicInteractionPlugin { + static Name = 'signal_transform'; + constructor(app: JlDrawApp) { + super(signalInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new signalInteraction(app); + } + filter(...grahpics: JlGraphic[]): Signal[] | undefined { + return grahpics + .filter((g) => g.type === Signal.Type) + .map((g) => g as Signal); + } + bind(g: Signal): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.on('transformstart', this.transformstart, this); + g.signalCode.on('transformstart', this.codetransformstart, this); + g.signalCode.draggable = true; + g.signalCode.selectable = true; + g.signalCode.rotatable = true; + g.signalCode.transformSave = true; + g.signalCode.eventMode = 'static'; + } + + unbind(g: Signal): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('transformstart', this.transformstart, this); + g.signalCode.off('transformstart', this.codetransformstart, this); + g.signalCode.draggable = false; + g.signalCode.selectable = false; + g.signalCode.rotatable = false; + g.signalCode.transformSave = false; + g.signalCode.eventMode = 'none'; + } + transformstart(e: GraphicTransformEvent) { + const target = e.target as DisplayObject; + const signal = target.getGraphic() as Signal; + signal.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(signal), + }); + } + codetransformstart(e: GraphicTransformEvent) { + const target = e.target as DisplayObject; + const signal = target.getGraphic() as Signal; + signal.getGraphicApp().setOptions({ + absorbablePositions: buildCodeAbsorbablePositions(signal), + }); + } +} diff --git a/src/graphics/station/Station.ts b/src/graphics/station/Station.ts new file mode 100644 index 0000000..1956a58 --- /dev/null +++ b/src/graphics/station/Station.ts @@ -0,0 +1,224 @@ +import { Color, Container, Graphics } from 'pixi.js'; +import { + GraphicData, + GraphicState, + JlGraphic, + JlGraphicTemplate, + VectorText, +} from 'src/jl-graphic'; +import { KilometerSystem } from '../signal/Signal'; + +export interface IStationData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get kilometerSystem(): KilometerSystem; + set kilometerSystem(v: KilometerSystem); + get hasControl(): boolean; /// 是否有控制 + set hasControl(v: boolean); + get concentrationStations(): boolean; ////是否集中站 + set concentrationStations(v: boolean); + clone(): IStationData; + copyFrom(data: IStationData): void; + eq(other: IStationData): boolean; +} + +export interface IStationState extends GraphicState { + get ipRtuStusDown(): boolean; + set ipRtuStusDown(v: boolean); + get ipRtuStusInLocalCtrl(): boolean; + set ipRtuStusInLocalCtrl(v: boolean); + get ipRtuStusInCentralCtrl(): boolean; + set ipRtuStusInCentralCtrl(v: boolean); + get ipRtuStusInEmergencyCtrl(): boolean; + set ipRtuStusInEmergencyCtrl(v: boolean); +} + +const stationConsts = { + radius: 3, + borderWidth: 1, + circleColorGrey: '0x808080', + circleColorBlue: '0x08F80D', + circleColorYellow: '0xFFFA0C', + codeColor: '0xF48815', + codeFontSize: 22, + codeControlFontSize: 12, + codeOffsetY: 30, + circleOffsetY: 20, + circleBetweenOffset: 40, + kilometerCodeColor: '0xFFFFFF', + kilometerCodeFontSize: 8, + kilometerCodeOffsetY: -25, +}; +class constrolGraphic extends Container { + circleA: Graphics = new Graphics(); + codeGraphA: VectorText = new VectorText(''); //控制名--站控 + circleB: Graphics = new Graphics(); + codeGraphB: VectorText = new VectorText(''); //控制名--中控 + arrow: Graphics = new Graphics(); + inArrow: Graphics = new Graphics(); + constructor() { + super(); + this.addChild(this.circleA); + this.addChild(this.codeGraphA); + this.addChild(this.circleB); + this.addChild(this.codeGraphB); + this.addChild(this.arrow); + this.addChild(this.inArrow); + this.codeGraphA.setVectorFontSize(stationConsts.codeFontSize); + this.codeGraphB.setVectorFontSize(stationConsts.codeFontSize); + } + draw(states: IStationState): void { + let StationControlFillColor = stationConsts.circleColorGrey; + let centralControlFillColor = stationConsts.circleColorBlue; + let inArrowFillColor = stationConsts.circleColorGrey; + if (states.ipRtuStusInLocalCtrl) { + StationControlFillColor = stationConsts.circleColorYellow; + centralControlFillColor = stationConsts.circleColorGrey; + if (!states.ipRtuStusDown) { + inArrowFillColor = stationConsts.circleColorBlue; + } + } + this.drawCircleCode( + this.circleA, + this.codeGraphA, + '站控', + StationControlFillColor + ); + this.circleA.position.set( + stationConsts.circleBetweenOffset / 2, + stationConsts.circleOffsetY + ); + this.codeGraphA.position.set( + stationConsts.circleBetweenOffset / 2, + stationConsts.codeOffsetY + ); + this.drawCircleCode( + this.circleB, + this.codeGraphB, + '中控', + centralControlFillColor + ); + this.circleB.position.set( + -stationConsts.circleBetweenOffset / 2, + stationConsts.circleOffsetY + ); + this.codeGraphB.position.set( + -stationConsts.circleBetweenOffset / 2, + stationConsts.codeOffsetY + ); + const arrow = this.arrow; + arrow.clear(); + arrow.lineStyle(stationConsts.borderWidth, new Color('0xFFFFFF')); + const points = [0, 0, 2, 2, 2, 1, 14, 1, 14, -1, 2, -1, 2, -2]; + arrow.beginFill('0xFFFFFF'); + arrow.drawPolygon(points); + arrow.endFill(); + arrow.scale.set(1.1, 1.1); + arrow.position.set(-7, stationConsts.circleOffsetY); + const inArrow = this.inArrow; + inArrow.beginFill(inArrowFillColor); + inArrow.drawPolygon(points); + inArrow.endFill(); + inArrow.position.set(-6.5, stationConsts.circleOffsetY); + } + drawCircleCode( + circle: Graphics, + codeGraph: VectorText, + code: string, + fillcolor: string + ): void { + circle.clear(); + circle.lineStyle(stationConsts.borderWidth, new Color(fillcolor)); + circle.beginFill(fillcolor, 1); + circle.drawCircle(0, 0, stationConsts.radius); + circle.endFill; + codeGraph.text = code; + codeGraph.style.fill = fillcolor; + codeGraph.setVectorFontSize(stationConsts.codeControlFontSize); + codeGraph.anchor.set(0.5); + } + clear(): void { + this.circleA.clear(); + this.circleB.clear(); + this.codeGraphA.text = ''; + this.codeGraphB.text = ''; + this.arrow.clear(); + this.inArrow.clear(); + } +} +export class Station extends JlGraphic { + static Type = 'station'; + codeGraph: VectorText = new VectorText(''); //车站名 + kilometerGraph: VectorText = new VectorText(''); //公里标 + controlGraphic: constrolGraphic = new constrolGraphic(); + constructor() { + super(Station.Type); + this.addChild(this.codeGraph); + this.addChild(this.kilometerGraph); + this.addChild(this.controlGraphic); + this.kilometerGraph.name = 'kilometer'; + this.controlGraphic.name = 'trainControl'; + } + + get datas(): IStationData { + return this.getDatas(); + } + get states(): IStationState { + return this.getStates(); + } + doRepaint(): void { + const codeGraph = this.codeGraph; + const kilometerGraph = this.kilometerGraph; + const controlGraphic = this.controlGraphic; + controlGraphic.clear(); + codeGraph.text = this.datas?.code || '车站Station'; + codeGraph.style.fill = stationConsts.codeColor; + codeGraph.setVectorFontSize(stationConsts.codeFontSize); + codeGraph.anchor.set(0.5); + const kilometerCode = this.datas.kilometerSystem?.kilometer || 12345678; + if (Math.floor(kilometerCode * 1000).toString().length > 3) { + const kiloBit = Math.floor(Number(kilometerCode) / 1000000).toString(); + kilometerGraph.text = + 'K' + + kiloBit + + '+' + + ( + Number(kilometerCode.toString().substring(kiloBit.length)) / 1000 + ).toFixed(3); + } else { + kilometerGraph.text = (kilometerCode * 1000).toFixed(3); + } + kilometerGraph.style.fill = stationConsts.kilometerCodeColor; + kilometerGraph.setVectorFontSize(stationConsts.kilometerCodeFontSize); + kilometerGraph.anchor.set(0.5); + kilometerGraph.position.set(0, stationConsts.kilometerCodeOffsetY); + if (this.datas.childTransforms?.length) { + this.datas.childTransforms.forEach((child) => { + if (child.name == 'kilometer') { + const pos = child.transform.position; + kilometerGraph.position.set(pos.x, pos.y); + } + }); + } + if (this.datas.hasControl) { + controlGraphic.draw(this.states); + } + } +} + +export class StationTemplate extends JlGraphicTemplate { + hasControl: boolean; + constructor(dataTemplate: IStationData, stateTemplate: IStationState) { + super(Station.Type, { + dataTemplate, + stateTemplate, + }); + this.hasControl = true; + } + new(): Station { + const station = new Station(); + station.loadData(this.datas); + station.loadState(this.states); + return station; + } +} diff --git a/src/graphics/station/StationDrawAssistant.ts b/src/graphics/station/StationDrawAssistant.ts new file mode 100644 index 0000000..15266cf --- /dev/null +++ b/src/graphics/station/StationDrawAssistant.ts @@ -0,0 +1,123 @@ +import { FederatedPointerEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; + +import { IStationData, Station, StationTemplate } from './Station'; + +export interface IStationDrawOptions { + newData: () => IStationData; +} + +export class StationDraw extends GraphicDrawAssistant< + StationTemplate, + IStationData +> { + codeGraph: Station; + constructor(app: JlDrawApp, template: StationTemplate) { + super( + app, + template, + 'svguse:../../drawIcon.svg#icon-station', + '车站Station' + ); + this.codeGraph = this.graphicTemplate.new(); + this.container.addChild(this.codeGraph); + stationInteraction.init(app); + } + + bind(): void { + super.bind(); + this.codeGraph.loadData(this.graphicTemplate.datas); + this.codeGraph.doRepaint(); + } + + clearCache(): void { + //this.codeGraph.destroy(); + } + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + prepareData(data: IStationData): boolean { + data.transform = this.container.saveTransform(); + data.hasControl = this.graphicTemplate.hasControl; + return true; + } +} + +function buildAbsorbablePositions(station: Station): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const stations = station.queryStore.queryByType(Station.Type); + const { width } = station.getGraphicApp().canvas; + stations.forEach((other) => { + if (other.id == station.id) { + return; + } + const ps = other.datas.transform.position; + const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y }); + aps.push(xs); + }); + return aps; +} + +export class stationInteraction extends GraphicInteractionPlugin { + static Name = 'station_transform'; + constructor(app: JlDrawApp) { + super(stationInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new stationInteraction(app); + } + filter(...grahpics: JlGraphic[]): Station[] | undefined { + return grahpics + .filter((g) => g.type === Station.Type) + .map((g) => g as Station); + } + bind(g: Station): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.controlGraphic.eventMode = 'static'; + g.controlGraphic.cursor = 'pointer'; + g.controlGraphic.draggable = true; + g.controlGraphic.selectable = true; + g.controlGraphic.transformSave = true; + g.kilometerGraph.eventMode = 'static'; + g.kilometerGraph.cursor = 'pointer'; + g.kilometerGraph.draggable = true; + g.kilometerGraph.selectable = true; + g.kilometerGraph.transformSave = true; + g.on('selected', this.onSelected, this); + } + unbind(g: Station): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.controlGraphic.eventMode = 'none'; + g.controlGraphic.draggable = false; + g.controlGraphic.selectable = false; + g.controlGraphic.transformSave = false; + g.kilometerGraph.eventMode = 'none'; + g.kilometerGraph.draggable = false; + g.kilometerGraph.selectable = false; + g.kilometerGraph.transformSave = false; + g.off('selected', this.onSelected, this); + } + onSelected(): void { + const station = this.app.selectedGraphics[0] as Station; + this.app.setOptions({ + absorbablePositions: buildAbsorbablePositions(station), + }); + } +} diff --git a/src/graphics/stationLine/StationLine.ts b/src/graphics/stationLine/StationLine.ts new file mode 100644 index 0000000..3cf0fbc --- /dev/null +++ b/src/graphics/stationLine/StationLine.ts @@ -0,0 +1,144 @@ +import { Color, Container, Graphics, Point } from 'pixi.js'; +import { + GraphicData, + JlGraphic, + JlGraphicTemplate, + VectorText, +} from 'src/jl-graphic'; + +export interface IStationLineData extends GraphicData { + get code(): string; // 编号 + set code(v: string); + get hasTransfer(): boolean; + set hasTransfer(v: boolean); + get hideName(): boolean; + set hideName(v: boolean); + + clone(): IStationLineData; + copyFrom(data: IStationLineData): void; + eq(other: IStationLineData): boolean; +} + +const stationConsts = { + radius: 5, + borderWidth: 1, + borderColor: '0xffffff', + fillColor: '0xffffff', + transferRadius: 3.5, + transferWidth: 0.4, + transferColor: '0xff0000', + codeColor: '0xF48815', + codeFontSize: 8, + codeOffsetY: 20, +}; +//子元素--圆点 +class circleGraphic extends Container { + circle: Graphics = new Graphics(); + arcUp: Graphics = new Graphics(); + arcDown: Graphics = new Graphics(); + arrowUp: Graphics = new Graphics(); + arrowDown: Graphics = new Graphics(); + constructor() { + super(); + this.addChild(this.circle); + this.addChild(this.arcUp); + this.addChild(this.arcDown); + this.addChild(this.arrowUp); + this.addChild(this.arrowDown); + } + draw(datas: IStationLineData): void { + const circle = this.circle; + circle.clear(); + circle.lineStyle( + stationConsts.borderWidth, + new Color(stationConsts.borderColor) + ); + circle.beginFill(stationConsts.fillColor, 1); + circle.drawCircle(0, 0, stationConsts.radius); + circle.endFill; + const arcGraphicUp = this.arcUp; + const arcGraphicDown = this.arcDown; + const arrowUpGraphic = this.arrowUp; + const arrowDownGraphic = this.arrowDown; + arcGraphicUp.clear(); + arcGraphicDown.clear(); + arrowUpGraphic.clear(); + arrowDownGraphic.clear(); + if (datas.hasTransfer) { + this.drawTransfer(arcGraphicUp, arrowUpGraphic); + this.drawTransfer(arcGraphicDown, arrowDownGraphic); + arcGraphicDown.rotation = Math.PI; + arrowDownGraphic.rotation = (Math.PI * 24) / 25; + arrowDownGraphic.position.set(stationConsts.transferRadius, 0); + } + } + drawTransfer(transferGraphic: Graphics, arrowGraphic: Graphics): void { + transferGraphic.lineStyle( + stationConsts.transferWidth, + new Color(stationConsts.transferColor) + ); + transferGraphic.arc( + 0, + 0, + stationConsts.transferRadius, + Math.PI / 10, + Math.PI, + false + ); + arrowGraphic.lineStyle( + stationConsts.transferWidth, + new Color(stationConsts.transferColor) + ); + arrowGraphic.moveTo(0, 0); + arrowGraphic.lineTo(1, 1); + arrowGraphic.moveTo(0, 0); + arrowGraphic.lineTo(-1, 1); + arrowGraphic.position.set(-stationConsts.transferRadius, 0); + arrowGraphic.pivot = new Point(0, 0); + arrowGraphic.rotation = -(Math.PI * 1) / 25; + } +} +export class StationLine extends JlGraphic { + static Type = 'stationLine'; + circleGraphic: circleGraphic = new circleGraphic(); + codeGraph: VectorText = new VectorText(''); //车站名 + + constructor() { + super(StationLine.Type); + this.addChild(this.codeGraph); + this.addChild(this.circleGraphic); + this.codeGraph.name = 'trainLineCode'; + } + + get datas(): IStationLineData { + return this.getDatas(); + } + doRepaint(): void { + this.circleGraphic.draw(this.datas); + const codeGraph = this.codeGraph; + codeGraph.text = this.datas?.code || '车站StationLine'; + codeGraph.style.fill = stationConsts.codeColor; + codeGraph.setVectorFontSize(stationConsts.codeFontSize); + codeGraph.anchor.set(0.5); + codeGraph.visible = !this.datas.hideName; + if (this.datas.childTransforms?.length) { + const pos = this.datas.childTransforms[0].transform.position; + codeGraph.position.set(pos.x, pos.y); + } else { + codeGraph.position.set(0, stationConsts.codeOffsetY); + } + } +} + +export class StationLineTemplate extends JlGraphicTemplate { + hasTransfer: boolean; + constructor(dataTemplate: IStationLineData) { + super(StationLine.Type, { + dataTemplate, + }); + this.hasTransfer = true; + } + new(): StationLine { + return new StationLine(); + } +} diff --git a/src/graphics/stationLine/StationLineDrawAssistant.ts b/src/graphics/stationLine/StationLineDrawAssistant.ts new file mode 100644 index 0000000..3866272 --- /dev/null +++ b/src/graphics/stationLine/StationLineDrawAssistant.ts @@ -0,0 +1,124 @@ +import { FederatedPointerEvent, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; + +import { + IStationLineData, + StationLine, + StationLineTemplate, +} from './StationLine'; +import { RunLine } from '../runLine/RunLine'; + +export interface IStationLineDrawOptions { + newData: () => IStationLineData; +} + +export class StationLineDraw extends GraphicDrawAssistant< + StationLineTemplate, + IStationLineData +> { + codeGraph: StationLine; + constructor(app: JlDrawApp, template: StationLineTemplate) { + super( + app, + template, + 'svguse:../../drawIcon.svg#icon-station', + '车站StationLine' + ); + this.codeGraph = this.graphicTemplate.new(); + this.container.addChild(this.codeGraph); + stationLineInteraction.init(app); + } + + bind(): void { + super.bind(); + this.codeGraph.loadData(this.graphicTemplate.datas); + this.codeGraph.doRepaint(); + } + + clearCache(): void { + //this.codeGraph.destroy(); + } + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + prepareData(data: IStationLineData): boolean { + const template = this.graphicTemplate; + data.transform = this.container.saveTransform(); + data.hasTransfer = template.hasTransfer; + return true; + } +} + +/** + * 构建吸附位置 + * @param polygon + * @returns + */ +function buildAbsorbablePositions(Station: StationLine): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const runLines = Station.queryStore.queryByType(RunLine.Type); + runLines.forEach((runLine) => { + const points = runLine.datas.points; + for (let i = 0; i < points.length - 1; i++) { + aps.push(new AbsorbableLine(points[i], points[i + 1])); + } + }); + return aps; +} + +export class stationLineInteraction extends GraphicInteractionPlugin { + static Name = 'stationLine_transform'; + static stationLine: StationLine; + constructor(app: JlDrawApp) { + super(stationLineInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new stationLineInteraction(app); + } + filter(...grahpics: JlGraphic[]): StationLine[] | undefined { + return grahpics + .filter((g) => g.type === StationLine.Type) + .map((g) => g as StationLine); + } + bind(g: StationLine): void { + stationLineInteraction.stationLine = g; + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.codeGraph.eventMode = 'static'; + g.codeGraph.cursor = 'pointer'; + g.codeGraph.draggable = true; + g.codeGraph.selectable = true; + g.codeGraph.transformSave = true; + g.on('selected', this.onSelected, this); + } + unbind(g: StationLine): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.codeGraph.eventMode = 'none'; + g.codeGraph.draggable = false; + g.codeGraph.selectable = false; + g.codeGraph.transformSave = false; + } + onSelected(): void { + this.app.setOptions({ + absorbablePositions: buildAbsorbablePositions( + stationLineInteraction.stationLine + ), + }); + } +} diff --git a/src/graphics/train/Train.ts b/src/graphics/train/Train.ts new file mode 100644 index 0000000..7e20031 --- /dev/null +++ b/src/graphics/train/Train.ts @@ -0,0 +1,401 @@ +import { Color, Graphics, Container, Point } from 'pixi.js'; +import { + GraphicData, + GraphicState, + JlGraphic, + JlGraphicTemplate, + VectorText, + calculateMirrorPoint, +} from 'src/jl-graphic'; +import { train } from 'src/protos/train'; +import { state } from 'src/protos/device_status'; + +export interface ITrainData extends GraphicData { + get code(): string; // 车号 + set code(v: string); + clone(): ITrainData; + copyFrom(data: ITrainData): void; + eq(other: ITrainData): boolean; +} + +export interface ITrainState extends GraphicState { + get lineId(): number; // 线路id + set lineId(v: number); + get rtuId(): number; // 集中站站号 + set rtuId(v: number); + get window(): train.NccWindow; // NccWindow + set window(v: train.NccWindow); + get devType(): state.DeviceType; // 所在设备类型 + set devType(v: state.DeviceType); + get devName(): string; // 所在设备名称 + set devName(v: string); + get id(): string; // 设备唯一 + set id(v: string); + get groupId(): string; // 列车车组号 + set groupId(v: string); + get trainId(): string; // 列车表号 + set trainId(v: string); + get globalId(): string; // 列车车次号 + set globalId(v: string); + get destinationId(): number; // 目的地ID + set destinationId(v: number); + get rollingStock(): number; // 编组数量 + set rollingStock(v: number); + get driverId(): string; // 司机号 + set driverId(v: string); + get otpTime(): number; // 计划偏离时间 + set otpTime(v: number); + get mode(): state.TrainMode; // 列车状态 + set mode(v: state.TrainMode); + get arriveTime(): number; // 到点 + set arriveTime(v: number); + get departTime(): number; // 发点 + set departTime(v: number); + get speed(): number; // 速度 + set speed(v: number); + get show(): boolean; // 是否显示 + set show(v: boolean); + get type(): boolean; // 车次号变化状态 + set type(v: boolean); + get routeId(): number; // 运行路径号 + set routeId(v: number); + get rate(): number; // 满载率 + set rate(v: number); +} + +interface bodyWH { + width: number; // 宽 + height: number; // 高 +} + +// 列车颜色 +export enum TrainColorEnum { + headColor = '0xFFCE4D', // 箭头颜色 + bodyColor = '0xA388B1', // 背景色 + codeColor = '0xffffff', // 车号颜色 + borderColor = '0xA3E198', // 边框的颜色 + directionColor = '0x00FF00', // 方向箭头颜色 +} + +enum diriveModelColorEnum { // 驾驶模式对应颜色 + AM = '0x00FF00', // ATO自动驾驶 + SM = '0xFFFF00', // ATP 监控下的人工驾驶模式 + RM = '0xFFC837', // 限制人工驾驶模式 + NRM = '0xA0522D', // 非限制人工驾驶模式 + red = '0xF80103', // 红色表示通信中断 +} +enum AAColorEnum { // 识别号AA颜色 + accuracy = '0xffffff', // 准点 + early = '0x00FF00', // 早点 + late = '0xA0522D', // 晚点 +} +enum typeColorEnum { // 识别号BBB颜色 + schedule = '0xffffff', // 计划车 + head = '0xE9FC01', // 头码车 + manual = '0xE9FC01', // 人工车 + special = '0xE9FC01', // 特殊车 +} + +enum statusTextColor { + H = '0xFFFF00', // H扣车 + S = '0x6260F3', // S跳停 + D = '0x00FF00', // D开门 + A = '0xFF0000', // A报警 +} + +export const trainConsts = { + codeWidth: 120, + codeHeight: 40, + codePadding: 5, + borderWidth: 1, + codeFontSize: 22, + textFontSize: 16, // 状态字母大小 + textMarginY: 10, // 状态字母与列车距离 + statusTextList: ['H', 'S', 'D', 'A'], + marginX: 2, // 图形x轴边距 + pauseW: 2, // 停止框宽度 +}; + +export class TrainHead extends Container { + arrow: Graphics; // 箭头 + pause: Graphics; // 停止 + constructor() { + super(); + this.arrow = new Graphics(); + this.pause = new Graphics(); + this.addChild(this.arrow); + this.addChild(this.pause); + } + clear() { + this.arrow.clear(); + this.pause.clear(); + } + doRepaint(states: ITrainState, bodyWH?: bodyWH) { + let direction = ''; + if (states.mode?.ipModeTrainDirUp) { + direction = 'left'; + } + if (states.mode?.ipModeTrainDirDown) { + direction = 'right'; + } + this.clear(); + if (!direction) { + return; + } + const marginX = trainConsts.marginX; + const pauseW = trainConsts.pauseW; + const codeWidth = bodyWH ? bodyWH.width : trainConsts.codeWidth; + const codeHeight = bodyWH ? bodyWH.height : trainConsts.codeHeight; + let arrowPoint = [ + -codeHeight * 0.4 - marginX - pauseW - marginX - codeWidth / 2, + 0, + -marginX - pauseW - marginX - codeWidth / 2, + codeHeight / 2, + -marginX - pauseW - marginX - codeWidth / 2, + -codeHeight / 2, + ]; + let pausePoint = [ + -marginX - pauseW / 2 - codeWidth / 2, + -codeHeight / 2, + -marginX - pauseW / 2 - codeWidth / 2, + codeHeight / 2, + ]; + if (direction != 'left') { + const aP: Array = []; + arrowPoint.forEach((item, index) => { + if (index % 2 == 1) { + const p = new Point(arrowPoint[index - 1], item); + const newP = calculateMirrorPoint(new Point(0, 0), p); + aP.push(newP.x, newP.y); + } + }); + arrowPoint = aP; + const pP: Array = []; + pausePoint.forEach((item, index) => { + if (index % 2 == 1) { + const p = new Point(pausePoint[index - 1], item); + const newP = calculateMirrorPoint(new Point(0, 0), p); + pP.push(newP.x, newP.y); + } + }); + pausePoint = pP; + } + const arrow = this.arrow; + arrow.beginFill(TrainColorEnum.headColor, 1); + arrow.drawPolygon(arrowPoint); + arrow.endFill(); + this.pause.lineStyle(pauseW, TrainColorEnum.headColor, 1); + this.pause.moveTo(pausePoint[0], pausePoint[1]); + this.pause.lineTo(pausePoint[2], pausePoint[3]); + } + stop() { + this.pause.visible = true; + this.arrow.visible = false; + } + run() { + this.pause.visible = false; + this.arrow.visible = true; + } +} + +export class TrainBody extends Container { + codeRact: Graphics; + codeAGraph: VectorText = new VectorText(''); //识别号AA + codeBGraph: VectorText = new VectorText(''); //识别号BBB + constructor() { + super(); + this.codeRact = new Graphics(); + this.addChild(this.codeRact); + this.addChild(this.codeAGraph); + this.addChild(this.codeBGraph); + this.codeAGraph.setVectorFontSize(trainConsts.codeFontSize); + this.codeBGraph.setVectorFontSize(trainConsts.codeFontSize); + } + clear() { + this.codeRact.clear(); + } + getBodyWH(): bodyWH { + const bodyAWH = this.codeAGraph.getLocalBounds(); + const bodyBWH = this.codeBGraph.getLocalBounds(); + return { + width: bodyAWH.width + bodyBWH.width + trainConsts.codePadding * 2, + height: bodyAWH.height + trainConsts.codePadding * 2, + }; + } + + doRepaint(states: ITrainState): void { + this.clear(); + const codeAGraph = this.codeAGraph; + const codeBGraph = this.codeBGraph; + const codeRact = this.codeRact; + let codeA = states?.trainId; + let fillAColor = AAColorEnum.accuracy; + if (states.mode?.ipModeTrainTypeSchedule) { + if (states?.otpTime > 0) { + fillAColor = AAColorEnum.late; + } else if (states?.otpTime < 0) { + fillAColor = AAColorEnum.early; + } + } + let fillBColor = typeColorEnum.schedule; + if (states.mode?.ipModeTrainTypeHead) { + codeA = states?.destinationId + ''; + fillBColor = typeColorEnum.head; + } else if (states.mode?.ipModeTrainTypeManual) { + codeA = 'MM'; + fillBColor = typeColorEnum.manual; + } else if (states.mode?.ipModeTrainTypeSpecial) { + codeA = ''; + } + const codeB = states?.globalId; + codeAGraph.text = codeA || '01'; + codeBGraph.text = codeB || '2222'; + codeAGraph.anchor.set(0.5); + codeBGraph.anchor.set(0.5); + const styleA = { + fill: fillAColor, + fontSize: trainConsts.codeFontSize, + }; + const styleB = { + fill: fillBColor, + fontSize: trainConsts.codeFontSize, + }; + codeAGraph.style = styleA; + codeBGraph.style = styleB; + const bodyAWH = codeAGraph.getLocalBounds(); + const bodyBWH = codeBGraph.getLocalBounds(); + codeAGraph.position.set(-bodyBWH.width / 2, 0); + codeBGraph.position.set(bodyAWH.width / 2, 0); + codeAGraph.updateOnScaled(); + codeBGraph.updateOnScaled(); + const { width: codeWidth, height: codeHeight } = this.getBodyWH(); + codeRact.lineStyle( + trainConsts.borderWidth, + new Color(TrainColorEnum.borderColor) + ); + codeRact.beginFill(new Color(TrainColorEnum.bodyColor)); + codeRact.drawRect(-codeWidth / 2, -codeHeight / 2, codeWidth, codeHeight); + codeRact.endFill(); + } +} + +class StatusText extends Container { + sText: VectorText = new VectorText(''); + constructor() { + super(); + this.addChild(this.sText); + } + doRepaint(text: string, bodyWH: bodyWH): void { + this.sText.text = text; + this.sText.anchor.set(0.5); + const c = (statusTextColor as never)[text] || statusTextColor.D; + const style = { + fill: c, + fontSize: trainConsts.textFontSize, + }; + this.sText.style = style; + const { width: codeWidth, height: codeHeight } = bodyWH; + const { width: textHWidth, height: textHeight } = + this.sText.getLocalBounds(); + const num = trainConsts.statusTextList.length; + let index = trainConsts.statusTextList.findIndex((item) => { + return item == text; + }); + if (index < 0) { + index = 1.5; // 中间 + } + const textMargin = (codeWidth - textHWidth * num) / (num - 1); + this.sText.position.set( + -codeWidth / 2 + (textHWidth * (index * 2 + 1)) / 2 + textMargin * index, + -codeHeight / 2 - textHeight / 2 - trainConsts.textMarginY + ); + } + clear(): void { + this.sText.text = ''; + } +} + +export class Train extends JlGraphic { + static Type = 'Train'; + + trainHead: TrainHead; + trainbody: TrainBody; + statusTextMap: Map = new Map(); + constructor() { + super(Train.Type); + this.trainbody = new TrainBody(); + this.trainHead = new TrainHead(); + this.addChild(this.trainHead); + this.addChild(this.trainbody); + } + + get datas(): ITrainData { + return this.getDatas(); + } + + get states(): ITrainState { + return this.getStates(); + } + + doRepaint(): void { + this.trainbody.doRepaint(this.states); + const bodyWH = this.trainbody.getBodyWH(); + this.trainHead.doRepaint(this.states, bodyWH); + } + + stop() { + this.trainHead.stop(); + } + run() { + this.trainHead.run(); + } + + showStatus(s: string) { + if (this.statusTextMap.has(s)) { + return; + } + const bodyWH = this.trainbody.getBodyWH(); + const textD = new StatusText(); + textD.doRepaint(s, bodyWH); + this.addChild(textD); + this.statusTextMap.set(s, textD); + } + hideStatus(s: string) { + if (!this.statusTextMap.has(s)) { + return; + } + const textD = this.statusTextMap.get(s); + if (textD) { + textD.clear(); + this.statusTextMap.delete(s); + } + } + chagneDirection(): void { + const bodyWH = this.trainbody.getBodyWH(); + this.trainHead.doRepaint(this.states, bodyWH); + } + chagneState(): void { + if (this.states.mode?.ipModeTrainHolded) { + this.showStatus('H'); + } else { + this.hideStatus('H'); + } + if (this.states.mode?.ipModeTrainDoorOpen) { + this.showStatus('D'); + } else { + this.hideStatus('D'); + } + } +} + +export class TrainTemplate extends JlGraphicTemplate { + constructor(dataTemplate: ITrainData, stateTemplate: ITrainState) { + super(Train.Type, { dataTemplate, stateTemplate }); + } + new(): Train { + const train = new Train(); + train.loadData(this.datas); + train.loadState(this.states); + return train; + } +} diff --git a/src/graphics/train/TrainDrawAssistant.ts b/src/graphics/train/TrainDrawAssistant.ts new file mode 100644 index 0000000..65577e0 --- /dev/null +++ b/src/graphics/train/TrainDrawAssistant.ts @@ -0,0 +1,71 @@ +import { Point, FederatedPointerEvent } from 'pixi.js'; +import { + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; + +import { ITrainData, Train, TrainTemplate } from './Train'; + +export interface ITrainDrawOptions { + newData: () => ITrainData; +} + +export class TrainDraw extends GraphicDrawAssistant { + _Train: Train | null = null; + + constructor(app: JlDrawApp, template: TrainTemplate) { + super(app, template, 'directions_bus_filled', '不展示'); + trainInteraction.init(app); + } + + public get Train(): Train { + if (!this._Train) { + this._Train = this.graphicTemplate.new(); + this.Train.loadData(this.graphicTemplate.datas); + this.container.addChild(this.Train); + } + return this._Train; + } + + redraw(p: Point): void { + this.Train.doRepaint(); + this.container.position.set(p.x, p.y); + } + onRightClick(): void { + this.createAndStore(true); + } + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + prepareData(data: ITrainData): boolean { + data.transform = this.container.saveTransform(); + return true; + } +} + +export class trainInteraction extends GraphicInteractionPlugin { + static Name = 'train_transform'; + constructor(app: JlDrawApp) { + super(trainInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new trainInteraction(app); + } + filter(...grahpics: JlGraphic[]): Train[] | undefined { + return grahpics.filter((g) => g.type === Train.Type).map((g) => g as Train); + } + bind(g: Train): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + } + unbind(g: Train): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + } +} diff --git a/src/graphics/trainLine/TrainLine.ts b/src/graphics/trainLine/TrainLine.ts new file mode 100644 index 0000000..ea326d6 --- /dev/null +++ b/src/graphics/trainLine/TrainLine.ts @@ -0,0 +1,81 @@ +import { + GraphicData, + GraphicState, + GraphicIdGenerator, + JlGraphic, + JlGraphicTemplate, +} from 'src/jl-graphic'; +import trainLineSprites from './trainLineSprites.png'; + +import { Assets, Sprite, Texture } from 'pixi.js'; + +export interface ITrainLineData extends GraphicData { + get code(): string; + set code(v: string); +} + +export interface ITrainLineState extends GraphicState { + get lineId(): number; + set lineId(v: number); + get trainIndex(): string; + set trainIndex(v: string); + get groupId(): string; + set groupId(v: string); + get show(): boolean; + set show(v: boolean); + get kilometerCode(): number; + set kilometerCode(v: number); + get dir(): number; + set dir(v: number); +} + +export class TrainLine extends JlGraphic { + static Type = 'TrainLine'; + train: Sprite; + trainTextures: Texture; + + constructor(trainTextures: Texture) { + super(TrainLine.Type); + this.trainTextures = trainTextures; + this.train = new Sprite(); + this.train.texture = this.trainTextures; + this.train.anchor.set(0.5); + this.train.scale.set(0.02, 0.02); + this.addChild(this.train); + } + get states(): ITrainLineState { + return this.getStates(); + } + doRepaint(): void { + this.train.texture = this.trainTextures; + // console.log(this.states, '****'); + // this.train.position.set(100, 100); + // const runLine = this.queryStore.queryById(this.states.lineId + ''); + } +} + +export class ItrainLineTemplate extends JlGraphicTemplate { + trainTextures?: Texture; + constructor(dataTemplate: ITrainLineData, stateTemplate: ITrainLineState) { + super(TrainLine.Type, { + dataTemplate, + stateTemplate, + }); + } + new(): TrainLine { + if (this.trainTextures) { + const data = this.datas as GraphicData; + data.id = GraphicIdGenerator.next(); + data.graphicType = this.type; + const g = new TrainLine(this.trainTextures); + g.loadData(data); + g.loadState(this.states); + return g; + } + throw new Error('资源未加载/加载失败'); + } + async loadAssets(): Promise { + this.trainTextures = await Assets.load(trainLineSprites); + return this.trainTextures as Texture; + } +} diff --git a/src/graphics/trainLine/TrainLineAssistant.ts b/src/graphics/trainLine/TrainLineAssistant.ts new file mode 100644 index 0000000..ce26b49 --- /dev/null +++ b/src/graphics/trainLine/TrainLineAssistant.ts @@ -0,0 +1,76 @@ +import { FederatedMouseEvent, Point } from 'pixi.js'; +import { + GraphicDrawAssistant, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, +} from 'src/jl-graphic'; +import { ITrainLineData, TrainLine, ItrainLineTemplate } from './TrainLine'; + +export class TrainLineDraw extends GraphicDrawAssistant< + ItrainLineTemplate, + ITrainLineData +> { + train: TrainLine | null = null; + + constructor(app: JlDrawApp, template: ItrainLineTemplate) { + super(app, template, 'directions_bus_filled', '列车线网'); + ItrainLineInteraction.init(app); + } + + bind(): void { + super.bind(); + if (!this.train) { + this.train = this.graphicTemplate.new(); + this.container.addChild(this.train); + } + } + + public get trainLine(): TrainLine { + if (!this.train) { + throw new Error('列车绘制逻辑异常'); + } + return this.train; + } + + redraw(cp: Point): void { + this.trainLine.position.copyFrom(cp); + } + onLeftUp(e: FederatedMouseEvent): void { + this.trainLine.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(false); + } + prepareData(data: ITrainLineData): boolean { + data.transform = this.trainLine.saveTransform(); + return true; + } + onEsc(): void { + this.finish(); + } +} + +export class ItrainLineInteraction extends GraphicInteractionPlugin { + static Name = 'trainLine_transform'; + constructor(app: JlDrawApp) { + super(ItrainLineInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new ItrainLineInteraction(app); + } + filter(...grahpics: JlGraphic[]): TrainLine[] | undefined { + return grahpics + .filter((g) => g.type === TrainLine.Type) + .map((g) => g as TrainLine); + } + bind(g: TrainLine): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + } + unbind(g: TrainLine): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + } +} diff --git a/src/graphics/trainLine/trainLineSprites.png b/src/graphics/trainLine/trainLineSprites.png new file mode 100644 index 0000000000000000000000000000000000000000..75e8a93df77e817cc660dbcf1f50a139eb2836a7 GIT binary patch literal 8918 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 z-(); + } + doRepaint(): void { + const section = this.queryStore.queryById
(this.datas.sectionId); + let width = TrainWindowConsts.width; + if (section.datas.sectionType == SectionType.Logic) { + const ps = section.getStartPoint(); + const pe = section.getEndPoint(); + width = distance2(ps, pe); + } + const rectGraphic = this.rectGraphic; + rectGraphic.clear(); + rectGraphic.lineStyle( + TrainWindowConsts.lineWidth, + new Color(TrainWindowConsts.lineColor) + ); + rectGraphic.drawRect(0, 0, width, TrainWindowConsts.height); + const rectP = new Rectangle(0, 0, width, TrainWindowConsts.height); + rectGraphic.pivot = getRectangleCenter(rectP); + } + loadRelations(): void { + const sectionId = this.datas.sectionId; + if (sectionId) { + const section = this.queryStore.queryById
(sectionId); + if (section) { + this.relationManage.addRelation( + this, + new GraphicRelationParam(section, section.datas.id) + ); + } + } + } + getRelatedSections(): Section[] { + return this.queryRelationByType('Section').map((rl) => + rl.getOtherGraphic
(this) + ); + } +} + +export class TrainWindowTemplate extends JlGraphicTemplate { + constructor(dataTemplate: ITrainWindowData) { + super(TrainWindow.Type, { + dataTemplate, + }); + } + new(): TrainWindow { + return new TrainWindow(); + } +} diff --git a/src/graphics/trainWindow/TrainWindowDrawAssistant.ts b/src/graphics/trainWindow/TrainWindowDrawAssistant.ts new file mode 100644 index 0000000..f0e117e --- /dev/null +++ b/src/graphics/trainWindow/TrainWindowDrawAssistant.ts @@ -0,0 +1,227 @@ +import { FederatedPointerEvent, IHitArea, Point } from 'pixi.js'; +import { + AbsorbableLine, + AbsorbablePosition, + GraphicDrawAssistant, + GraphicIdGenerator, + GraphicInteractionPlugin, + JlDrawApp, + JlGraphic, + distance2, + linePoint, +} from 'src/jl-graphic'; + +import { + ITrainWindowData, + TrainWindow, + TrainWindowTemplate, + TrainWindowConsts, +} from './TrainWindow'; +import { Section, SectionType } from '../section/Section'; + +export interface ITrainWindowDrawOptions { + newData: () => ITrainWindowData; +} + +export class GenerateParams { + count: number; + interval: number; + pd: boolean; // 是否在右侧开始添加 + constructor(count: number, interval: number, pd: boolean) { + this.count = count; + this.interval = interval; + this.pd = pd; + } +} + +export class TrainWindowDraw extends GraphicDrawAssistant< + TrainWindowTemplate, + ITrainWindowData +> { + trainWindowGraph: TrainWindow; + constructor(app: JlDrawApp, template: TrainWindowTemplate) { + super(app, template, 'sym_o_square', '不展示'); + this.trainWindowGraph = this.graphicTemplate.new(); + this.container.addChild(this.trainWindowGraph); + TrainWindowInteraction.init(app); + } + + bind(): void { + super.bind(); + this.trainWindowGraph.loadData(this.graphicTemplate.datas); + this.trainWindowGraph.doRepaint(); + } + + onLeftDown(e: FederatedPointerEvent): void { + this.container.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + + prepareData(data: ITrainWindowData): boolean { + data.transform = this.container.saveTransform(); + return true; + } + generates(trainWindow: TrainWindow, params: GenerateParams): void { + const { count, pd } = params; + let { interval } = params; + const ps = trainWindow.datas.transform.position; + let direction; + if (pd) { + direction = 1; + interval = direction * interval; + } else { + direction = -1; + interval = direction * interval; + } + const p = new Point( + ps.x + direction * TrainWindowConsts.width + interval, + ps.y + ); + const trainWindows: TrainWindow[] = []; + + for (let i = 0; i < count; i++) { + const point = p.clone(); + const offsetX = (direction * TrainWindowConsts.width + interval) * i; + point.x += offsetX; + const trainWindow = new TrainWindow(); + trainWindow.loadData(this.graphicTemplate.datas); + trainWindow.position.copyFrom(point); + trainWindow.id = GraphicIdGenerator.next(); + trainWindows.push(trainWindow); + } + this.storeGraphic(...trainWindows); + } + draw(x: number, ps: Point, direction: number, section: Section) { + const trainWindow = new TrainWindow(); + trainWindow.loadData(this.graphicTemplate.datas); + trainWindow.position.set( + x, + ps.y - direction * TrainWindowConsts.offsetSection + ); + trainWindow.id = GraphicIdGenerator.next(); + trainWindow.datas.sectionId = section.id; + this.storeGraphic(trainWindow); + trainWindow.loadRelations(); + } + oneGenerates(height: Point) { + const sections = this.app.queryStore.queryByType
(Section.Type); + const trainWindowAll = this.app.queryStore.queryByType( + TrainWindow.Type + ); + this.app.deleteGraphics(...trainWindowAll); + sections.forEach((section) => { + const ps = section.localToCanvasPoint(section.getStartPoint()); + const pe = section.localToCanvasPoint(section.getEndPoint()); + let direction = 1; + if (ps.y > height.y) { + direction = -1; + } + const x = (ps.x + pe.x) / 2; + if (section.datas.children.length) { + section.childSections.forEach((childSection) => { + const psChild = childSection.localToCanvasPoint( + childSection.getStartPoint() + ); + this.draw(psChild.x, psChild, direction, childSection); + }); + } else { + this.draw(x, ps, direction, section); + } + }); + } +} + +//碰撞检测 +export class RectGraphicHitArea implements IHitArea { + rect: TrainWindow; + constructor(rect: TrainWindow) { + this.rect = rect; + } + contains(x: number, y: number): boolean { + const section = this.rect.queryStore.queryById
( + this.rect.datas.sectionId + ); + let width = TrainWindowConsts.width; + if (section.datas.sectionType == SectionType.Logic) { + const ps = section.getStartPoint(); + const pe = section.getEndPoint(); + width = distance2(ps, pe); + } + let contains = false; + const tolerance = TrainWindowConsts.lineWidth; + const p1 = new Point(0, 0); + const p2 = new Point(width, 0); + const p3 = new Point(width, TrainWindowConsts.height); + const p4 = new Point(0, TrainWindowConsts.height); + const p = new Point(x, y); + + contains = contains || linePoint(p1, p2, p, tolerance); + contains = contains || linePoint(p2, p3, p, tolerance); + contains = contains || linePoint(p3, p4, p, tolerance); + contains = contains || linePoint(p4, p1, p, tolerance); + return contains; + } +} + +/** + * 构建吸附位置 + * @param polygon + * @returns + */ +function buildAbsorbablePositions( + trainWindow: TrainWindow +): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + const trainWindows = trainWindow.queryStore.queryByType( + TrainWindow.Type + ); + const { width } = trainWindow.getGraphicApp().canvas; + trainWindows.forEach((other) => { + if (other.id == trainWindow.id) { + return; + } + const ps = other.datas.transform.position; + const xs = new AbsorbableLine({ x: 0, y: ps.y }, { x: width, y: ps.y }); + aps.push(xs); + }); + return aps; +} + +export class TrainWindowInteraction extends GraphicInteractionPlugin { + static Name = 'TrainWindow_transform'; + constructor(app: JlDrawApp) { + super(TrainWindowInteraction.Name, app); + } + static init(app: JlDrawApp) { + return new TrainWindowInteraction(app); + } + filter(...grahpics: JlGraphic[]): TrainWindow[] | undefined { + return grahpics + .filter((g) => g.type === TrainWindow.Type) + .map((g) => g as TrainWindow); + } + bind(g: TrainWindow): void { + g.eventMode = 'static'; + g.cursor = 'pointer'; + g.scalable = true; + g.rotatable = true; + g.rectGraphic.hitArea = new RectGraphicHitArea(g); + g.on('transformstart', this.move, this); + } + unbind(g: TrainWindow): void { + g.eventMode = 'none'; + g.scalable = false; + g.rotatable = false; + g.off('selected', this.move, this); + } + move(): void { + const trainWindow = this.app.selectedGraphics[0] as TrainWindow; + this.app.setOptions({ + absorbablePositions: buildAbsorbablePositions(trainWindow), + }); + } +} diff --git a/src/graphics/trainWindow/oneClickDrawAssistant.ts b/src/graphics/trainWindow/oneClickDrawAssistant.ts new file mode 100644 index 0000000..c0c52b9 --- /dev/null +++ b/src/graphics/trainWindow/oneClickDrawAssistant.ts @@ -0,0 +1,81 @@ +import { Color, FederatedPointerEvent, Graphics, Point } from 'pixi.js'; +import { + GraphicData, + GraphicDrawAssistant, + JlDrawApp, + JlGraphic, + JlGraphicTemplate, +} from 'src/jl-graphic'; +import { TrainWindow } from './TrainWindow'; +import { TrainWindowDraw } from './TrainWindowDrawAssistant'; +import { AxleCounting } from '../axleCounting/AxleCounting'; +import { AxleCountingDraw } from '../axleCounting/AxleCountingDrawAssistant'; +import { useDrawStore } from 'src/stores/draw-store'; + +interface IOneClickData extends GraphicData { + get code(): string; // 编号 +} + +export class OneClickGenerate extends JlGraphic { + static Type = 'OneClickGenerate'; + lineGraphic: Graphics = new Graphics(); + constructor() { + super(OneClickGenerate.Type); + this.addChild(this.lineGraphic); + } + + doRepaint(): void { + this.lineGraphic.clear(); + this.lineGraphic.lineStyle(1, new Color('0xff0000')); + this.lineGraphic.moveTo(-1920, 0); + this.lineGraphic.lineTo(1920, 0); + } +} + +export class OneClickGenerateTemplate extends JlGraphicTemplate { + constructor() { + super(OneClickGenerate.Type, {}); + } + new(): OneClickGenerate { + return new OneClickGenerate(); + } +} + +export class OneClickGenerateDraw extends GraphicDrawAssistant< + OneClickGenerateTemplate, + IOneClickData +> { + lineGraph: OneClickGenerate; + constructor(app: JlDrawApp, template: OneClickGenerateTemplate) { + super(app, template, 'sym_o_square', '不展示'); + this.lineGraph = this.graphicTemplate.new(); + this.container.addChild(this.lineGraph); + } + + bind(): void { + super.bind(); + this.lineGraph.doRepaint(); + } + onLeftDown(e: FederatedPointerEvent): void { + const type = useDrawStore().$state.oneClickType; + if (type == 'TrainWindow') { + const trainWindowDraw = this.app.getDrawAssistant( + TrainWindow.Type + ) as TrainWindowDraw; + trainWindowDraw.oneGenerates(this.toCanvasCoordinates(e.global)); + } else { + const axleCountingDraw = this.app.getDrawAssistant( + AxleCounting.Type + ) as AxleCountingDraw; + axleCountingDraw.oneGenerates(this.toCanvasCoordinates(e.global)); + } + this.finish(); + } + + redraw(p: Point): void { + this.container.position.copyFrom(p); + } + prepareData(): boolean { + return true; + } +} diff --git a/src/graphics/turnout/Turnout.ts b/src/graphics/turnout/Turnout.ts new file mode 100644 index 0000000..9d83f43 --- /dev/null +++ b/src/graphics/turnout/Turnout.ts @@ -0,0 +1,351 @@ +import { Graphics, IPointData } from 'pixi.js'; +import { + GraphicData, + GraphicRelationParam, + GraphicState, + JlGraphic, + JlGraphicTemplate, + VectorText, + angleOfIncludedAngle, + distance2, +} from 'src/jl-graphic'; +import { Section, SectionPort } from '../section/Section'; +import { epsilon } from 'src/jl-graphic/math'; +import { + IRelatedRefData, + createRelatedRefProto, + protoPort2Data, +} from '../CommonGraphics'; +import { KilometerSystem } from '../signal/Signal'; + +export interface ITurnoutData extends GraphicData { + get code(): string; + set code(code: string); + get pointA(): IPointData[]; //A端点列表(从岔心向外) + set pointA(point: IPointData[]); + get pointB(): IPointData[]; + set pointB(point: IPointData[]); + get pointC(): IPointData[]; + set pointC(point: IPointData[]); + get paRef(): IRelatedRefData | undefined; + set paRef(ref: IRelatedRefData | undefined); + get pbRef(): IRelatedRefData | undefined; + set pbRef(ref: IRelatedRefData | undefined); + get pcRef(): IRelatedRefData | undefined; + set pcRef(ref: IRelatedRefData | undefined); + get kilometerSystem(): KilometerSystem[]; + set kilometerSystem(v: KilometerSystem[]); + clone(): ITurnoutData; + copyFrom(data: ITurnoutData): void; + eq(other: ITurnoutData): boolean; +} + +export const TurnoutConsts = { + lineColor: '#5578b6', + lineWidth: 5, + forkLenth: 20, + labelFontSize: 12, +}; + +export enum TurnoutPosition { + NORMAL = 0, + REVERSE = 1, +} + +export enum TurnoutPort { + A = 'A', + B = 'B', + C = 'C', +} + +export interface ITurnoutState extends GraphicState { + position: TurnoutPosition; +} + +export function getForkPoint(r: number, p: IPointData): IPointData { + if (r === 0) return { x: 0, y: 0 }; + const len = Math.sqrt((-p.x) ** 2 + (-p.y) ** 2); + const scale = r / len; + return { x: scale * p.x, y: scale * p.y }; +} + +export class TurnoutSection extends Graphics { + turnout: Turnout; + port: TurnoutPort; + constructor(turnout: Turnout, port: TurnoutPort) { + super(); + this.turnout = turnout; + this.port = port; + } + + paint() { + let pList: IPointData[] = []; + switch (this.port) { + case TurnoutPort.A: + pList = this.turnout.datas.pointA; + break; + case TurnoutPort.B: + pList = this.turnout.datas.pointB; + break; + case TurnoutPort.C: + pList = this.turnout.datas.pointC; + break; + } + const gap = this.port === TurnoutPort.A ? 0 : TurnoutConsts.forkLenth; + const start = getForkPoint(gap, pList[0]); + this.clear() + .lineStyle(TurnoutConsts.lineWidth, TurnoutConsts.lineColor) + .moveTo(start.x, start.y); + pList.forEach((p) => { + const { x, y } = p; + this.lineTo(x, y); + }); + } +} + +class ForkGraphic extends Graphics { + turnout: Turnout; + constructor(turnout: Turnout) { + super(); + this.turnout = turnout; + } + + paint(p: IPointData) { + const target = getForkPoint(TurnoutConsts.forkLenth, p); + this.clear() + .lineStyle(TurnoutConsts.lineWidth, TurnoutConsts.lineColor) + .moveTo(0, 0) + .lineTo(target.x, target.y); + } +} + +export class Turnout extends JlGraphic { + static Type = 'Turnout'; + graphics: { + fork: ForkGraphic; + sections: [TurnoutSection, TurnoutSection, TurnoutSection]; + label: VectorText; + }; + + constructor() { + super(Turnout.Type); + this.name = 'turnout'; + this.graphics = { + fork: new ForkGraphic(this), + sections: [ + new TurnoutSection(this, TurnoutPort.A), + new TurnoutSection(this, TurnoutPort.B), + new TurnoutSection(this, TurnoutPort.C), + ], + label: new VectorText(), + }; + this.addChild(this.graphics.fork); + // this.addChild(...this.graphics.sections); + this.addChild(this.graphics.sections[0]); + this.addChild(this.graphics.sections[1]); + this.addChild(this.graphics.sections[2]); + this.graphics.label.anchor.set(0.5); + this.graphics.label.style.fill = '#0f0'; + this.graphics.label.setVectorFontSize(TurnoutConsts.labelFontSize); + this.graphics.label.position.set(20, 20); + this.graphics.label.transformSave = true; + this.graphics.label.name = 'label'; + this.addChild(this.graphics.label); + } + + get datas(): ITurnoutData { + return this.getDatas(); + } + + get states(): ITurnoutState { + return this.getStates(); + } + + getPortPoints() { + return [this.datas.pointA, this.datas.pointB, this.datas.pointC]; + } + + doRepaint(): void { + const { pointB } = this.datas; + this.graphics.fork.paint(pointB[0]); + + this.graphics.sections.forEach((sectionGraphic) => sectionGraphic.paint()); + + this.graphics.label.text = this.datas.code; + } + + buildRelation(): void { + this.relationManage.deleteRelationOfGraphic(this); + + /** 道岔和区段 */ + this.queryStore.queryByType
(Section.Type).forEach((section) => { + this.getPortPoints().forEach((port, i) => { + if ( + distance2( + section.localToCanvasPoint(section.getStartPoint()), + this.localToCanvasPoint(port[port.length - 1]) + ) <= epsilon + ) { + this.relationManage.addRelation( + new GraphicRelationParam( + this, + [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i] + ), + new GraphicRelationParam(section, SectionPort.A) + ); + } + if ( + distance2( + section.localToCanvasPoint(section.getEndPoint()), + this.localToCanvasPoint(port[port.length - 1]) + ) <= epsilon + ) { + this.relationManage.addRelation( + new GraphicRelationParam( + this, + [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i] + ), + new GraphicRelationParam(section, SectionPort.B) + ); + } + }); + }); + + /** 道岔和道岔 */ + this.getPortPoints().forEach((thisPort, i) => { + let params: GraphicRelationParam[] = [], + deflection = 180; + this.queryStore.queryByType(Turnout.Type).forEach((turnout) => { + if (turnout.id === this.id) return; + turnout.getPortPoints().forEach((otherPort, j) => { + if ( + distance2( + this.localToCanvasPoint(thisPort[thisPort.length - 1]), + turnout.localToCanvasPoint(otherPort[otherPort.length - 1]) + ) <= epsilon + ) { + const angle = angleOfIncludedAngle( + this.localToCanvasPoint(thisPort[thisPort.length - 1]) /* 交点 */, + thisPort[thisPort.length - 2] + ? this.localToCanvasPoint(thisPort[thisPort.length - 2]) + : this.position, + otherPort[otherPort.length - 2] + ? turnout.localToCanvasPoint(otherPort[otherPort.length - 2]) + : turnout.position + ); + if (180 - Math.abs(angle) <= deflection) { + deflection = 180 - Math.abs(angle); + params = [ + new GraphicRelationParam( + this, + [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][i] + ), + new GraphicRelationParam( + turnout, + [TurnoutPort.A, TurnoutPort.B, TurnoutPort.C][j] + ), + ]; + } + } + }); + }); + if (params.length === 2) { + this.relationManage.addRelation(params[0], params[1]); + } + }); + } + + saveRelations() { + const paRelation = this.relationManage + .getRelationsOfGraphic(this) + .find( + (relation) => relation.getRelationParam(this).param === TurnoutPort.A + ); + const paDevice = paRelation?.getOtherGraphic
(this); + if (paDevice) { + this.datas.paRef = createRelatedRefProto( + paDevice.type, + paDevice.id, + paRelation?.getOtherRelationParam(this).param + ); + } else { + this.datas.paRef = undefined; + } + const pbRelation = this.relationManage + .getRelationsOfGraphic(this) + .find( + (relation) => relation.getRelationParam(this).param === TurnoutPort.B + ); + const pbDevice = pbRelation?.getOtherGraphic
(this); + if (pbDevice) { + this.datas.pbRef = createRelatedRefProto( + pbDevice.type, + pbDevice.id, + pbRelation?.getOtherRelationParam(this).param + ); + } else { + this.datas.pbRef = undefined; + } + const pcRelation = this.relationManage + .getRelationsOfGraphic(this) + .find( + (relation) => relation.getRelationParam(this).param === TurnoutPort.C + ); + const pcDevice = pcRelation?.getOtherGraphic
(this); + if (pcDevice) { + this.datas.pcRef = createRelatedRefProto( + pcDevice.type, + pcDevice.id, + pcRelation?.getOtherRelationParam(this).param + ); + } else { + this.datas.pcRef = undefined; + } + } + + loadRelations() { + if (this.datas.paRef?.id) { + this.relationManage.addRelation( + new GraphicRelationParam(this, TurnoutPort.A), + new GraphicRelationParam( + this.queryStore.queryById(this.datas.paRef.id), + protoPort2Data(this.datas.paRef.devicePort) + ) + ); + } + if (this.datas.pbRef?.id) { + this.relationManage.addRelation( + new GraphicRelationParam(this, TurnoutPort.B), + new GraphicRelationParam( + this.queryStore.queryById(this.datas.pbRef.id), + protoPort2Data(this.datas.pbRef.devicePort) + ) + ); + } + if (this.datas.pcRef?.id) { + this.relationManage.addRelation( + new GraphicRelationParam(this, TurnoutPort.C), + new GraphicRelationParam( + this.queryStore.queryById(this.datas.pcRef.id), + protoPort2Data(this.datas.pcRef.devicePort) + ) + ); + } + } +} + +export class TurnoutTemplate extends JlGraphicTemplate { + constructor(dataTemplate: ITurnoutData, stateTemplate?: ITurnoutState) { + super(Turnout.Type, { + dataTemplate, + stateTemplate, + }); + } + + new() { + const g = new Turnout(); + g.loadData(this.datas); + // g.loadState(this.states); + return g; + } +} diff --git a/src/graphics/turnout/TurnoutDrawAssistant.ts b/src/graphics/turnout/TurnoutDrawAssistant.ts new file mode 100644 index 0000000..9c22ebb --- /dev/null +++ b/src/graphics/turnout/TurnoutDrawAssistant.ts @@ -0,0 +1,445 @@ +import { + AbsorbablePosition, + DraggablePoint, + GraphicApp, + GraphicDrawAssistant, + GraphicInteractionPlugin, + GraphicTransformEvent, + JlDrawApp, + JlGraphic, + VectorText, + linePoint, + polylinePoint, +} from 'src/jl-graphic'; +import { + ITurnoutData, + Turnout, + TurnoutConsts, + TurnoutPort, + TurnoutSection, + TurnoutTemplate, + getForkPoint, +} from './Turnout'; +import { + DisplayObject, + FederatedMouseEvent, + IHitArea, + IPointData, + Point, +} from 'pixi.js'; +import { + GraphicEditPlugin, + getWaypointRangeIndex, +} from 'src/jl-graphic/plugins/GraphicEditPlugin'; +import { Section } from '../section/Section'; +import AbsorbablePoint, { + AbsorbableLine, +} from 'src/jl-graphic/graphic/AbsorbablePosition'; +import { ContextMenu } from 'src/jl-graphic/ui/ContextMenu'; +import { MenuItemOptions } from 'src/jl-graphic/ui/Menu'; + +export class TurnoutDraw extends GraphicDrawAssistant< + TurnoutTemplate, + ITurnoutData +> { + turnout: Turnout; + constructor(app: JlDrawApp, template: TurnoutTemplate) { + super(app, template, 'sym_o_ramp_left', '道岔Turnout'); + + this.turnout = this.graphicTemplate.new(); + this.container.addChild(this.turnout); + + TurnoutPointsInteractionPlugin.init(app); + } + + onLeftUp(e: FederatedMouseEvent): void { + this.turnout.position.copyFrom(this.toCanvasCoordinates(e.global)); + this.createAndStore(true); + } + + prepareData(data: ITurnoutData): boolean { + data.transform = this.turnout.saveTransform(); + data.code = 'A000000'; + return true; + } + + redraw(cp: Point): void { + this.turnout.position.copyFrom(cp); + } +} + +export class TurnoutHitArea implements IHitArea { + turnout: Turnout; + constructor(turnout: Turnout) { + this.turnout = turnout; + } + contains(x: number, y: number): boolean { + const { pointA, pointB, pointC } = this.turnout.datas; + return ( + polylinePoint( + [...pointA, { x: 0, y: 0 }], + { x, y }, + TurnoutConsts.lineWidth + ) || + polylinePoint( + [...pointB, { x: 0, y: 0 }], + { x, y }, + TurnoutConsts.lineWidth + ) || + polylinePoint( + [...pointC, { x: 0, y: 0 }], + { x, y }, + TurnoutConsts.lineWidth + ) + ); + } +} + +class ForkHitArea implements IHitArea { + turnout: Turnout; + constructor(turnout: Turnout) { + this.turnout = turnout; + } + contains(x: number, y: number): boolean { + const intersectPointB = getForkPoint( + TurnoutConsts.forkLenth, + this.turnout.datas.pointB[0] + ); + const intersectPointC = getForkPoint( + TurnoutConsts.forkLenth, + this.turnout.datas.pointC[0] + ); + + return ( + linePoint( + intersectPointB, + { x: 0, y: 0 }, + { x, y }, + TurnoutConsts.lineWidth + ) || + linePoint( + intersectPointC, + { x: 0, y: 0 }, + { x, y }, + TurnoutConsts.lineWidth + ) + ); + } +} + +class TurnoutSectionHitArea implements IHitArea { + section: TurnoutSection; + constructor(section: TurnoutSection) { + this.section = section; + } + contains(x: number, y: number): boolean { + let points: IPointData[]; + let start: IPointData; + switch (this.section.port) { + case TurnoutPort.A: + points = this.section.turnout.datas.pointA; + start = { x: 0, y: 0 }; + break; + case TurnoutPort.B: + points = this.section.turnout.datas.pointB; + start = getForkPoint(TurnoutConsts.forkLenth, points[0]); + break; + case TurnoutPort.C: + points = this.section.turnout.datas.pointC; + start = getForkPoint(TurnoutConsts.forkLenth, points[0]); + break; + } + return polylinePoint([start, ...points], { x, y }, TurnoutConsts.lineWidth); + } +} + +function buildAbsorbablePositions(turnout: Turnout): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + + const sections = turnout.queryStore.queryByType
(Section.Type); + sections.forEach((section) => { + const ps = new AbsorbablePoint( + section.localToCanvasPoint(section.getStartPoint()) + ); + const pe = new AbsorbablePoint( + section.localToCanvasPoint(section.getEndPoint()) + ); + aps.push(ps, pe); //区段端点 + }); + + const turnouts = turnout.queryStore.queryByType(Turnout.Type); + turnouts.forEach((otherTurnout) => { + const { + pointA: [A], + pointB: [B], + pointC: [C], + } = otherTurnout.datas; + + [A, B, C].forEach((p) => { + aps.push( + new AbsorbablePoint(otherTurnout.localToCanvasPoint(p)), //道岔端点 + new AbsorbableLine( + otherTurnout.localToCanvasPoint({ x: -5 * p.x, y: -5 * p.y }), + otherTurnout.localToCanvasPoint({ x: 5 * p.x, y: 5 * p.y }) + ) //道岔延长线 + ); + }); + aps.push( + new AbsorbableLine( + otherTurnout.localToCanvasPoint({ x: 0, y: -500 }), + otherTurnout.localToCanvasPoint({ x: 0, y: 500 }) + ), //岔心垂直线 + new AbsorbableLine( + otherTurnout.localToCanvasPoint({ x: -500, y: 0 }), + otherTurnout.localToCanvasPoint({ x: 500, y: 0 }) + ), //岔心水平线 + new AbsorbableLine( + otherTurnout.localToCanvasPoint({ x: -500, y: 500 }), + otherTurnout.localToCanvasPoint({ x: 500, y: -500 }) + ), //岔心/ + new AbsorbableLine( + otherTurnout.localToCanvasPoint({ x: -500, y: -500 }), + otherTurnout.localToCanvasPoint({ x: 500, y: 500 }) + ) //岔心\ + ); + }); + + return aps; +} + +function onEditPointCreate(turnout: Turnout, dp: DraggablePoint) { + dp.on('transformstart', (e: GraphicTransformEvent) => { + if (e.isShift()) { + turnout.getGraphicApp().setOptions({ + absorbablePositions: buildAbsorbablePositions(turnout), + }); + } + }); +} + +const addPointConfig: MenuItemOptions = { name: '添加路径点' }; +const clearPointConfig: MenuItemOptions = { name: '清除路径点' }; + +const turnoutSectionEditMenu: ContextMenu = ContextMenu.init({ + name: '道岔区段路径编辑', + groups: [ + { + items: [addPointConfig, clearPointConfig], + }, + ], +}); + +export class TurnoutPointsInteractionPlugin extends GraphicInteractionPlugin { + static Name = 'TurnoutPointsDrag'; + static init(app: JlDrawApp) { + return new TurnoutPointsInteractionPlugin(app); + } + + constructor(app: GraphicApp) { + super(TurnoutPointsInteractionPlugin.Name, app); + app.registerMenu(turnoutSectionEditMenu); + } + + onSectionContextMenu(e: FederatedMouseEvent, section: TurnoutSection) { + let points: IPointData[]; + if (section.port === TurnoutPort.A) points = section.turnout.datas.pointA; + if (section.port === TurnoutPort.B) points = section.turnout.datas.pointB; + if (section.port === TurnoutPort.C) points = section.turnout.datas.pointC; + const p = section.turnout.screenToLocalPoint(e.global); + addPointConfig.handler = () => { + if (section.port === TurnoutPort.A) { + const { start } = getWaypointRangeIndex( + [{ x: 0, y: 0 }, ...section.turnout.datas.pointA], + false, + p, + TurnoutConsts.lineWidth + ); + const points = section.turnout.datas.pointA; + const ps = points.slice(0, start); + ps.push(new Point(p.x, p.y)); + ps.push(...points.slice(start)); + section.turnout.datas.pointA = ps; + } + if (section.port === TurnoutPort.B) { + const { start } = getWaypointRangeIndex( + [{ x: 0, y: 0 }, ...section.turnout.datas.pointB], + false, + p, + TurnoutConsts.lineWidth + ); + const points = section.turnout.datas.pointB; + const ps = points.slice(0, start); + ps.push(new Point(p.x, p.y)); + ps.push(...points.slice(start)); + section.turnout.datas.pointB = ps; + } + if (section.port === TurnoutPort.C) { + const { start } = getWaypointRangeIndex( + [{ x: 0, y: 0 }, ...section.turnout.datas.pointC], + false, + p, + TurnoutConsts.lineWidth + ); + const points = section.turnout.datas.pointC; + const ps = points.slice(0, start); + ps.push(new Point(p.x, p.y)); + ps.push(...points.slice(start)); + section.turnout.datas.pointC = ps; + } + this.onSelected(section.turnout); + }; + clearPointConfig.handler = () => { + if (points.length <= 1) return; + points.splice(0, points.length - 1); + section.turnout.repaint(); + }; + turnoutSectionEditMenu.open(e.global); + } + + bind(g: Turnout): void { + g.graphics.fork.eventMode = 'static'; + g.graphics.fork.cursor = 'pointer'; + g.graphics.fork.hitArea = new ForkHitArea(g); + g.graphics.sections.forEach((sectionGraphic) => { + sectionGraphic.eventMode = 'static'; + sectionGraphic.cursor = 'pointer'; + sectionGraphic.hitArea = new TurnoutSectionHitArea(sectionGraphic); + sectionGraphic.on( + 'rightclick', + (e) => this.onSectionContextMenu(e, sectionGraphic), + sectionGraphic + ); + }); + g.graphics.label.eventMode = 'static'; + g.graphics.label.cursor = 'pointer'; + g.graphics.label.draggable = true; + g.graphics.label.selectable = true; + g.graphics.label.name = 'label'; + g.graphics.label.transformSave = true; + g.transformSave = true; + g.on('selected', this.onSelected, this); + g.on('unselected', this.onUnSelected, this); + } + + unbind(g: Turnout): void { + g.off('selected', this.onSelected, this); + g.off('unselected', this.onUnSelected, this); + g.graphics.sections.forEach((sectionGraphic) => { + sectionGraphic.off('rightclick'); + }); + } + + onSelected(g: DisplayObject) { + const turnout = g as Turnout; + let tep = turnout.getAssistantAppend( + TurnoutEditPlugin.Name + ); + if (!tep) { + tep = new TurnoutEditPlugin(turnout, { onEditPointCreate }); + turnout.addAssistantAppend(tep); + } + tep.reset(); + tep.showAll(); + } + + onUnSelected(g: DisplayObject) { + const turnout = g as Turnout; + const tep = turnout.getAssistantAppend( + TurnoutEditPlugin.Name + ); + if (tep) { + tep.hideAll(); + } + } + + filter(...grahpics: JlGraphic[]): Turnout[] | undefined { + return grahpics.filter((g) => g.type == Turnout.Type) as Turnout[]; + } +} + +type onTurnoutEditPointCreate = (turnout: Turnout, dp: DraggablePoint) => void; + +export interface ITurnoutEditOptions { + onEditPointCreate?: onTurnoutEditPointCreate; +} + +export class TurnoutEditPlugin extends GraphicEditPlugin { + static Name = 'TurnoutEdit'; + options: ITurnoutEditOptions; + editPoints: DraggablePoint[][] = [[], [], []]; + labels: VectorText[] = []; + + constructor(graphic: Turnout, options?: ITurnoutEditOptions) { + super(graphic); + this.name = TurnoutEditPlugin.Name; + this.options = Object.assign({}, options); + this.initEditPoints(); + } + reset(): void { + this.destoryEditPoints(); + this.removeChildren(); + this.initEditPoints(); + } + + initEditPoints() { + const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA); + const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB); + const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC); + const cpMap: Map = new Map([ + [cpA, this.graphic.datas.pointA], + [cpB, this.graphic.datas.pointB], + [cpC, this.graphic.datas.pointC], + ]); + Array.from(cpMap.entries()).forEach(([cpDatas, dataPoints], i) => { + cpDatas.forEach((cpData, j) => { + const dp = new DraggablePoint(cpData); + dp.on('transforming', (e: GraphicTransformEvent) => { + const localPoint = this.graphic.canvasToLocalPoint(dp.position); + dataPoints[j].x = localPoint.x; + dataPoints[j].y = localPoint.y; + + this.graphic.repaint(); + }); + if (this.options.onEditPointCreate) { + this.options.onEditPointCreate(this.graphic, dp); + } + this.editPoints[i].push(dp); + }); + }); + this.editPoints.forEach((cps) => { + this.addChild(...cps); + }); + this.labels = ['A', 'B', 'C'].map((str) => { + const vc = new VectorText(str); + vc.setVectorFontSize(14); + vc.anchor.set(0.5); + return vc; + }); + this.addChild(...this.labels); + } + + destoryEditPoints() { + this.editPoints.forEach((dps) => { + dps.forEach((dp) => { + dp.off('transforming'); + dp.destroy(); + this.removeChild(dp); + }); + }); + this.editPoints = [[], [], []]; + } + + updateEditedPointsPosition() { + const cpA = this.graphic.localToCanvasPoints(...this.graphic.datas.pointA); + const cpB = this.graphic.localToCanvasPoints(...this.graphic.datas.pointB); + const cpC = this.graphic.localToCanvasPoints(...this.graphic.datas.pointC); + [cpA, cpB, cpC].forEach((cps, i) => { + cps.forEach((cp, j) => { + this.editPoints[i][j].position.copyFrom(cp); + if (j === cps.length - 1) { + this.labels[i].position.copyFrom({ x: cp.x, y: cp.y + 12 }); + } + }); + }); + } +} diff --git a/src/jl-graphic/app/JlDrawApp.ts b/src/jl-graphic/app/JlDrawApp.ts new file mode 100644 index 0000000..8a1bfa2 --- /dev/null +++ b/src/jl-graphic/app/JlDrawApp.ts @@ -0,0 +1,679 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-empty-function */ +import { + BitmapFont, + BitmapText, + Container, + DisplayObject, + FederatedMouseEvent, + IPointData, + Point, +} from 'pixi.js'; +import { GraphicIdGenerator } from '../core/IdGenerator'; +import { GraphicData, GraphicTemplate, JlGraphic } from '../core/JlGraphic'; +import { JlOperation } from '../operation/JlOperation'; +import { + AppDragEvent, + AppInteractionPlugin, + CombinationKey, + GraphicTransformEvent, + InteractionPlugin, + KeyListener, + ShiftData, +} from '../plugins'; +import { CommonMouseTool } from '../plugins/CommonMousePlugin'; +import { MenuItemOptions } from '../ui/Menu'; +import { DOWN, LEFT, RIGHT, UP, recursiveChildren } from '../utils'; +import { + GraphicApp, + GraphicAppOptions, + ICanvasProperties, + JlCanvas, +} from './JlGraphicApp'; + +/** + * 图形绘制助手 + */ +export abstract class GraphicDrawAssistant< + GT extends GraphicTemplate, + GD extends GraphicData +> extends AppInteractionPlugin { + readonly __GraphicDrawAssistant = true; + app: JlDrawApp; + type: string; // 图形对象类型 + description: string; // 描述 + icon: string; // 界面显示的图标 + container: Container = new Container(); + graphicTemplate: GT; + + escListener: KeyListener = new KeyListener({ + value: 'Escape', + onRelease: () => { + this.onEsc(); + }, + }); + + onEsc() { + this.createAndStore(true); + } + + constructor( + graphicApp: JlDrawApp, + graphicTemplate: GT, + icon: string, + description: string + ) { + super(graphicTemplate.type, graphicApp); + this.app = graphicApp; + this.type = graphicTemplate.type; + this.graphicTemplate = graphicTemplate; + this.icon = icon; + this.description = description; + this.app.registerGraphicTemplates(this.graphicTemplate); + } + + public get canvas(): JlCanvas { + return this.app.canvas; + } + + bind(): void { + this.app._drawing = true; + const canvas = this.canvas; + canvas.addChild(this.container); + canvas.on('mousedown', this.onLeftDown, this); + canvas.on('mousemove', this.onMouseMove, this); + canvas.on('mouseup', this.onLeftUp, this); + canvas.on('rightdown', this.onRightDown, this); + canvas.on('rightup', this.onRightUp, this); + canvas.on('_rightclick', this.onRightClick, this); + + this.app.viewport.wheel({ + percent: 0.01, + }); + this.app.addKeyboardListener(this.escListener); + + this.app.viewport.drag({ + mouseButtons: 'right', + }); + } + unbind(): void { + this.clearCache(); + const canvas = this.canvas; + if (this.container?.parent) { + canvas.removeChild(this.container); + } + canvas.off('mousedown', this.onLeftDown, this); + canvas.off('mousemove', this.onMouseMove, this); + canvas.off('mouseup', this.onLeftUp, this); + canvas.off('rightdown', this.onRightDown, this); + canvas.off('rightup', this.onRightUp, this); + + this.app.viewport.plugins.remove('wheel'); + + this.app.removeKeyboardListener(this.escListener); + + this.app.viewport.plugins.remove('drag'); + this.app._drawing = false; + } + + onLeftDown(e: FederatedMouseEvent) {} + + onMouseMove(e: FederatedMouseEvent) { + this.redraw(this.toCanvasCoordinates(e.global)); + } + + onLeftUp(e: FederatedMouseEvent) {} + onRightDown(e: FederatedMouseEvent) {} + onRightUp(e: FederatedMouseEvent) {} + onRightClick(e: FederatedMouseEvent) { + this.finish(); + } + /** + * 获取下一个id + */ + nextId(): string { + return GraphicIdGenerator.next(); + } + + clearCache(): void {} + + /** + * 重绘 + * @param cp 鼠标所在画布坐标 + */ + abstract redraw(cp: Point): void; + + abstract prepareData(data: GD): boolean; + + toCanvasCoordinates(p: Point): Point { + return this.app.toCanvasCoordinates(p); + } + /** + * 保存创建的图形对象 + */ + storeGraphic(...graphics: JlGraphic[]): void { + this.app.addGraphics(...graphics); + // 创建图形对象操作记录 + this.app.opRecord.record(new GraphicCreateOperation(this.app, graphics)); + } + /** + * 创建并添加到图形App + */ + createAndStore(finish: boolean): JlGraphic | null { + const data = this.graphicTemplate.datas as GD; + data.id = this.nextId(); + data.graphicType = this.graphicTemplate.type; + if (!this.prepareData(data)) { + if (finish) { + this.finish(); + } + return null; + } + const template = this.graphicTemplate; + const g = template.new(); + g.loadData(data); + this.storeGraphic(g); + if (finish) { + this.finish(g); + } + return g; + } + + /** + * 绘制完成 + */ + finish(...graphics: JlGraphic[]): void { + this.clearCache(); + this.app.interactionPlugin(CommonMouseTool.Name).resume(); + this.app.updateSelected(...graphics); + } +} + +export type DrawAssistant = GraphicDrawAssistant; + +export interface IDrawAppOptions { + /** + * 绘制辅助交互插件 + */ + drawAssistants: DrawAssistant[]; +} + +export type DrawAppOptions = GraphicAppOptions & IDrawAppOptions; + +/** + * 绘制应用 + */ +export class JlDrawApp extends GraphicApp { + font: BitmapFont = BitmapFont.from( + 'coordinates', + { + fontFamily: 'Roboto', + fontSize: 16, + fill: '#ff2700', + }, + { chars: ['画布坐标:() 屏幕坐标:() 缩放:.,', ['0', '9']] } + ); + coordinates: BitmapText = new BitmapText('画布坐标: (0, 0) 屏幕坐标:(0, 0)', { + fontName: 'coordinates', + }); + scaleText: BitmapText = new BitmapText('缩放: 1', { + fontName: 'coordinates', + }); + + drawAssistants: DrawAssistant[] = []; + _drawing = false; + + constructor(dom: HTMLElement) { + super(dom); + + this.appendDrawStatesDisplay(); + + // 拖拽操作记录 + this.appOperationRecord(); + // 绑定通用键盘操作 + this.bindKeyboardOperation(); + } + + setOptions(options: DrawAppOptions): void { + super.setOptions(options); + // this.registerInteractionPlugin(...options.drawAssistants); + } + + registerInteractionPlugin(...plugins: InteractionPlugin[]): void { + plugins.forEach((plugin) => { + if (plugin instanceof GraphicDrawAssistant) { + this.drawAssistants.push(plugin); + } + super.registerInteractionPlugin(plugin); + }); + } + + getDrawAssistant(graphicType: string): DA { + const sda = this.drawAssistants + .filter((da) => da.type === graphicType) + .pop(); + if (!sda) { + throw new Error(`未找到图形绘制助手: ${graphicType}`); + } + return sda as DA; + } + + private appOperationRecord() { + let dragStartDatas: GraphicData[] = []; + this.on('drag_op_start', (e: AppDragEvent) => { + // 图形拖拽,记录初始数据 + if (!e.target.isCanvas()) { + dragStartDatas = this.selectedGraphics.map((g) => g.saveData()); + } + }); + // 图形拖拽操作监听 + this.on('drag_op_end', () => { + // 图形拖拽,记录操作 + if (dragStartDatas.length > 0) { + const newData = this.selectedGraphics.map((g) => g.saveData()); + this.opRecord.record( + new GraphicDataUpdateOperation( + this, + this.selectedGraphics, + dragStartDatas, + newData + ) + ); + dragStartDatas = []; + } + }); + // 菜单操作 + let preMenuHandleDatas: GraphicData[] = []; + this.on('pre-menu-handle', (menu: MenuItemOptions) => { + if (menu.name === '撤销' || menu.name === '重做') { + return; + } + preMenuHandleDatas = this.selectedGraphics.map((g) => g.saveData()); + }); + this.on('post-menu-handle', () => { + if (preMenuHandleDatas.length > 0) { + const newData = this.selectedGraphics.map((g) => g.saveData()); + this.opRecord.record( + new GraphicDataUpdateOperation( + this, + this.selectedGraphics, + preMenuHandleDatas, + newData + ) + ); + preMenuHandleDatas = []; + } + }); + } + + /** + * 绘制状态信息显示 + */ + private appendDrawStatesDisplay(): void { + this.app.stage.addChild(this.coordinates); + this.app.stage.addChild(this.scaleText); + const bound = this.coordinates.getLocalBounds(); + this.scaleText.position.set(bound.width + 10, 0); + this.canvas.on('mousemove', (e) => { + if (e.target) { + const { x, y } = this.toCanvasCoordinates(e.global); + const cpTxt = `(${x}, ${y})`; + const tp = e.global; + const tpTxt = `(${tp.x}, ${tp.y})`; + this.coordinates.text = `画布坐标:${cpTxt} 屏幕坐标:${tpTxt}`; + const bound = this.coordinates.getLocalBounds(); + this.scaleText.position.set(bound.width + 10, 0); + } + }); + this.viewport.on('zoomed-end', () => { + this.scaleText.text = `缩放: ${this.viewport.scaled}`; + }); + } + + bindKeyboardOperation(): void { + this.addKeyboardListener( + // Ctrl + A + new KeyListener({ + value: 'KeyA', + combinations: [CombinationKey.Ctrl], + onPress: (e: KeyboardEvent, app: GraphicApp) => { + if (e.ctrlKey) { + (app as JlDrawApp).selectAllGraphics(); + } + }, + }) + ); + + // 复制功能 + this.addKeyboardListener( + new KeyListener({ + value: 'KeyD', + combinations: [CombinationKey.Shift], + onPress: (e: KeyboardEvent, app: GraphicApp) => { + app.graphicCopyPlugin.init(); + }, + }) + ); + this.addKeyboardListener( + new KeyListener({ + // Ctrl + Z + value: 'KeyZ', + global: true, + combinations: [CombinationKey.Ctrl], + onPress: (e: KeyboardEvent, app: GraphicApp) => { + app.opRecord.undo(); + }, + }) + ); + this.addKeyboardListener( + new KeyListener({ + // Ctrl + Shift + Z + value: 'KeyZ', + global: true, + combinations: [CombinationKey.Ctrl, CombinationKey.Shift], + onPress: (e: KeyboardEvent, app: GraphicApp) => { + app.opRecord.redo(); + }, + }) + ); + + this.addKeyboardListener( + new KeyListener({ + value: 'Delete', + onPress: (e: KeyboardEvent, app: GraphicApp) => { + (app as JlDrawApp).deleteSelectedGraphics(); + }, + }) + ); + this.addKeyboardListener( + new KeyListener({ + value: 'ArrowUp', + pressTriggerAsOriginalEvent: true, + onPress: (e: KeyboardEvent, app: GraphicApp) => { + updateGraphicPositionOnKeyboardEvent(app, UP); + }, + onRelease: (e: KeyboardEvent, app: GraphicApp) => { + recordGraphicMoveOperation(app); + }, + }) + ); + this.addKeyboardListener( + new KeyListener({ + value: 'ArrowDown', + pressTriggerAsOriginalEvent: true, + onPress: (e: KeyboardEvent, app: GraphicApp) => { + updateGraphicPositionOnKeyboardEvent(app, DOWN); + }, + onRelease: (e: KeyboardEvent, app: GraphicApp) => { + recordGraphicMoveOperation(app); + }, + }) + ); + this.addKeyboardListener( + new KeyListener({ + value: 'ArrowLeft', + pressTriggerAsOriginalEvent: true, + onPress: (e: KeyboardEvent, app: GraphicApp) => { + updateGraphicPositionOnKeyboardEvent(app, LEFT); + }, + onRelease: (e: KeyboardEvent, app: GraphicApp) => { + recordGraphicMoveOperation(app); + }, + }) + ); + this.addKeyboardListener( + new KeyListener({ + value: 'ArrowRight', + pressTriggerAsOriginalEvent: true, + onPress: (e: KeyboardEvent, app: GraphicApp) => { + updateGraphicPositionOnKeyboardEvent(app, RIGHT); + }, + onRelease: (e: KeyboardEvent, app: GraphicApp) => { + recordGraphicMoveOperation(app); + }, + }) + ); + } + + /** + * 全选 + */ + selectAllGraphics() { + this.updateSelected(...this.queryStore.getAllGraphics()); + } + + /** + * 图形对象存储处理,默认添加图形交互 + * @param graphic + */ + beforeGraphicStore(graphic: JlGraphic): void { + graphic.eventMode = 'static'; + graphic.selectable = true; + graphic.draggable = true; + } + + /** + * 删除选中图形对象 + */ + deleteSelectedGraphics() { + const deletes = this.selectedGraphics.slice( + 0, + this.selectedGraphics.length + ); + this.deleteGraphics(...this.selectedGraphics); + // 删除图形对象操作记录 + this.opRecord.record(new GraphicDeleteOperation(this, deletes)); + } + + updateCanvasAndRecord(data: ICanvasProperties) { + const old = this.canvas.properties.clone(); + this.canvas.update(data); + const newVal = this.canvas.properties.clone(); + this.opRecord.record( + new UpdateCanvasOperation(this, this.canvas, old, newVal) + ); + } + + updateGraphicAndRecord(g: JlGraphic, data: GraphicData) { + const old = g.saveData(); + g.updateData(data); + const newVal = g.saveData(); + this.opRecord.record( + new GraphicDataUpdateOperation(this, [g], [old], [newVal]) + ); + } +} + +let dragStartDatas: GraphicData[] = []; + +function handleArrowKeyMoveGraphics( + app: GraphicApp, + handler: (obj: DisplayObject) => void +) { + if ( + app.selectedGraphics.length === 1 && + app.selectedGraphics[0].hasSelectedChilds() + ) { + recursiveChildren(app.selectedGraphics[0], (child) => { + if (child.selected && child.draggable) { + handler(child); + } + }); + } else { + app.selectedGraphics.forEach((g) => { + handler(g); + }); + } +} + +function updateGraphicPositionOnKeyboardEvent(app: GraphicApp, dp: IPointData) { + let dragStart = false; + if (dragStartDatas.length === 0) { + dragStartDatas = app.selectedGraphics.map((g) => g.saveData()); + dragStart = true; + } + handleArrowKeyMoveGraphics(app, (g) => { + if (dragStart) { + g.shiftStartPoint = g.position.clone(); + g.emit( + 'transformstart', + GraphicTransformEvent.shift(g, ShiftData.new(g.shiftStartPoint)) + ); + } else { + g.shiftLastPoint = g.position.clone(); + } + g.position.x += dp.x; + g.position.y += dp.y; + if (!dragStart) { + if (g.shiftStartPoint && g.shiftLastPoint) { + g.emit( + 'transforming', + GraphicTransformEvent.shift( + g, + ShiftData.new( + g.shiftStartPoint, + g.position.clone(), + g.shiftLastPoint + ) + ) + ); + } + } + }); +} +function recordGraphicMoveOperation(app: GraphicApp) { + if ( + dragStartDatas.length > 0 && + dragStartDatas.length === app.selectedGraphics.length + ) { + const newData = app.selectedGraphics.map((g) => g.saveData()); + app.opRecord.record( + new GraphicDataUpdateOperation( + app, + app.selectedGraphics, + dragStartDatas, + newData + ) + ); + + handleArrowKeyMoveGraphics(app, (g) => { + if (g.shiftStartPoint) { + g.emit( + 'transformend', + GraphicTransformEvent.shift( + g, + ShiftData.new(g.shiftStartPoint, g.position.clone()) + ) + ); + } + }); + } + dragStartDatas = []; +} + +/** + * 更新画布操作 + */ +export class UpdateCanvasOperation extends JlOperation { + obj: JlCanvas; + old: ICanvasProperties; + data: ICanvasProperties; + description = ''; + + constructor( + app: GraphicApp, + obj: JlCanvas, + old: ICanvasProperties, + data: ICanvasProperties + ) { + super(app, 'update-canvas'); + this.app = app; + this.obj = obj; + this.old = old; + this.data = data; + } + + undo(): JlGraphic[] { + this.obj.update(this.old); + return []; + } + redo(): JlGraphic[] { + this.obj.update(this.data); + return []; + } +} +/** + * 创建图形操作 + */ +export class GraphicCreateOperation extends JlOperation { + obj: JlGraphic[]; + description = ''; + + constructor(app: GraphicApp, obj: JlGraphic[]) { + super(app, 'graphic-create'); + this.app = app; + this.obj = obj; + } + + undo(): JlGraphic[] | void { + this.app.deleteGraphics(...this.obj); + } + redo(): JlGraphic[] { + this.app.addGraphics(...this.obj); + return this.obj; + } +} +/** + * 删除图形操作 + */ +export class GraphicDeleteOperation extends JlOperation { + obj: JlGraphic[]; + + constructor(app: GraphicApp, obj: JlGraphic[]) { + super(app, 'graphic-delete'); + this.app = app; + this.obj = obj; + } + + undo(): JlGraphic[] { + this.app.addGraphics(...this.obj); + return this.obj; + } + redo(): void { + this.app.deleteGraphics(...this.obj); + } +} + +export class GraphicDataUpdateOperation extends JlOperation { + obj: JlGraphic[]; + oldData: GraphicData[]; + newData: GraphicData[]; + constructor( + app: GraphicApp, + obj: JlGraphic[], + oldData: GraphicData[], + newData: GraphicData[] + ) { + super(app, 'graphic-drag'); + this.obj = [...obj]; + this.oldData = oldData; + this.newData = newData; + } + + undo(): void | JlGraphic[] { + for (let i = 0; i < this.obj.length; i++) { + const g = this.obj[i]; + // g.exitChildEdit(); + g.updateData(this.oldData[i]); + } + return this.obj; + } + redo(): void | JlGraphic[] { + for (let i = 0; i < this.obj.length; i++) { + const g = this.obj[i]; + // g.exitChildEdit(); + g.updateData(this.newData[i]); + } + return this.obj; + } +} diff --git a/src/jl-graphic/app/JlGraphicApp.ts b/src/jl-graphic/app/JlGraphicApp.ts new file mode 100644 index 0000000..c2b0af8 --- /dev/null +++ b/src/jl-graphic/app/JlGraphicApp.ts @@ -0,0 +1,905 @@ +import EventEmitter from 'eventemitter3'; +import { Viewport } from 'pixi-viewport'; +import { + Application, + Color, + Container, + DisplayObject, + Graphics, + Point, + Rectangle, +} from 'pixi.js'; +import { GraphicQueryStore, GraphicStore } from '../core/GraphicStore'; +import { GraphicIdGenerator } from '../core/IdGenerator'; +import { + GraphicData, + GraphicState, + GraphicTemplate, + GraphicTransform, + JlGraphic, +} from '../core/JlGraphic'; +import { AbsorbablePosition } from '../graphic'; +import { + AppWsMsgBroker, + StompCli, + type AppStateSubscription, + type StompCliOption, +} from '../message/WsMsgBroker'; +import { OperationRecord } from '../operation/JlOperation'; +import { + AnimationManager, + CommonMouseTool, + GraphicTransformPlugin, + IMouseToolOptions, +} from '../plugins'; +import { GraphicCopyPlugin } from '../plugins/CopyPlugin'; +import { + AppDragEvent, + DragPlugin, + InteractionPlugin, + InteractionPluginType, + ViewportMovePlugin, +} from '../plugins/InteractionPlugin'; +import { + JlGraphicAppKeyboardPlugin, + KeyListener, +} from '../plugins/KeyboardPlugin'; +import { ContextMenu, ContextMenuPlugin } from '../ui/ContextMenu'; +import { MenuItemOptions } from '../ui/Menu'; +import { getRectangleCenter, recursiveChildren } from '../utils/GraphicUtils'; + +export const AppConsts = { + viewportname: '__viewport', + canvasname: '__jlcanvas', + AssistantAppendsName: '__assistantAppends', +}; + +/** + * 画布属性 + */ +export interface ICanvasProperties { + width: number; + height: number; + backgroundColor: string; + viewportTransform: GraphicTransform; +} + +export class CanvasData implements ICanvasProperties { + width: number; + height: number; + backgroundColor: string; + viewportTransform: GraphicTransform; + constructor( + properties: ICanvasProperties = { + width: 1920, + height: 1080, + backgroundColor: '#ffffff', + viewportTransform: GraphicTransform.default(), + } + ) { + this.width = properties.width; + this.height = properties.height; + this.backgroundColor = properties.backgroundColor; + this.viewportTransform = properties.viewportTransform; + } + + copyFrom(properties: ICanvasProperties): boolean { + let sizeChange = false; + if (properties.width <= 0 || properties.height <= 0) { + console.error('画布宽度/高度不能小于等于0'); + } else { + const width = Math.floor(properties.width); + const height = Math.floor(properties.height); + if (this.width != width) { + this.width = width; + sizeChange = true; + } + if (this.height != height) { + this.height = height; + sizeChange = true; + } + } + this.backgroundColor = properties.backgroundColor; + this.viewportTransform = properties.viewportTransform; + return sizeChange; + } + + clone(): CanvasData { + const cp = new CanvasData(this); + return cp; + } +} + +export class JlCanvas extends Container { + __JlCanvas = true; + type = 'Canvas'; + app: GraphicApp; + _properties: CanvasData; + bg: Graphics = new Graphics(); // 背景 + nonInteractiveContainer: Container; // 无交互对象容器 + assistantAppendContainer: Container; // 辅助附加容器 + + constructor(app: GraphicApp, properties: CanvasData = new CanvasData()) { + super(); + this.app = app; + this._properties = properties; + this.eventMode = 'static'; + this.nonInteractiveContainer = new Container(); + this.nonInteractiveContainer.name = 'non-interactives'; + this.nonInteractiveContainer.eventMode = 'none'; + this.addChild(this.bg); + this.addChild(this.nonInteractiveContainer); + + this.sortableChildren = true; + this.assistantAppendContainer = new Container(); + this.assistantAppendContainer.eventMode = 'static'; + this.assistantAppendContainer.name = AppConsts.AssistantAppendsName; + this.assistantAppendContainer.zIndex = 999; + this.assistantAppendContainer.sortableChildren = true; + this.addChild(this.assistantAppendContainer); + + this.repaint(); + } + + /** + * 图形重绘(数据/状态变化时触发) + */ + repaint(): void { + this.doRepaint(); + } + + public get width(): number { + return this._properties.width; + } + + public get height(): number { + return this._properties.height; + } + + public get backgroundColor(): string { + return this._properties.backgroundColor; + } + + doRepaint() { + this.bg.clear(); + this.bg + .beginFill(new Color(this.backgroundColor)) + .drawRect(0, 0, this._properties.width, this._properties.height) + .endFill(); + } + + public get properties(): CanvasData { + return this._properties; + } + + saveData(): CanvasData { + const vp = this.getViewport(); + this.properties.viewportTransform = vp.saveTransform(); + return this.properties.clone(); + } + + update(properties: ICanvasProperties) { + // 更新画布 + const old = this.properties.clone(); + const sizeChange = this._properties.copyFrom(properties); + this.repaint(); + if (sizeChange) { + this.app.updateViewport(); + } + const vp = this.getViewport(); + vp.loadTransform(properties.viewportTransform); + this.emit('dataupdate', this.properties, old); + } + + addChild(...children: U): U[0] { + const rt = super.addChild(...children); + children.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onAddToCanvas()); + }); + return rt; + } + removeChild(...children: U): U[0] { + children.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onRemoveFromCanvas()); + }); + return super.removeChild(...children); + } + /** + * 添加无交互Child + */ + addNonInteractiveChild(...obj: DisplayObject[]): void { + this.nonInteractiveContainer.addChild(...obj); + obj.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onAddToCanvas()); + }); + } + + removeGraphic(...obj: DisplayObject[]): void { + obj.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onRemoveFromCanvas()); + }); + this.removeChild(...obj); + this.nonInteractiveContainer.removeChild(...obj); + } + + /** + * 移除无交互Child + */ + removeNonInteractiveChild(...obj: DisplayObject[]): void { + obj.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onRemoveFromCanvas()); + }); + this.nonInteractiveContainer.removeChild(...obj); + } + + addAssistantAppends(...appends: DisplayObject[]): void { + this.assistantAppendContainer.addChild(...appends); + appends.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onAddToCanvas()); + }); + } + removeAssistantAppends(...appends: DisplayObject[]): void { + appends.forEach((g) => { + recursiveChildren(g as Container, (child) => child.onAddToCanvas()); + }); + this.assistantAppendContainer.removeChild(...appends); + } + + /** + * 暂停所有可交互对象 + */ + pauseInteractiveChildren() { + this.interactiveChildren = false; + } + + /** + * 恢复所有可交互对象 + */ + resumeInteractiveChildren() { + this.interactiveChildren = true; + } +} + +/** + * 选中改变事件 + */ +export class SelectedChangeEvent { + graphic: JlGraphic; + select: boolean; + + constructor(graphic: JlGraphic, select: boolean) { + this.graphic = graphic; + this.select = select; + } +} + +export interface GraphicAppEvents extends GlobalMixins.GraphicAppEvents { + graphicstored: [graphic: JlGraphic]; + graphicdeleted: [graphic: JlGraphic]; + loadfinish: []; + 'interaction-plugin-resume': [plugin: InteractionPlugin]; // 交互插件启用 + 'interaction-plugin-pause': [plugin: InteractionPlugin]; // 交互插件停止 + 'options-update': [options: GraphicAppOptions]; // 配置更新 + graphicselectedchange: [graphic: JlGraphic, selected: boolean]; + graphicchildselectedchange: [child: DisplayObject, selected: boolean]; + 'viewport-scaled': [vp: Viewport]; + drag_op_start: [event: AppDragEvent]; + drag_op_move: [event: AppDragEvent]; + drag_op_end: [event: AppDragEvent]; + 'pre-menu-handle': [menu: MenuItemOptions]; + 'post-menu-handle': [menu: MenuItemOptions]; + 'websocket-state-change': [app: GraphicApp, connected: boolean]; + destroy: [app: GraphicApp]; +} + +/** + * 图形App构造参数 + */ +export interface IGraphicAppConfig { + /** + * 交互类型配置 + */ + interactiveTypeOptions?: IInteractiveGraphicOptions; + /** + * 最大保存的操作记录数,默认100,越大越占用内存资源 + */ + maxOperationRecords?: number; + /** + * 拖拽触发移动门槛 + */ + threshold?: number; + /** + * 通用鼠标工具选项 + */ + mouseToolOptions?: IMouseToolOptions; + /** + * 可吸附位置列表 + */ + absorbablePositions?: AbsorbablePosition[]; + /** + * 超出屏幕显示范围是否剪裁,默认true + */ + cullable?: boolean; +} + +/** + * 图形添加到容器选项 + */ +export interface IInteractiveGraphicOptions { + /** + * 包含添加到可交互容器的图形类型,和Excludes同时只能存在一个 + */ + interactiveGraphicTypeIncludes?: string[]; + /** + * 不包含添加到可交互容器的图形类型,和Includes同时只能存在一个 + */ + interactiveGraphicTypeExcludes?: string[]; +} + +export type GraphicAppOptions = IGraphicAppConfig; + +/** + * 图形app基类 + */ +export class GraphicApp extends EventEmitter { + private graphicStore: GraphicStore; + _options?: GraphicAppOptions; + dom: HTMLElement; + app: Application; // Pixi 渲染器 + viewport: Viewport; // 视口 + canvas: JlCanvas; // 画布 + interactiveTypeOptions: IInteractiveGraphicOptions; // 图形交互配置 + + graphicTemplateMap: Map = new Map< + string, + GraphicTemplate + >(); // 图形对象模板 + + opRecord: OperationRecord; // 操作记录 + + keyboardPlugin: JlGraphicAppKeyboardPlugin; // 键盘操作处理插件 + graphicCopyPlugin: GraphicCopyPlugin; // 图形复制操作插件 + menuPlugin: ContextMenuPlugin; // 菜单插件 + animationManager: AnimationManager; // 动画管理组件 + + interactionPluginMap: Map = new Map< + string, + InteractionPlugin + >(); // 交互插件 + + wsMsgBroker?: AppWsMsgBroker; // websocket消息代理 + + constructor(dom: HTMLElement) { + super(); + document.body.style.overflow = 'hidden'; + // console.log('创建图形App') + this.dom = dom; + this.graphicStore = new GraphicStore(this); + /** + * 默认都添加为非交互 + */ + this.interactiveTypeOptions = { interactiveGraphicTypeIncludes: [] }; + // 创建pixi渲染app + this.app = new Application({ + width: dom.clientWidth, + height: dom.clientHeight, + antialias: true, + resizeTo: dom, + }); + dom.appendChild(this.app.view as unknown as Node); + + // 创建画布 + this.canvas = new JlCanvas(this); + this.canvas.name = AppConsts.canvasname; + // 创建相机 + this.viewport = new Viewport({ + screenWidth: window.innerWidth, + screenHeight: window.innerHeight, + worldWidth: this.canvas._properties.width, + worldHeight: this.canvas._properties.height, + // divWheel: dom, + passiveWheel: true, + events: this.app.renderer.events, + disableOnContextMenu: true, + }); + // 设置视口操作方式 + this.viewport + .wheel({ + percent: 1, + }) + .pinch() + .clampZoom({ + minScale: 0.1, + maxScale: 8, + }) + .clamp({ + direction: 'all', + }); + this.viewport.name = AppConsts.viewportname; + this.viewport.interactiveChildren = true; + // 添加视口到渲染器舞台 + this.app.stage.addChild(this.viewport); + // 将画布置于视口 + this.viewport.addChild(this.canvas); + + // 监听并通知缩放变化事件 + this.viewport.on('zoomed-end', () => { + this.emit('viewport-scaled', this.viewport); + }); + + this.opRecord = new OperationRecord(); + + // 绑定键盘监听 + this.keyboardPlugin = new JlGraphicAppKeyboardPlugin(this); + this.graphicCopyPlugin = new GraphicCopyPlugin(this); + this.menuPlugin = new ContextMenuPlugin(this); + + // 添加通用交互插件 + CommonMouseTool.new(this).resume(); + + // drag插件 + DragPlugin.new(this).resume(); + // 视口移动插件 + ViewportMovePlugin.new(this); + + // 图形变换插件 + GraphicTransformPlugin.new(this).resume(); + + // 动画管理 + this.animationManager = new AnimationManager(this); + } + + setOptions(options: GraphicAppOptions) { + // console.log('更新选项', options); + if (this._options) { + this._options = Object.assign(this._options, options); + } else { + this._options = options; + } + if (options.interactiveTypeOptions) { + // 更新交互类型配置 + this.interactiveTypeOptions = options.interactiveTypeOptions; + } + if (options.maxOperationRecords && options.maxOperationRecords > 0) { + this.opRecord.setMaxLen(options.maxOperationRecords); + } + this.emit('options-update', options); + } + + /** + * 注册图形对象模板 + * @param graphicTemplates + */ + registerGraphicTemplates(...graphicTemplates: GraphicTemplate[]) { + graphicTemplates.forEach((graphicTemplate) => { + this.graphicTemplateMap.set(graphicTemplate.type, graphicTemplate); + }); + } + + getGraphicTemplatesByType(type: string): GT { + const template = this.graphicTemplateMap.get(type); + if (!template) { + throw new Error(`不存在type=${type}的图形对象模板`); + } + return template as GT; + } + + /** + * 注册菜单 + * @param menu + */ + registerMenu(menu: ContextMenu) { + this.menuPlugin.registerMenu(menu); + } + + /** + * 使能websocket Stomp通信 + */ + enableWsStomp(options: StompCliOption) { + StompCli.new(options); + this.wsMsgBroker = new AppWsMsgBroker(this); + } + + /** + * 订阅websocket消息 + */ + subscribe(sub: AppStateSubscription) { + if (this.wsMsgBroker) { + // console.log('APP订阅', sub) + this.wsMsgBroker.subscribe(sub); + } else { + throw new Error('请先打开StompClient, 执行app.enableWebsocket()'); + } + } + /** + * 取消websocket订阅 + */ + unsubscribe(destination: string) { + if (this.wsMsgBroker) { + this.wsMsgBroker.unsbuscribe(destination); + } else { + throw new Error('请先执行enableWebsocket'); + } + } + + /** + * 处理websocket状态 + * @param graphicStates + */ + handleGraphicStates(graphicStates: GraphicState[]) { + graphicStates.forEach((state) => { + const list = this.queryStore.queryByIdOrCode(state.code); + if (list.length == 0) { + const template = this.getGraphicTemplatesByType(state.graphicType); + const g = template.new(); + g.loadState(state); + this.addGraphics(g); + } else { + list.forEach((g) => { + g.updateStates(state); + }); + } + }); + } + + /** + * 添加键盘监听器,如果是相同的按键,新注册的会覆盖旧的,当移除新的时,旧的自动生效 + * @param keyListeners + */ + addKeyboardListener(...keyListeners: KeyListener[]) { + keyListeners.forEach((keyListener) => + this.keyboardPlugin.addKeyListener(keyListener) + ); + } + + /** + * 移除键盘监听器 + * @param keyListeners + */ + removeKeyboardListener(...keyListeners: KeyListener[]) { + keyListeners.forEach((keyListener) => + this.keyboardPlugin.removeKeyListener(keyListener) + ); + } + + /** + * dom尺寸变更处理 + * @param domWidth canvas容器的宽 + * @param domHeight canvas容器的高 + */ + onDomResize(domWidth: number, domHeight: number) { + this.updateViewport(domWidth, domHeight); + } + + public get queryStore(): GraphicQueryStore { + return this.graphicStore; + } + + public get selectedGraphics(): JlGraphic[] { + return this.queryStore.getAllGraphics().filter((g) => g.selected); + } + + fireSelectedChange(graphic: JlGraphic) { + // console.log('通知选中变化', this.selecteds) + const select = graphic.selected; + this.emit('graphicselectedchange', graphic, select); + } + + /** + * 更新选中 + */ + updateSelected(...graphics: JlGraphic[]) { + this.selectedGraphics.forEach((graphic) => { + if (graphics.findIndex((g) => g.id === graphic.id) >= 0) { + return; + } + if (graphic.selected) { + graphic.updateSelected(false); + this.fireSelectedChange(graphic); + } + }); + graphics.forEach((graphic) => { + if (graphic.updateSelected(true)) { + this.fireSelectedChange(graphic); + } + }); + } + + /** + * 更新画布 + * @param param + */ + updateCanvas(param: ICanvasProperties) { + this.canvas.update(param); + } + + /** + * 加载图形,GraphicApp默认添加到无交互容器,DrawApp默认添加到交互容器,如需定制,提供选项配置 + * @param protos + * @param options 添加到可交互/不可交互容器选项配置 + */ + async loadGraphic(protos: GraphicData[]) { + for (const item of this.graphicTemplateMap) { + await item[1].loadAssets(); + } + // console.log('开始加载proto数据', protos); + // 加载数据到图形存储 + protos.forEach((proto) => { + const template = this.getGraphicTemplatesByType(proto.graphicType); + const g = template.new(); + g.loadData(proto); + this.addGraphics(g); + }); + // 加载数据关系 + this.graphicStore.getAllGraphics().forEach((g) => g.loadRelations()); + // 更新id生成器 + const max = + this.graphicStore + .getAllGraphics() + .filter((g) => !isNaN(parseInt(g.id))) + .map((g) => parseInt(g.id)) + .sort((a, b) => a - b) + .pop() ?? 0; + // console.log('最大值', max) + GraphicIdGenerator.initSerial(max); + // 加载完成通知 + this.emit('loadfinish'); + } + + /** + * 添加图形前处理 + * @param graphic + */ + beforeGraphicStore(graphic: JlGraphic): void { + const options = this.interactiveTypeOptions; + // 默认无交互 + graphic.eventMode = 'auto'; + if (options) { + if ( + options.interactiveGraphicTypeIncludes && + options.interactiveGraphicTypeIncludes.findIndex( + (type) => type === graphic.type + ) >= 0 + ) { + graphic.eventMode = 'static'; + } else if ( + options.interactiveGraphicTypeExcludes && + options.interactiveGraphicTypeExcludes.findIndex( + (type) => type === graphic.type + ) < 0 + ) { + graphic.eventMode = 'static'; + } + } + } + private doAddGraphics(graphic: JlGraphic): void { + this.beforeGraphicStore(graphic); + if (this.graphicStore.storeGraphics(graphic)) { + // cullable,默认设置剪裁,如果图形包围框不在屏幕内,则不渲染,增加效率用 + if (!this._options || this._options.cullable !== false) { + graphic.cullable = true; + } + if (graphic.eventMode == 'static' || graphic.eventMode == 'dynamic') { + // 添加为可交互 + // console.log(`type=${graphic.type}的图形添加到交互容器`); + this.canvas.addChild(graphic); + } else { + // 添加到不可交互容器 + // console.log(`type=${graphic.type}的图形添加到无交互容器`); + this.canvas.addNonInteractiveChild(graphic); + } + graphic.repaint(); + this.emit('graphicstored', graphic); + graphic.on('childselected', (child) => { + this.emit('graphicchildselectedchange', child, true); + }); + graphic.on('childunselected', (child) => { + this.emit('graphicchildselectedchange', child, false); + }); + } + } + + private doDeleteGraphics(graphic: JlGraphic): void { + // graphic可能是vue的Proxy对象,会导致canvas删除时因不是同一个对象而无法从画布移除 + const g = this.graphicStore.deleteGraphics(graphic); + if (g) { + // 从画布移除 + this.canvas.removeGraphic(g); + // 清除选中 + if (g.updateSelected(false)) { + this.fireSelectedChange(g); + } + // 对象删除处理 + g.onDelete(); + this.emit('graphicdeleted', g); + } + } + + /** + * 存储图形 + * @param graphics 图形对象 + */ + addGraphics(...graphics: JlGraphic[]) { + graphics.forEach((g) => this.doAddGraphics(g)); + } + /** + * 删除图形 + * @param graphics 图形对象 + */ + deleteGraphics(...graphics: JlGraphic[]) { + graphics.forEach((g) => this.doDeleteGraphics(g)); + } + + /** + * 检测并构建关系 + */ + detectRelations(): void { + this.graphicStore.getAllGraphics().forEach((g) => g.buildRelation()); + } + + /** + * 转换操作坐标点为画布坐标点 + * @param e 事件 + * @returns 画布坐标点 + */ + toCanvasCoordinates(p: Point): Point { + return this.viewport.toWorld(p); + } + + /** + * 获取当前缩放倍率 + */ + getViewportScaled(): number { + return this.viewport.scaled; + } + /** + * 视口中心坐标 + * @returns + */ + getViewportCenter(): Point { + return this.viewport.center; + } + /** + * 获取视口角落坐标 + * @returns + */ + getViewportCorner(): Point { + return this.viewport.corner; + } + + /** + * 注册交互插件,会替换旧的 + */ + registerInteractionPlugin(...plugins: InteractionPlugin[]): void { + plugins.forEach((plugin) => { + const old = this.interactionPluginMap.get(plugin.name); + if (old) { + console.warn(`已经存在name=${plugin.name}的交互插件,忽略此插件注册!`); + return; + } + this.interactionPluginMap.set(plugin.name, plugin); + }); + } + + /** + * 根据名称获取交互插件 + * @param name + * @returns + */ + interactionPlugin

(name: string): P { + const plugin = this.interactionPluginMap.get(name); + if (!plugin) { + throw new Error(`未找到name=${name}的交互插件`); + } + return plugin as P; + } + + /** + * 停止应用交互插件 + */ + pauseAppInteractionPlugins(): void { + this.interactionPluginMap.forEach((plugin) => { + if (plugin.isActive() && plugin._type === InteractionPluginType.App) { + this.doPauseInteractionPlugin(plugin); + } + }); + } + + private doPauseInteractionPlugin(plugin?: InteractionPlugin): void { + if (plugin && plugin.isActive()) { + plugin.pause(); + this.emit('interaction-plugin-pause', plugin); + } + } + + /** + * 移除交互插件 + */ + removeInteractionPlugin(plugin: InteractionPlugin) { + this.interactionPluginMap.delete(plugin.name); + } + + updateViewport(domWidth?: number, domHeight?: number): void { + let screenWidth = this.viewport.screenWidth; + let screenHeight = this.viewport.screenHeight; + if (domWidth) { + screenWidth = domWidth; + } + if (domHeight) { + screenHeight = domHeight; + } + const worldWidth = this.canvas._properties.width; + const worldHeight = this.canvas._properties.height; + this.app.resize(); + this.viewport.resize(screenWidth, screenHeight, worldWidth, worldHeight); + if (this.viewport.OOB().right) { + this.viewport.right = this.viewport.right + 1; + } else if (this.viewport.OOB().left) { + this.viewport.left = this.viewport.left - 1; + } else if (this.viewport.OOB().top) { + this.viewport.top = this.viewport.top - 1; + } else if (this.viewport.OOB().bottom) { + this.viewport.bottom = this.viewport.bottom + 1; + } + } + + /** + * 使图形居中显示(所有图形的外包围盒) + */ + makeGraphicCenterShow(...group: JlGraphic[]): void { + if (group.length > 0) { + const bounds0 = group[0].getBounds(); + let lx = bounds0.x; + let ly = bounds0.y; + let rx = bounds0.x + bounds0.width; + let ry = bounds0.y + bounds0.height; + if (group.length > 1) { + for (let i = 1; i < group.length; i++) { + const g = group[i]; + const bound = g.getBounds(); + if (bound.x < lx) { + lx = bound.x; + } + if (bound.y < ly) { + ly = bound.y; + } + const brx = bound.x + bound.width; + if (brx > rx) { + rx = brx; + } + const bry = bound.y + bound.height; + if (bry > ry) { + ry = bry; + } + } + } + const { x, y } = getRectangleCenter( + new Rectangle(lx, ly, rx - lx, ry - ly) + ); + const p = this.viewport.toWorld(x, y); + this.viewport.moveCenter(p.x, p.y); + } + } + + /** + * 销毁 + */ + destroy(): void { + console.log('销毁图形 APP'); + this.emit('destroy', this); + if (this.wsMsgBroker) { + this.wsMsgBroker.close(); + // if (!StompCli.hasAppMsgBroker()) { + // // 如果没有其他消息代理,关闭websocket Stomp客户端 + // StompCli.close(); + // } + } + this.interactionPluginMap.forEach((plugin) => { + plugin.pause(); + }); + this.canvas.destroy(true); + this.viewport.destroy(); + this.app.destroy(true, true); + document.body.style.overflow = 'auto'; + } +} diff --git a/src/jl-graphic/app/index.ts b/src/jl-graphic/app/index.ts new file mode 100644 index 0000000..9e8a44a --- /dev/null +++ b/src/jl-graphic/app/index.ts @@ -0,0 +1,2 @@ +export * from './JlGraphicApp'; +export * from './JlDrawApp'; diff --git a/src/jl-graphic/core/GraphicRelation.ts b/src/jl-graphic/core/GraphicRelation.ts new file mode 100644 index 0000000..88375d5 --- /dev/null +++ b/src/jl-graphic/core/GraphicRelation.ts @@ -0,0 +1,185 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { GraphicApp } from '../app/JlGraphicApp'; +import { JlGraphic } from './JlGraphic'; + +/** + * 图形关系数据 + */ +export class GraphicRelationParam { + g: JlGraphic; + param: any; + constructor(g: JlGraphic, param: any = null) { + this.g = g; + this.param = param; + } + isTheGraphic(g: JlGraphic): boolean { + return this.g.id === g.id; + } + getGraphic(): G { + return this.g as G; + } + getParam

(): P { + return this.param as P; + } + equals(other: GraphicRelationParam): boolean { + return this.isTheGraphic(other.g) && this.param === other.param; + } +} +/** + * 图形关系 + */ +export class GraphicRelation { + rp1: GraphicRelationParam; + rp2: GraphicRelationParam; + constructor(rp1: GraphicRelationParam, rp2: GraphicRelationParam) { + this.rp1 = rp1; + this.rp2 = rp2; + } + + contains(g: JlGraphic): boolean { + return this.rp1.isTheGraphic(g) || this.rp2.isTheGraphic(g); + } + + /** + * 获取给定图形的关系参数 + * @param g + * @returns + */ + getRelationParam(g: JlGraphic): GraphicRelationParam { + if (!this.contains(g)) { + throw new Error( + `图形关系${this.rp1.g.id}-${this.rp2.g.id}中不包含给定图形${g.id}` + ); + } + if (this.rp1.isTheGraphic(g)) { + return this.rp1; + } else { + return this.rp2; + } + } + /** + * 获取关联的另一个图形的关系参数 + * @param g + * @returns + */ + getOtherRelationParam(g: JlGraphic): GraphicRelationParam { + if (!this.contains(g)) { + throw new Error( + `图形关系${this.rp1.g.id}-${this.rp2.g.id}中不包含给定图形${g.id}` + ); + } + if (this.rp1.isTheGraphic(g)) { + return this.rp2; + } else { + return this.rp1; + } + } + /** + * 获取关联的另一个图形对象 + * @param g + * @returns graphic + */ + getOtherGraphic(g: JlGraphic): G { + return this.getOtherRelationParam(g).g as G; + } + + equals(orp1: GraphicRelationParam, orp2: GraphicRelationParam): boolean { + if (this.rp1.isTheGraphic(orp1.g)) { + return this.rp1.equals(orp1) && this.rp2.equals(orp2); + } else if (this.rp1.isTheGraphic(orp2.g)) { + return this.rp1.equals(orp2) && this.rp2.equals(orp1); + } + return false; + } + + isEqualOther(other: GraphicRelation): boolean { + return this.equals(other.rp1, other.rp2); + } +} + +/** + * 图形关系管理 + */ +export class RelationManage { + app: GraphicApp; + relations: GraphicRelation[] = []; + constructor(app: GraphicApp) { + this.app = app; + } + + isContainsRelation( + rp1: GraphicRelationParam, + rp2: GraphicRelationParam + ): boolean { + const relation = this.relations.find((relation) => + relation.equals(rp1, rp2) + ); + return !!relation; + } + addRelation( + rp1: GraphicRelationParam | JlGraphic, + rp2: GraphicRelationParam | JlGraphic + ): void { + if (!(rp1 instanceof GraphicRelationParam)) { + rp1 = new GraphicRelationParam(rp1); + } + if (!(rp2 instanceof GraphicRelationParam)) { + rp2 = new GraphicRelationParam(rp2); + } + if (!this.isContainsRelation(rp1, rp2)) { + const relation = new GraphicRelation(rp1, rp2); + this.relations.push(relation); + } + } + + /** + * 获取图形的所有关系 + * @param g + * @returns + */ + getRelationsOfGraphic(g: JlGraphic): GraphicRelation[] { + return this.relations.filter((rl) => rl.contains(g)); + } + + /** + * 获取指定图形的指定关系图形类型的所有关系 + * @param g 指定图形 + * @param type 关联图形的类型 + * @returns + */ + getRelationsOfGraphicAndOtherType( + g: JlGraphic, + type: string + ): GraphicRelation[] { + return this.relations.filter( + (rl) => rl.contains(g) && rl.getOtherGraphic(g).type === type + ); + } + + /** + * 删除关系 + * @param relation + */ + private deleteRelation(relation: GraphicRelation): void { + const index = this.relations.findIndex((rl) => rl.isEqualOther(relation)); + if (index >= 0) { + this.relations.splice(index, 1); + } + } + /** + * 删除指定图形的所有关系 + * @param g + */ + deleteRelationOfGraphic(g: JlGraphic): void { + const relations = this.getRelationsOfGraphic(g); + relations.forEach((rl) => this.deleteRelation(rl)); + } + /** + * 删除指定图形的所有关系 + * @param g + */ + deleteRelationOfGraphicAndOtherType(g: JlGraphic, type: string): void { + const relations = this.getRelationsOfGraphicAndOtherType(g, type); + relations.forEach((rl) => this.deleteRelation(rl)); + } +} diff --git a/src/jl-graphic/core/GraphicStore.ts b/src/jl-graphic/core/GraphicStore.ts new file mode 100644 index 0000000..979bd20 --- /dev/null +++ b/src/jl-graphic/core/GraphicStore.ts @@ -0,0 +1,185 @@ +import { GraphicApp } from '../app/JlGraphicApp'; +import { RelationManage } from './GraphicRelation'; +import { JlGraphic } from './JlGraphic'; + +export interface GraphicQueryStore { + /** + * 获取所有图形对象 + */ + getAllGraphics(): JlGraphic[]; + /** + * 根据id获取图形 + */ + queryById(id: string): T; + /** + * 根据id模糊查询图形 + * @param id + */ + queryByIdAmbiguous(id: string): JlGraphic[]; + + /** + * 根据类型获取图形列表 + */ + queryByType(type: string): T[]; + /** + * 根据code查询 + * @param code + */ + queryByCode(code: string): JlGraphic[] | undefined; + /** + * 根据code模糊查询图形 + * @param code + * @param type + */ + queryByCodeAmbiguous(code: string): JlGraphic[]; + /** + * 根据id或code查询图形 + * @param v + */ + queryByIdOrCode(v: string): JlGraphic[]; + /** + * 根据code和类型获取图形 + * @param code + * @param type + */ + queryByCodeAndType( + code: string, + type: string + ): T | undefined; + /** + * 根据code和类型模糊查询图形 + * @param code + * @param type + */ + queryByCodeAndTypeAmbiguous( + code: string, + type: string + ): T[]; +} + +/** + * 图形存储 + */ +export class GraphicStore implements GraphicQueryStore { + app: GraphicApp; + store: Map; + relationManage: RelationManage; + constructor(app: GraphicApp) { + this.app = app; + this.store = new Map(); + this.relationManage = new RelationManage(app); + } + /** + * 获取所有图形对象 + */ + getAllGraphics(): JlGraphic[] { + return [...this.store.values()]; + } + queryById(id: string): T { + const graphic = this.store.get(id) as T; + if (!graphic) throw Error(`未找到id为 [${id}] 的图形.`); + return this.store.get(id) as T; + } + queryByIdAmbiguous(id: string): JlGraphic[] { + const list: JlGraphic[] = []; + this.store.forEach((g) => { + if (g.id.search(id) >= 0) { + list.push(g); + } + }); + return list; + } + queryByType(type: string): T[] { + const list: T[] = []; + this.store.forEach((g) => { + if (g.type === type) { + list.push(g as T); + } + }); + return list; + } + queryByCode(code: string): JlGraphic[] | undefined { + const list: JlGraphic[] = []; + this.store.forEach((g) => { + if (g.code === code) { + list.push(g); + } + }); + return list; + } + queryByCodeAmbiguous(code: string): JlGraphic[] { + const list: JlGraphic[] = []; + this.store.forEach((g) => { + if (g.code.search(code) >= 0) { + list.push(g); + } + }); + return list; + } + queryByIdOrCode(s: string): JlGraphic[] { + const list: JlGraphic[] = []; + this.store.forEach((g) => { + if (g.isIdOrCode(s)) { + list.push(g); + } + }); + return list; + } + queryByCodeAndType( + code: string, + type: string + ): T | undefined { + for (const item of this.store.values()) { + if (item.code === code && item.type === type) { + return item as T; + } + } + } + queryByCodeAndTypeAmbiguous( + code: string, + type: string + ): T[] { + const list: T[] = []; + this.store.forEach((g) => { + if (g.type === type && g.code.search(code) >= 0) { + list.push(g as T); + } + }); + return list; + } + + /** + * 存储图形对象 + * @param graphics 要存储的图形 + */ + storeGraphics(graphic: JlGraphic): boolean { + if (!graphic.id || graphic.id.trim() === '') { + throw new Error(`存储图形对象异常: id为空, ${graphic}`); + } + if (this.store.has(graphic.id)) { + // 已经存在 + const exist = this.store.get(graphic.id); + console.error(`已经存在id=${graphic.id}的设备${exist}`); + return false; + } else { + this.store.set(graphic.id, graphic); + graphic.queryStore = this; + graphic.relationManage = this.relationManage; + return true; + } + } + /** + * 删除图形 + * @param graph 要删除的图形 + */ + deleteGraphics(graphic: JlGraphic): JlGraphic | undefined { + const id = graphic.id; + const remove = this.store.get(id); + if (remove) { + this.store.delete(id); + // 删除图形关系 + this.relationManage.deleteRelationOfGraphic(remove); + } + return remove; + } +} diff --git a/src/jl-graphic/core/IdGenerator.ts b/src/jl-graphic/core/IdGenerator.ts new file mode 100644 index 0000000..131f699 --- /dev/null +++ b/src/jl-graphic/core/IdGenerator.ts @@ -0,0 +1,28 @@ +/** + * ID生成器 + */ +export class IdGenerator { + serial = 0; + type: string; + + constructor(type: string) { + this.type = type; + } + + next(): string { + ++this.serial; + // console.log(this.getType() + this.serial) + return this.getType() + this.serial; + } + + getType(): string { + return this.type; + } + + initSerial(serial: number): void { + // console.log(serial) + this.serial = serial; + } +} + +export const GraphicIdGenerator: IdGenerator = new IdGenerator(''); diff --git a/src/jl-graphic/core/JlGraphic.ts b/src/jl-graphic/core/JlGraphic.ts new file mode 100644 index 0000000..7ed967a --- /dev/null +++ b/src/jl-graphic/core/JlGraphic.ts @@ -0,0 +1,1015 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-empty-function */ +import { Viewport } from 'pixi-viewport'; +import { + Container, + DisplayObject, + Graphics, + IPointData, + Point, + Rectangle, +} from 'pixi.js'; +import { AppConsts, JlCanvas } from '../app'; +import { + convertRectangleToPolygonPoints, + recursiveChildren, + recursiveFindChild, + recursiveFindParent, + recursiveParents, +} from '../utils'; +import { GraphicRelation, RelationManage } from './GraphicRelation'; +import { GraphicQueryStore } from './GraphicStore'; +import { GraphicIdGenerator } from './IdGenerator'; + +//基础图形对象扩展 +DisplayObject.prototype._selectable = false; //是否可选中 +DisplayObject.prototype._selected = false; +DisplayObject.prototype._childEdit = false; +DisplayObject.prototype._transformSave = false; +DisplayObject.prototype._assistantAppendMap = null; +DisplayObject.prototype._draggable = false; +DisplayObject.prototype._shiftStartPoint = null; +DisplayObject.prototype._shiftLastPoint = null; +DisplayObject.prototype._scalable = false; +DisplayObject.prototype._keepAspectRatio = true; +DisplayObject.prototype._rotatable = false; +Object.defineProperties(DisplayObject.prototype, { + assistantAppendMap: { + get() { + if (this._assistantAppendMap == null) { + this._assistantAppendMap = new Map(); + } + return this._assistantAppendMap; + }, + }, + selectable: { + get(): boolean { + return this._selectable; + }, + set(value: boolean): void { + this._selectable = value; + }, + }, + selected: { + get(): boolean { + return this._selected; + }, + set(v) { + this._selected = v; + }, + }, + childEdit: { + get() { + return this._childEdit; + }, + set(v) { + this._childEdit = v; + }, + }, + transformSave: { + get() { + return this._transformSave; + }, + set(v) { + this._transformSave = v; + }, + }, + draggable: { + get(): boolean { + return this._draggable; + }, + set(v) { + this._draggable = v; + }, + }, + shiftStartPoint: { + get() { + return this._shiftStartPoint; + }, + set(v) { + this._shiftStartPoint = v; + }, + }, + shiftLastPoint: { + get() { + return this._shiftLastPoint; + }, + set(v) { + this._shiftLastPoint = v; + }, + }, + scalable: { + get() { + return this._scalable; + }, + set(v) { + this._scalable = v; + }, + }, + keepAspectRatio: { + get(): boolean { + return this._keepAspectRatio; + }, + set(v) { + this._keepAspectRatio = v; + }, + }, + rotatable: { + get() { + return this._rotatable; + }, + set(v) { + this._rotatable = v; + }, + }, + worldAngle: { + get() { + let angle = this.angle; + let parent = this.parent; + while (parent != undefined && parent != null) { + angle += parent.angle; + parent = parent.parent; + } + angle = angle % 360; + if (angle > 180) { + angle = angle - 360; + } + return angle; + }, + }, +}); +DisplayObject.prototype.getAllParentScaled = + function getAllParentScaled(): Point { + const scaled = new Point(1, 1); + recursiveParents(this, (parent) => { + scaled.x *= parent.scale.x; + scaled.y *= parent.scale.y; + }); + return scaled; + }; +DisplayObject.prototype.getPositionOnCanvas = + function getPositionOnCanvas(): Point { + if (this.parent.isCanvas()) { + return this.position; + } else { + return this.parent.localToCanvasPoint(this.position); + } + }; +DisplayObject.prototype.updatePositionByCanvasPosition = + function updatePositionByCanvasPosition(p: IPointData): void { + if (this.parent.isCanvas()) { + this.position.copyFrom(p); + } else { + const localPosition = this.parent.canvasToLocalPoint(p); + this.position.copyFrom(localPosition); + } + }; +DisplayObject.prototype.saveTransform = function saveTransform() { + return GraphicTransform.fromObject(this); +}; +DisplayObject.prototype.loadTransform = function loadTransform( + transfrom: GraphicTransform +) { + this.position.copyFrom(transfrom.position); + this.scale.copyFrom(transfrom.scale); + this.rotation = transfrom.rotation; + this.skew.copyFrom(transfrom.skew); +}; +DisplayObject.prototype.isChild = function isChild( + obj: DisplayObject +): boolean { + return recursiveFindChild(this as Container, (child) => child == obj) != null; +}; +DisplayObject.prototype.isParent = function isParent( + obj: DisplayObject +): boolean { + return recursiveFindParent(this, (parent) => parent == obj) != null; +}; +DisplayObject.prototype.isAssistantAppend = + function isAssistantAppend(): boolean { + return ( + recursiveFindParent(this, (parent) => { + return parent.name === AppConsts.AssistantAppendsName; + }) != null + ); + }; +DisplayObject.prototype.addAssistantAppend = function addAssistantAppend< + D extends DisplayObject +>(...appends: D[]): void { + appends.forEach((append) => { + if (append.name == null || append.name.trim() == '') { + throw new Error('辅助附加name不能为空'); + } + this.assistantAppendMap.set(append.name, append); + this.getCanvas().addAssistantAppends(append); + }); +}; +DisplayObject.prototype.getAssistantAppend = function getAssistantAppend< + D extends DisplayObject +>(name: string): D | undefined { + return this.assistantAppendMap.get(name) as D; +}; +DisplayObject.prototype.removeAssistantAppend = function removeAssistantAppend( + ...appends: DisplayObject[] +): void { + appends.forEach((append) => { + if (append.name) { + this.removeAssistantAppendByName(append.name); + } + }); +}; +DisplayObject.prototype.removeAssistantAppendByName = + function removeAssistantAppendByName(...names: string[]): void { + names.forEach((name) => { + const append = this.getAssistantAppend(name); + if (append) { + this.getCanvas().removeAssistantAppends(append); + this.assistantAppendMap.delete(name); + append.destroy(); + } + }); + }; +DisplayObject.prototype.removeAllAssistantAppend = + function removeAllAssistantAppend(): void { + if (this._assistantAppendMap != null) { + this.assistantAppendMap.forEach((append) => { + append.getCanvas().removeAssistantAppends(append); + }); + this.assistantAppendMap.clear(); + } + }; + +DisplayObject.prototype.isGraphic = function isGraphic() { + return Object.hasOwn(this, '__JlGraphic'); +}; +DisplayObject.prototype.getGraphic = function getGraphic< + G extends JlGraphic +>(): G | null { + let graphic = this as DisplayObject; + while (graphic && !Object.hasOwn(graphic, '__JlGraphic')) { + graphic = graphic.parent; + } + if (graphic) { + return graphic as G; + } + return null; +}; +DisplayObject.prototype.isGraphicChild = function isGraphicChild() { + const g = this.getGraphic(); + return g != null && !this.isAssistantAppend() && g.isChild(this); +}; +DisplayObject.prototype.onAddToCanvas = function onAddToCanvas() {}; +DisplayObject.prototype.onRemoveFromCanvas = function onRemoveFromCanvas() {}; +DisplayObject.prototype.isInCanvas = function isInCanvas(): boolean { + let graphic = this as DisplayObject; + while (graphic && !Object.hasOwn(graphic, '__JlCanvas')) { + graphic = graphic.parent; + } + if (graphic) { + return true; + } + return false; +}; +DisplayObject.prototype.getCanvas = function getCanvas() { + let graphic = this as DisplayObject; + while (graphic && !Object.hasOwn(graphic, '__JlCanvas')) { + graphic = graphic.parent; + } + if (graphic) { + return graphic as JlCanvas; + } + throw new Error(`图形${this.name}不在画布中`); +}; +DisplayObject.prototype.isCanvas = function isCanvas(): boolean { + return Object.hasOwn(this, '__JlCanvas'); +}; +DisplayObject.prototype.getViewport = function getViewport() { + const canvas = this.getCanvas(); + return canvas.parent as Viewport; +}; +DisplayObject.prototype.getGraphicApp = function getGraphicApp() { + const canvas = this.getCanvas(); + return canvas.app; +}; +DisplayObject.prototype.localToCanvasPoint = function localToCanvasPoint( + p: IPointData +): Point { + return this.getViewport().toWorld(this.toGlobal(p)); +}; +DisplayObject.prototype.localToCanvasPoints = function localToCanvasPoints( + ...points: IPointData[] +): Point[] { + return points.map((p) => this.localToCanvasPoint(p)); +}; +DisplayObject.prototype.canvasToLocalPoint = function canvasToLocalPoint( + p: IPointData +): Point { + return this.toLocal(this.getViewport().toScreen(p)); +}; +DisplayObject.prototype.canvasToLocalPoints = function canvasToLocalPoints( + ...points: IPointData[] +): Point[] { + return points.map((p) => this.canvasToLocalPoint(p)); +}; +DisplayObject.prototype.localToScreenPoint = function localToScreenPoint( + p: IPointData +): Point { + return this.toGlobal(p); +}; +DisplayObject.prototype.localToScreenPoints = function localToScreenPoints( + ...points: IPointData[] +): Point[] { + return points.map((p) => this.toGlobal(p)); +}; +DisplayObject.prototype.screenToLocalPoint = function screenToLocalPoint( + p: IPointData +): Point { + return this.toLocal(p); +}; +DisplayObject.prototype.screenToLocalPoints = function screenToLocalPoints( + ...points: IPointData[] +): Point[] { + return points.map((p) => this.toLocal(p)); +}; + +DisplayObject.prototype.localBoundsToCanvasPoints = + function localBoundsToCanvasPoints() { + const rect = this.getLocalBounds(); + const pps = convertRectangleToPolygonPoints(rect); + return this.localToCanvasPoints(...pps); + }; + +// 扩展pixijs图形对象,添加自定义绘制贝塞尔曲线,可自定义分段数 +Graphics.prototype.drawBezierCurve = function drawBezierCurve( + p1: IPointData, + p2: IPointData, + cp1: IPointData, + cp2: IPointData, + segmentsCount: number +): Graphics { + const fromX = p1.x; + const fromY = p1.y; + const n = segmentsCount; + let dt = 0; + let dt2 = 0; + let dt3 = 0; + let t2 = 0; + let t3 = 0; + const cpX = cp1.x; + const cpY = cp1.y; + const cpX2 = cp2.x; + const cpY2 = cp2.y; + const toX = p2.x; + const toY = p2.y; + this.moveTo(p1.x, p1.y); + for (let i = 1, j = 0; i <= n; ++i) { + j = i / n; + dt = 1 - j; + dt2 = dt * dt; + dt3 = dt2 * dt; + t2 = j * j; + t3 = t2 * j; + const px = dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX; + const py = dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY; + this.lineTo(px, py); + } + return this; +}; + +export interface IGraphicTransform { + position: IPointData; + scale: IPointData; + rotation: number; + skew: IPointData; +} + +/** + * 图形变换数据 + */ +export class GraphicTransform { + position: IPointData; + scale: IPointData; + rotation: number; + skew: IPointData; + + constructor( + position: IPointData, + scale: IPointData, + rotation: number, + skew: IPointData + ) { + this.position = position; + this.scale = scale; + this.rotation = rotation; + this.skew = skew; + } + static default(): GraphicTransform { + return new GraphicTransform( + new Point(0, 0), + new Point(1, 1), + 0, + new Point(0, 0) + ); + } + static fromObject(obj: DisplayObject): GraphicTransform { + return new GraphicTransform( + obj.position.clone(), + obj.scale.clone(), + obj.rotation, + obj.skew.clone() + ); + } + static from(transform: IGraphicTransform | undefined): GraphicTransform { + if (transform) { + return new GraphicTransform( + new Point(transform.position.x, transform.position.y), + new Point(transform.scale.x, transform.scale.y), + transform.rotation, + new Point(transform.skew.x, transform.skew.y) + ); + } + return GraphicTransform.default(); + } +} + +export interface IChildTransform { + name: string; + transform: IGraphicTransform; +} + +/** + * 图形子元素变换 + */ +export class ChildTransform { + name: string; + transform: GraphicTransform; + constructor(name: string, transform: GraphicTransform) { + this.name = name; + this.transform = transform; + } + static fromChild(child: DisplayObject): ChildTransform { + if ( + child.name == null || + child.name == undefined || + child.name.trim() == '' + ) { + throw new Error( + `图形type=${ + child.getGraphic()?.type + }的子元素${child}name为空,但设置为需要保存变换数据` + ); + } + return new ChildTransform(child.name, GraphicTransform.fromObject(child)); + } + static from(ct: IChildTransform): ChildTransform { + return new ChildTransform(ct.name, GraphicTransform.from(ct.transform)); + } +} + +/** + * 图形数据 + */ +export interface GraphicData { + get id(): string; // 图形id + set id(v: string); + get graphicType(): string; // 图形类型 + set graphicType(v: string); + get transform(): GraphicTransform; // + set transform(v: GraphicTransform); + get childTransforms(): ChildTransform[] | undefined; // + set childTransforms(v: ChildTransform[] | undefined); + + /** + * 克隆消息 + */ + clone(): GraphicData; + /** + * 从给定数据拷贝 + * @param data + */ + copyFrom(data: GraphicData): void; + /** + * 是否相等 + * @param other + */ + eq(other: GraphicData): boolean; +} + +/** + * 图形状态 + */ +export interface GraphicState { + get code(): string; // 业务标识 + get graphicType(): string; // 图形类型 + /** + * 克隆消息 + */ + clone(): GraphicState; + /** + * 从给定数据拷贝 + * @param data + */ + copyFrom(data: GraphicState): void; + /** + * 是否相等 + * @param data + */ + eq(data: GraphicState): boolean; +} + +export interface GraphicAnimationOptions { + name: string; + + run?: (dt: number) => void; +} + +export class GraphicAnimation { + options: GraphicAnimationOptions; + _running: boolean; + /** + * 倍速 + */ + _xSpeed: number; + constructor(options: GraphicAnimationOptions) { + this.options = options; + this._running = false; + this._xSpeed = 1; + } + + static init(options: GraphicAnimationOptions) { + return new GraphicAnimation(options); + } + + pause(): GraphicAnimation { + this._running = false; + return this; + } + resume(): GraphicAnimation { + this._running = true; + return this; + } + + public get name(): string { + return this.options.name; + } + + public get running(): boolean { + return this._running; + } + + public get xSpeed(): number { + return this._xSpeed; + } + + public set xSpeed(v: number) { + this._xSpeed = v; + } + + run(dt: number): GraphicAnimation { + if (this.options.run) { + this.options.run(dt * this.xSpeed); + } + return this; + } +} + +/** + * 图形对象基类 + */ +export abstract class JlGraphic extends Container { + readonly __JlGraphic = true as const; + readonly type: string; // 图形类型 + private _id = ''; // 图形的唯一标识,不具有业务意义,唯一,不可重复,可用做图形数据关联。 + private _code = ''; // 业务编号/名称,用于标识图形对象,具有业务意义 + _datas?: GraphicData; // 图形数据 + _states?: GraphicState; // 图形状态数据 + private _relationManage?: RelationManage; // 图形关系管理 + private _queryStore?: GraphicQueryStore; // 图形对象查询仓库 + + constructor(type: string) { + super(); + this.type = type; + this.draggable = false; + this.filters; + } + + /** + * 添加图形动画,只有在画布上才能添加 + * @param animation + */ + addAnimation(animation: GraphicAnimation): void { + const app = this.getGraphicApp(); + app.animationManager.registerAnimation(this, animation); + } + removeAnimation(name: string): void { + const app = this.getGraphicApp(); + app.animationManager.unregisterAnimation(this, name); + } + animation(name: string): GraphicAnimation | undefined { + const app = this.getGraphicApp(); + return app.animationManager.animation(this, name); + } + removeAllAnimation(): void { + const app = this.getGraphicApp(); + app.animationManager.unregisterGraphicAnimations(this); + } + + /** + * 更新选中状态 + * @param selected + * @returns 是否更新 + */ + updateSelected(selected: boolean): boolean { + if (this.selected !== selected) { + this.selected = selected; + this.fireSelected(); + return true; + } + return false; + } + + invertSelected() { + this.selected = !this.selected; + this.fireSelected(); + } + + fireSelected() { + if (this.selected) { + this.emit('selected', this); + } else { + this.exitChildEdit(); + this.removeAllChildSelected(); + this.emit('unselected', this); + } + } + + hasSelectedChilds(): boolean { + return ( + recursiveFindChild(this, (child) => { + if (child.selected) { + return true; + } + return false; + }) != null + ); + } + setChildSelected(child: DisplayObject): boolean { + if (child.isGraphicChild() && child.selectable) { + this.removeAllChildSelected(); + child.selected = true; + this.fireChildSelected(child); + } + return false; + } + invertChildSelected(child: DisplayObject): boolean { + if (child.isGraphicChild() && child.selectable) { + child.selected = !child.selected; + this.fireChildSelected(child); + } + return false; + } + removeAllChildSelected() { + recursiveChildren(this, (child) => { + if (child.selected) { + child.selected = false; + this.fireChildSelected(child); + } + }); + } + fireChildSelected(child: DisplayObject) { + if (child.selected) { + this.emit('childselected', child); + } else { + this.emit('childunselected', child); + } + } + exitChildEdit() { + this.childEdit = false; + this.removeAllChildSelected(); + } + + /** + * 是否此对象id/code + */ + isIdOrCode(s: string): boolean { + return this.id === s || this.code === s; + } + + /** + * 获取图形id,如果图形数据对象存在,则返回图形数据对象id + */ + public get id(): string { + if (this._datas) { + return this._datas.id; + } + return this._id; + } + /** + * 设置图形id,如果图形数据存在,则同时设置图形数据id + */ + public set id(v: string) { + this._id = v; + if (this._datas) { + this._datas.id = v; + } + } + /** + * 获取图形业务code,如果业务code在图形数据或图形状态中,则需要重写此方法 + */ + public get code(): string { + return this._code; + } + /** + * 设置图形业务code,如果业务code在图形数据或图形状态中,则需要重写此方法 + */ + public set code(v: string) { + this._code = v; + } + + getDatas(): D { + if (this._datas) { + return this._datas as D; + } + throw new Error(`id=${this.id},type=${this.type}的图形没有数据`); + } + + getStates(): S { + if (this._states) { + return this._states as S; + } + throw new Error(`id=${this.id},type=${this.type}的的图形没有状态`); + } + + public get queryStore(): GraphicQueryStore { + if (this._queryStore) { + return this._queryStore; + } + throw new Error(`type=${this.type}的图形没有QueryStore`); + } + + public set queryStore(v: GraphicQueryStore) { + this._queryStore = v; + } + + public get relationManage(): RelationManage { + if (this._relationManage) { + return this._relationManage; + } + throw new Error(`type=${this.type}的图形没有关系管理`); + } + + public set relationManage(v: RelationManage) { + this._relationManage = v; + } + + /** + * 构建图形关系 + * @param g + */ + buildRelation() {} + + /** + * 从数据加载恢复图形关系 + */ + loadRelations() {} + + /** + * 获取当前图形的所有图形关系 + * @returns + */ + getAllRelations(): GraphicRelation[] { + return this.relationManage.getRelationsOfGraphic(this); + } + /** + * 获取当前图形的所有指定类型图形关系 + * @param type + * @returns + */ + queryRelationByType(type: string): GraphicRelation[] { + return this.relationManage.getRelationsOfGraphicAndOtherType(this, type); + } + /** + * 删除当前图形关联的指定类型的关系 + * @param type + */ + deleteRelationByType(type: string): void { + this.relationManage.deleteRelationOfGraphicAndOtherType(this, type); + } + + /** + * 构建并保存关系数据到datas中 + */ + saveRelations(): void {} + /** + * 保存数据,复制,非原始数据 + * @returns + */ + saveData(): D { + this.getDatas().graphicType = this.type; + this.getDatas().transform = GraphicTransform.fromObject(this); + this.getDatas().childTransforms = this.buildChildTransforms(); + this.saveRelations(); + return this.getDatas().clone() as D; + } + /** + * 构建子元素变换列表 + * @returns + */ + private buildChildTransforms(): ChildTransform[] { + const childTransforms: ChildTransform[] = []; + recursiveChildren(this, (child) => { + if (child.transformSave) { + childTransforms.push(ChildTransform.fromChild(child)); + } + }); + return childTransforms; + } + + /** + * 加载数据 + * @param data + */ + loadData(data: GraphicData) { + if (data.graphicType !== this.type) { + throw new Error( + `不同的图形类型,请检查数据是否正常: data.graphicType="${data.graphicType}, type="${this.type}` + ); + } + this._datas = data; + this.loadTransformFrom(data); + } + + private loadTransformFrom(data: GraphicData) { + if (data.transform) { + this.loadTransform(data.transform); + } + if (data.childTransforms) { + data.childTransforms.forEach((ct) => { + const child = this.getChildByName(ct.name, true); + if (child) { + child.loadTransform(ct.transform); + } + }); + } + } + /** + * 更新图形数据 + * @param data + * @returns + */ + updateData(data: GraphicData): boolean { + let update = false; + if (!this.getDatas().eq(data)) { + update = true; + const old = this.getDatas().clone(); + this.getDatas().copyFrom(data); + this.onDataChange(data, old); + this.loadTransformFrom(data); + this.emit('dataupdate', this.getDatas(), old); + this.repaint(); + } + return update; + } + /** + * 图形数据更新 + */ + onDataChange(newVal: GraphicData, old?: GraphicData): void {} + + /** + * 加载状态 + * @param state + */ + loadState(state: GraphicState) { + if (state.graphicType !== this.type) { + throw new Error( + `不同的图形类型,请检查数据是否正常: state.graphicType="${state.graphicType}, type="${this.type}` + ); + } + this._states = state; + } + /** + * 更新状态 + * @param state + * @returns + */ + updateStates(state: GraphicState): boolean { + let stateChange = false; + if (!this.getStates().eq(state)) { + // 判断并更新状态,默认状态 + const old = this.getStates().clone(); + this.getStates().copyFrom(state); + this.onStateChange(state, old); + stateChange = true; + this.emit('stateupdate', this.getStates(), old); + this.repaint(); + } + return stateChange; + } + /** + * 图形状态更新处理 + */ + onStateChange(newVal: GraphicState, old?: GraphicState): void {} + + repaint(): void { + this.doRepaint(); + this.emit('repaint', this); + } + + /** + * 处理重绘逻辑 + */ + abstract doRepaint(): void; + + /** + * 处理删除逻辑 + */ + onDelete(): void { + this.removeAllAssistantAppend(); + this.removeAllListeners(); + recursiveChildren(this, (child) => child.removeAllAssistantAppend()); + } + + /** + * 框选检测,默认取图形包围盒判定,若需要精细判定-子类重写此方法 + * @param box + * @returns + */ + boxIntersectCheck(box: Rectangle): boolean { + return box.intersects(this.getLocalBounds(), this.localTransform); + } +} + +export type CreateData = () => GraphicData; +export type CreateState = () => GraphicState; + +export interface IGraphicTemplateOptions { + dataTemplate?: GraphicData; + stateTemplate?: GraphicState; +} + +/** + * 图形对象模板 + */ +export abstract class JlGraphicTemplate { + readonly type: string; + options: IGraphicTemplateOptions; + + constructor(type: string, options: IGraphicTemplateOptions) { + this.type = type; + this.options = options; + } + + get datas(): GraphicData { + if (this.options.dataTemplate) { + return this.options.dataTemplate.clone(); + } + throw new Error(`type=${this.type}的图形模板没有数据模板`); + } + + get states(): GraphicState { + if (this.options.stateTemplate) { + return this.options.stateTemplate.clone(); + } + throw new Error(`type=${this.type}的图形模板没有状态模板`); + } + + // getDataCreator(): T { + // return this.options.dataCreator as T; + // } + // getStateCreator(): T { + // return this.options.stateCreator as T; + // } + + /** + * 初始化一个新的图形对象 + */ + abstract new(): G; + /** + * 加载图形对象需要用到的资源 + */ + async loadAssets(): Promise {} + + /** + * 克隆图形对象 + * @param graphic + * @returns + */ + clone(graphic: G): G { + const g = this.new(); + if (graphic._datas) { + // 数据克隆 + const datas = graphic.saveData(); + g.loadData(datas); + } + if (graphic._states) { + // 状态克隆 + const state = graphic.getStates().clone(); + g.loadState(state); + } + g.id = GraphicIdGenerator.next(); + return g; + } +} + +export type GraphicTemplate = JlGraphicTemplate; diff --git a/src/jl-graphic/core/index.ts b/src/jl-graphic/core/index.ts new file mode 100644 index 0000000..742c1e9 --- /dev/null +++ b/src/jl-graphic/core/index.ts @@ -0,0 +1,4 @@ +export * from './JlGraphic'; +export * from './IdGenerator'; +export * from './GraphicRelation'; +export * from './GraphicStore'; diff --git a/src/jl-graphic/global.d.ts b/src/jl-graphic/global.d.ts new file mode 100644 index 0000000..a70a5f9 --- /dev/null +++ b/src/jl-graphic/global.d.ts @@ -0,0 +1,158 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +declare namespace GlobalMixins { + type JlCanvasType = import('./app').JlCanvas; + type CanvasProperties = import('./app').ICanvasProperties; + type GraphicApp = import('./app').GraphicApp; + type JlGraphicType = import('./core').JlGraphic; + type GraphicData = import('./core').GraphicData; + type GraphicState = import('./core').GraphicState; + type GraphicTransform = import('./core').GraphicTransform; + type GraphicTransformEvent = import('./plugins').GraphicTransformEvent; + type BoundsGraphic = import('./plugins').BoundsGraphic; + type IPointDataType = import('pixi.js').IPointData; + type PointType = import('pixi.js').Point; + type FederatedMouseEvent = import('pixi.js').FederatedMouseEvent; + type DisplayObjectType = import('pixi.js').DisplayObject; + type ContainerType = import('pixi.js').Container; + interface DisplayObjectEvents { + 'enter-absorbable-area': [number | undefined, number | undefined]; + 'out-absorbable-area': [number | undefined, number | undefined]; + dataupdate: [newVal: any, oldVal: any]; + stateupdate: [newVal: any, oldVal: any]; + repaint: [DisplayObjectType]; + transformstart: [e: GraphicTransformEvent]; + transforming: [e: GraphicTransformEvent]; + transformend: [e: GraphicTransformEvent]; + _rightclick: [e: FederatedMouseEvent]; + _leftclick: [e: FederatedMouseEvent]; + selected: [DisplayObjectType]; + unselected: [DisplayObjectType]; + childselected: [DisplayObjectType]; + childunselected: [DisplayObjectType]; + } + + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface GraphicAppEvents { + // propertiesupdate: [selectedData: GraphicData | CanvasProperties | null]; + } + + interface DisplayObject { + _selectable: boolean; + _selected: boolean; + selectable: boolean; //是否可选中 + selected: boolean; // 是否选中 + _childEdit: boolean; // 子元素编辑模式 + childEdit: boolean; + _transformSave: boolean; // 变换是否保存 + transformSave: boolean; // + _assistantAppendMap: Map | null; // 辅助附加图形map + assistantAppendMap: Map; + _draggable: boolean; // 是否可拖拽 + draggable: boolean; + _shiftStartPoint: PointType | null; // 位移起始坐标 + shiftStartPoint: PointType | null; + _shiftLastPoint: PointType | null; // 位移上一个事件时坐标 + shiftLastPoint: PointType | null; + _scalable: boolean; // 是否可缩放 + scalable: boolean; + _keepAspectRatio: boolean; // 缩放是否保持纵横比,默认保持 + keepAspectRatio: boolean; + _rotatable: boolean; // 是否可旋转 + rotatable: boolean; + worldAngle: number; // 世界角度,(-180, 180] + /** + * 获取所有父级元素叠加缩放 + */ + getAllParentScaled(): PointType; + /** + * 获取位置在画布的坐标 + */ + getPositionOnCanvas(): PointType; + /** + * 通过画布坐标更新位置 + * @param p 画布坐标 + */ + updatePositionByCanvasPosition(p: IPointData): void; + /** + * 保存变换数据 + */ + saveTransform(): GraphicTransform; + /** + * 加载变换 + * @param transform 变换数据 + */ + loadTransform(transform: GraphicTransform): void; + isChild(obj: DisplayObject): boolean; // 是否子元素 + isParent(obj: DisplayObject): boolean; // 是否父元素 + isAssistantAppend(): boolean; // 是否辅助附加图形 + addAssistantAppend(...appends: D[]): void; + removeAssistantAppend(...appends: DisplayObjectType[]): void; + removeAssistantAppendByName(...names: string[]): void; + removeAllAssistantAppend(): void; + getAssistantAppend( + name: string + ): D | undefined; // 获取辅助附加图形对象 + isGraphic(): boolean; // 是否业务图形对象 + getGraphic(): G | null; // 获取所属的图形对象 + isGraphicChild(): boolean; // 是否图形子元素 + onAddToCanvas(): void; // 添加到画布处理 + onRemoveFromCanvas(): void; //从画布移除处理 + isInCanvas(): boolean; // 是否添加到画布中 + getCanvas(): JlCanvasType; // 获取所在画布 + isCanvas(): boolean; // 是否画布对象 + getViewport(): Viewport; // 获取视口 + getGraphicApp(): GraphicApp; // 获取图形app + /** + * 图形本地坐标转为画布坐标 + * @param p 图形本地坐标 + */ + localToCanvasPoint(p: IPointData): PointType; + /** + * 批量转换图形本地坐标为画布坐标 + * @param points 图形本地坐标 + */ + localToCanvasPoints(...points: IPointData[]): PointType[]; + /** + * 画布坐标转为图形本地坐标 + * @param p 画布坐标 + */ + canvasToLocalPoint(p: IPointData): PointType; + /** + * 批量转换画布坐标为图形本地坐标 + * @param points 画布坐标 + */ + canvasToLocalPoints(...points: IPointData[]): PointType[]; + /** + * 本地坐标转为屏幕坐标 + * @param p 本地坐标 + */ + localToScreenPoint(p: IPointData): PointType; + /** + * 批量转换本地坐标为屏幕坐标 + * @param points 本地坐标 + */ + localToScreenPoints(...points: IPointData[]): PointType[]; + /** + * 屏幕坐标转为本地坐标 + * @param p 屏幕坐标 + */ + screenToLocalPoint(p: IPointData): PointType; + /** + * 批量转换屏幕坐标为本地坐标 + * @param points 屏幕坐标 + */ + screenToLocalPoints(...points: IPointData[]): PointType[]; // 批量 + + localBoundsToCanvasPoints(): PointType[]; // 本地包围框转为多边形点坐标 + } + + interface Graphics { + drawBezierCurve( + p1: IPointData, + p2: IPointData, + cp1: IPointData, + cp2: IPointData, + segmentsCount: number + ): Graphics; + } +} diff --git a/src/jl-graphic/graphic/AbsorbablePosition.ts b/src/jl-graphic/graphic/AbsorbablePosition.ts new file mode 100644 index 0000000..b3a7acf --- /dev/null +++ b/src/jl-graphic/graphic/AbsorbablePosition.ts @@ -0,0 +1,252 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { + Color, + Container, + DisplayObject, + Graphics, + IPointData, + Point, +} from 'pixi.js'; +import { + calculateFootPointFromPointToLine, + calculateIntersectionPointOfCircleAndPoint, + distance, + distance2, + isLineContainOther, + linePoint, +} from '../utils'; +import { VectorGraphic, VectorGraphicUtil } from './VectorGraphic'; + +/** + * 抽象可吸附位置 + */ +export interface AbsorbablePosition extends Container { + /** + * 是否与另一个可吸附位置重叠(相似,但可能范围不同) + * @param other + */ + isOverlapping(other: AbsorbablePosition): boolean; + + /** + * 与另一个相似的吸附位置比较范围大小 + * @param other + * @returns >0此吸附范围大,<0另一个吸附范围大,=0两个吸附范围一样大 + */ + compareTo(other: AbsorbablePosition): number; + + /** + * 尝试吸附图形对象 + * @param objs 图形对象列表 + * @returns 如果吸附成功,返回true,否则false + */ + tryAbsorb(...objs: DisplayObject[]): void; +} + +/** + * 可吸附点图形参数 + */ +export const AbsorbablePointParam = { + lineWidth: 1, + lineColor: '#000000', + fillColor: '#E77E0E', + radius: 5, // 半径 +}; + +const AbsorbablePointGraphic = new Graphics(); +// AbsorbablePointGraphic.lineStyle( +// AbsorbablePointParam.lineWidth, +// AbsorbablePointParam.lineColor +// ); +AbsorbablePointGraphic.beginFill(AbsorbablePointParam.fillColor); +AbsorbablePointGraphic.drawCircle(0, 0, AbsorbablePointParam.radius); +AbsorbablePointGraphic.endFill(); + +/** + * 可吸附点 + */ +export default class AbsorbablePoint + extends Graphics + implements AbsorbablePosition, VectorGraphic +{ + _point: Point; + absorbRange: number; + scaledListenerOn = false; + + /** + * + * @param point 画布坐标 + * @param absorbRange + */ + constructor(point: IPointData, absorbRange = 10) { + super(AbsorbablePointGraphic.geometry); + this._point = new Point(point.x, point.y); + this.absorbRange = absorbRange; + this.position.copyFrom(this._point); + this.interactive; + VectorGraphicUtil.handle(this); + } + compareTo(other: AbsorbablePosition): number { + if (other instanceof AbsorbablePoint) { + return this.absorbRange - other.absorbRange; + } + throw new Error('非可吸附点'); + } + isOverlapping(other: AbsorbablePosition): boolean { + if (other instanceof AbsorbablePoint) { + return ( + this._point.equals(other._point) && + this.absorbRange === other.absorbRange + ); + } + return false; + } + tryAbsorb(...objs: DisplayObject[]): void { + for (let i = 0; i < objs.length; i++) { + const obj = objs[i]; + const canvasPosition = obj.getPositionOnCanvas(); + if ( + distance( + this._point.x, + this._point.y, + canvasPosition.x, + canvasPosition.y + ) < this.absorbRange + ) { + obj.updatePositionByCanvasPosition(this._point); + } + } + } + updateOnScaled() { + const scaled = this.getAllParentScaled(); + const scale = Math.max(scaled.x, scaled.y); + this.scale.set(1 / scale, 1 / scale); + } +} + +/** + * 可吸附线 + */ +export class AbsorbableLine extends Graphics implements AbsorbablePosition { + p1: Point; + p2: Point; + absorbRange: number; + _color = '#E77E0E'; + + /** + * + * @param p1 画布坐标 + * @param p2 画布坐标 + * @param absorbRange + */ + constructor(p1: IPointData, p2: IPointData, absorbRange = 20) { + super(); + this.p1 = new Point(p1.x, p1.y); + this.p2 = new Point(p2.x, p2.y); + this.absorbRange = absorbRange; + this.redraw(); + } + isOverlapping(other: AbsorbablePosition): boolean { + if (other instanceof AbsorbableLine) { + const contain = isLineContainOther( + { p1: this.p1, p2: this.p2 }, + { p1: other.p1, p2: other.p2 } + ); + return contain; + } + return false; + } + compareTo(other: AbsorbablePosition): number { + if (other instanceof AbsorbableLine) { + return distance2(this.p1, this.p2) - distance2(other.p1, other.p2); + } + throw new Error('非可吸附线'); + } + redraw() { + this.clear(); + this.lineStyle(1, new Color(this._color)); + this.moveTo(this.p1.x, this.p1.y); + this.lineTo(this.p2.x, this.p2.y); + } + + tryAbsorb(...objs: DisplayObject[]): void { + for (let i = 0; i < objs.length; i++) { + const obj = objs[i]; + const canvasPosition = obj.getPositionOnCanvas(); + if (linePoint(this.p1, this.p2, canvasPosition, this.absorbRange, true)) { + const fp = calculateFootPointFromPointToLine( + this.p1, + this.p2, + canvasPosition + ); + obj.updatePositionByCanvasPosition(fp); + } + } + } +} + +/** + * 可吸附圆 + */ +export class AbsorbableCircle extends Graphics implements AbsorbablePosition { + absorbRange: number; + p0: Point; + radius: number; + _color = '#E77E0E'; + + /** + * + * @param p 画布坐标 + * @param radius + * @param absorbRange + */ + constructor(p: IPointData, radius: number, absorbRange = 10) { + super(); + this.p0 = new Point(p.x, p.y); + this.radius = radius; + this.absorbRange = absorbRange; + this.redraw(); + } + isOverlapping(other: AbsorbablePosition): boolean { + if (other instanceof AbsorbableCircle) { + return this.p0.equals(other.p0) && this.radius === other.radius; + } + return false; + } + compareTo(other: AbsorbablePosition): number { + if (other instanceof AbsorbableCircle) { + return this.absorbRange - other.absorbRange; + } + throw new Error('非可吸附圆'); + } + + redraw() { + this.clear(); + this.lineStyle(1, new Color(this._color)); + this.drawCircle(this.p0.x, this.p0.y, this.radius); + } + + tryAbsorb(...objs: DisplayObject[]): void { + for (let i = 0; i < objs.length; i++) { + const obj = objs[i]; + const canvasPosition = obj.getPositionOnCanvas(); + const len = distance( + this.p0.x, + this.p0.y, + canvasPosition.x, + canvasPosition.y + ); + if ( + len > this.radius - this.absorbRange && + len < this.radius + this.absorbRange + ) { + // 吸附,计算直线与圆交点,更新对象坐标 + const p = calculateIntersectionPointOfCircleAndPoint( + this.p0, + this.radius, + canvasPosition + ); + obj.updatePositionByCanvasPosition(p); + } + } + } +} diff --git a/src/jl-graphic/graphic/DashedLine.ts b/src/jl-graphic/graphic/DashedLine.ts new file mode 100644 index 0000000..fbed07e --- /dev/null +++ b/src/jl-graphic/graphic/DashedLine.ts @@ -0,0 +1,102 @@ +import { Container, Graphics, IPointData, Point } from 'pixi.js'; +import { angleToAxisx } from '../utils'; + +export interface IDashedLineOptions { + /** + * 每小段长度,默认4 + */ + length?: number; + /** + * 起始间隔,默认0 + */ + startSpace?: number; + /** + * 间隔长度,默认4 + */ + space?: number; + /** + * 线宽,默认1 + */ + lineWidth?: number; + /** + * 线色,默认黑 + */ + color?: string; +} + +interface ICompleteDashedLineOptions extends IDashedLineOptions { + length: number; + startSpace: number; + space: number; + lineWidth: number; + color: string; +} + +const DefaultDashedLineOptions: ICompleteDashedLineOptions = { + length: 4, + startSpace: 0, + space: 4, + lineWidth: 1, + color: '#0000ff', +}; + +export class DashedLine extends Container { + p1: Point; + p2: Point; + _options: ICompleteDashedLineOptions; + constructor(p1: IPointData, p2: IPointData, options?: IDashedLineOptions) { + super(); + const config = Object.assign({}, DefaultDashedLineOptions, options); + this._options = config; + this.p1 = new Point(p1.x, p1.y); + this.p2 = new Point(p2.x, p2.y); + this.redraw(); + } + + setOptions(options: IDashedLineOptions) { + if (options.startSpace != undefined) { + this._options.startSpace = options.startSpace; + } + if (options.length != undefined) { + this._options.length = options.length; + } + if (options.space != undefined) { + this._options.space = options.space; + } + if (options.lineWidth != undefined) { + this._options.lineWidth = options.lineWidth; + } + if (options.color != undefined) { + this._options.color = options.color; + } + this.redraw(); + } + + redraw() { + this.removeChildren(); + const p1 = this.p1; + const p2 = this.p2; + const option = this._options; + const total = Math.pow( + Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2), + 0.5 + ); + let len = option.startSpace; + while (len < total) { + let dashedLen = option.length; + if (len + option.length > total) { + dashedLen = total - len; + } + const line = new Graphics(); + line.lineStyle(option.lineWidth, option.color); + line.moveTo(len, 0); + line.lineTo(len + dashedLen, 0); + this.addChild(line); + len = len + dashedLen + option.space; + } + + this.pivot.set(0, option.lineWidth / 2); + this.position.set(p1.x, p1.y); + this.angle = angleToAxisx(p1, p2); + } +} diff --git a/src/jl-graphic/graphic/DraggablePoint.ts b/src/jl-graphic/graphic/DraggablePoint.ts new file mode 100644 index 0000000..2fbcf8e --- /dev/null +++ b/src/jl-graphic/graphic/DraggablePoint.ts @@ -0,0 +1,45 @@ +import { Graphics, IPointData } from 'pixi.js'; +import { VectorGraphic, VectorGraphicUtil } from './VectorGraphic'; + +/** + * 拖拽点参数 + */ +export const DraggablePointParam = { + lineWidth: 1, + lineColor: 0x000000, + fillColor: 0xffffff, + radius: 5, // 半径 +}; + +const DraggablePointGraphic = new Graphics(); +DraggablePointGraphic.lineStyle( + DraggablePointParam.lineWidth, + DraggablePointParam.lineColor +); +DraggablePointGraphic.beginFill(DraggablePointParam.fillColor); +DraggablePointGraphic.drawCircle(0, 0, DraggablePointParam.radius); +DraggablePointGraphic.endFill(); + +/** + * 拖拽点,用于更新图形属性 + */ +export class DraggablePoint extends Graphics implements VectorGraphic { + scaledListenerOn = false; + /** + * + * @param point 画布坐标点 + */ + constructor(point: IPointData) { + super(DraggablePointGraphic.geometry); + this.position.copyFrom(point); + this.eventMode = 'static'; + this.draggable = true; + this.cursor = 'crosshair'; + VectorGraphicUtil.handle(this); + } + updateOnScaled() { + const scaled = this.getAllParentScaled(); + const scale = Math.max(scaled.x, scaled.y); + this.scale.set(1 / scale, 1 / scale); + } +} diff --git a/src/jl-graphic/graphic/VectorGraphic.ts b/src/jl-graphic/graphic/VectorGraphic.ts new file mode 100644 index 0000000..b00b385 --- /dev/null +++ b/src/jl-graphic/graphic/VectorGraphic.ts @@ -0,0 +1,44 @@ +import { DisplayObject } from 'pixi.js'; + +export interface VectorGraphic extends DisplayObject { + scaledListenerOn: boolean; + updateOnScaled(): void; +} + +export class VectorGraphicUtil { + static handle(obj: VectorGraphic): void { + const vg = obj; + const onScaleChange = function (obj: DisplayObject) { + if (vg.isParent(obj)) { + vg.updateOnScaled(); + } + }; + const registerScaleChange = function registerScaleChange( + obj: VectorGraphic + ): void { + if (!obj.scaledListenerOn) { + obj.scaledListenerOn = true; + obj.getGraphicApp().on('viewport-scaled', onScaleChange); + } + }; + const unregisterScaleChange = function unregisterScaleChange( + obj: VectorGraphic + ): void { + obj.scaledListenerOn = false; + obj.getGraphicApp().off('viewport-scaled', onScaleChange); + }; + obj.onAddToCanvas = function onAddToCanvas() { + obj.updateOnScaled(); + registerScaleChange(obj); + }; + obj.onRemoveFromCanvas = function onRemoveFromCanvas() { + unregisterScaleChange(obj); + }; + + obj.on('added', (container) => { + if (container.isInCanvas()) { + obj.onAddToCanvas(); + } + }); + } +} diff --git a/src/jl-graphic/graphic/VectorText.ts b/src/jl-graphic/graphic/VectorText.ts new file mode 100644 index 0000000..f28e031 --- /dev/null +++ b/src/jl-graphic/graphic/VectorText.ts @@ -0,0 +1,35 @@ +import { ICanvas, ITextStyle, Text, TextStyle } from 'pixi.js'; +import { VectorGraphic, VectorGraphicUtil } from '.'; + +/** + * 矢量文字.实现原理:在缩放发生变化时,更新fontSize + */ +export class VectorText extends Text implements VectorGraphic { + vectorFontSize = 8; + scaled = 1; + scaledListenerOn = false; + + constructor( + text?: string | number, + style?: Partial | TextStyle, + canvas?: ICanvas + ) { + super(text, style, canvas); + VectorGraphicUtil.handle(this); + } + + updateOnScaled() { + const scaled = this.getAllParentScaled(); + const scale = Math.max(scaled.x, scaled.y); + this.style.fontSize = this.vectorFontSize * scale; + this.scale.set(1 / scale, 1 / scale); + } + + /** + * 设置矢量文字的字体大小 + */ + setVectorFontSize(fontSize: number) { + this.vectorFontSize = fontSize; + this.style.fontSize = fontSize; + } +} diff --git a/src/jl-graphic/graphic/index.ts b/src/jl-graphic/graphic/index.ts new file mode 100644 index 0000000..726584a --- /dev/null +++ b/src/jl-graphic/graphic/index.ts @@ -0,0 +1,4 @@ +export * from './VectorGraphic'; +export * from './VectorText'; +export * from './DraggablePoint'; +export * from './AbsorbablePosition'; diff --git a/src/jl-graphic/index.ts b/src/jl-graphic/index.ts new file mode 100644 index 0000000..e64f743 --- /dev/null +++ b/src/jl-graphic/index.ts @@ -0,0 +1,7 @@ +export * from './core'; +export * from './graphic'; +export * from './app'; +export * from './operation'; +export * from './utils'; +export * from './plugins'; +export * from './message'; diff --git a/src/jl-graphic/math/Constants.ts b/src/jl-graphic/math/Constants.ts new file mode 100644 index 0000000..87393fb --- /dev/null +++ b/src/jl-graphic/math/Constants.ts @@ -0,0 +1,26 @@ +/** + * 浮点数相等判断误差值 + */ +export const epsilon = 0.00001; + +/** + * 判断浮点数是不是0 + * @param v + * @returns + */ +export function isZero(v: number) { + if (Math.abs(v) < epsilon) { + return true; + } + return false; +} + +/** + * 两浮点数是否相等 + * @param f1 + * @param f2 + * @returns + */ +export function floatEquals(f1: number, f2: number): boolean { + return isZero(f1 - f2); +} diff --git a/src/jl-graphic/math/Vector2.ts b/src/jl-graphic/math/Vector2.ts new file mode 100644 index 0000000..1894d6f --- /dev/null +++ b/src/jl-graphic/math/Vector2.ts @@ -0,0 +1,360 @@ +/* eslint-disable @typescript-eslint/no-this-alias */ + +import { epsilon } from './Constants'; + +export default class Vector2 { + constructor(values?: [number, number]) { + if (values !== undefined) { + this.xy = values; + } + } + + static from(p: { x: number; y: number }): Vector2 { + return new Vector2([p.x, p.y]); + } + + private values = new Float32Array(2); + + static readonly zero = new Vector2([0, 0]); + static readonly one = new Vector2([1, 1]); + + get x(): number { + return this.values[0]; + } + + set x(value: number) { + this.values[0] = value; + } + get y(): number { + return this.values[1]; + } + set y(value: number) { + this.values[1] = value; + } + + get xy(): [number, number] { + return [this.values[0], this.values[1]]; + } + + set xy(values: [number, number]) { + this.values[0] = values[0]; + this.values[1] = values[1]; + } + + at(index: number): number { + return this.values[index]; + } + + reset(): void { + this.x = 0; + this.y = 0; + } + + copy(dest?: Vector2): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + dest.x = this.x; + dest.y = this.y; + + return dest; + } + + negate(dest?: Vector2): Vector2 { + if (!dest) { + dest = this; + } + + dest.x = -this.x; + dest.y = -this.y; + + return dest; + } + + equals(vector: Vector2, threshold = epsilon): boolean { + if (Math.abs(this.x - vector.x) > threshold) { + return false; + } + + if (Math.abs(this.y - vector.y) > threshold) { + return false; + } + + return true; + } + + length(): number { + return Math.sqrt(this.squaredLength()); + } + + squaredLength(): number { + const x = this.x; + const y = this.y; + + return x * x + y * y; + } + + add(vector: Vector2): Vector2 { + this.x += vector.x; + this.y += vector.y; + + return this; + } + + subtract(vector: Vector2): Vector2 { + this.x -= vector.x; + this.y -= vector.y; + + return this; + } + + multiply(vector: Vector2): Vector2 { + this.x *= vector.x; + this.y *= vector.y; + + return this; + } + + divide(vector: Vector2): Vector2 { + this.x /= vector.x; + this.y /= vector.y; + + return this; + } + + scale(value: number, dest?: Vector2): Vector2 { + if (!dest) { + dest = this; + } + + dest.x *= value; + dest.y *= value; + + return dest; + } + + normalize(dest?: Vector2): Vector2 { + if (!dest) { + dest = this; + } + + let length = this.length(); + + if (length === 1) { + return this; + } + + if (length === 0) { + dest.x = 0; + dest.y = 0; + + return dest; + } + + length = 1.0 / length; + + dest.x *= length; + dest.y *= length; + + return dest; + } + + // multiplyMat2(matrix: mat2, dest?: Vector2): Vector2 { + // if (!dest) { + // dest = this; + // } + + // return matrix.multiplyVec2(this, dest); + // } + + // multiplyMat3(matrix: mat3, dest?: Vector2): Vector2 { + // if (!dest) { + // dest = this; + // } + + // return matrix.multiplyVec2(this, dest); + // } + + // static cross(vector: Vector2, vector2: Vector2, dest?: vec3): vec3 { + // if (!dest) { + // dest = new vec3(); + // } + + // const x = vector.x; + // const y = vector.y; + + // const x2 = vector2.x; + // const y2 = vector2.y; + + // const z = x * y2 - y * x2; + + // dest.x = 0; + // dest.y = 0; + // dest.z = z; + + // return dest; + // } + + /** + * 向量点乘 + * @param vector + * @param vector2 + * @returns + */ + static dot(vector: Vector2, vector2: Vector2): number { + return vector.x * vector2.x + vector.y * vector2.y; + } + /** + * 向量长度 + * @param vector + * @param vector2 + * @returns + */ + static distance(vector: Vector2, vector2: Vector2): number { + return Math.sqrt(this.squaredDistance(vector, vector2)); + } + + /** + * 向量长度平方 + * @param vector + * @param vector2 + * @returns + */ + static squaredDistance(vector: Vector2, vector2: Vector2): number { + const x = vector2.x - vector.x; + const y = vector2.y - vector.y; + + return x * x + y * y; + } + + /** + * v2->v1的方向的单位向量 + * @param v1 + * @param v2 + * @param dest + * @returns + */ + static direction(v1: Vector2, v2: Vector2, dest?: Vector2): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + const x = v1.x - v2.x; + const y = v1.y - v2.y; + + let length = Math.sqrt(x * x + y * y); + + if (length === 0) { + dest.x = 0; + dest.y = 0; + + return dest; + } + + length = 1 / length; + + dest.x = x * length; + dest.y = y * length; + + return dest; + } + + static mix( + vector: Vector2, + vector2: Vector2, + time: number, + dest?: Vector2 + ): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + const x = vector.x; + const y = vector.y; + + const x2 = vector2.x; + const y2 = vector2.y; + + dest.x = x + time * (x2 - x); + dest.y = y + time * (y2 - y); + + return dest; + } + + /** + * 向量加法 + * @param vector + * @param vector2 + * @param dest + * @returns + */ + static sum(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + dest.x = vector.x + vector2.x; + dest.y = vector.y + vector2.y; + + return dest; + } + + /** + * 向量减法 + * @param vector + * @param vector2 + * @param dest + * @returns + */ + static difference( + vector: Vector2, + vector2: Vector2, + dest?: Vector2 + ): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + dest.x = vector.x - vector2.x; + dest.y = vector.y - vector2.y; + + return dest; + } + + /** + * 向量乘法 + * @param vector + * @param vector2 + * @param dest + * @returns + */ + static product(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + dest.x = vector.x * vector2.x; + dest.y = vector.y * vector2.y; + + return dest; + } + + /** + * 向量除法 + * @param vector + * @param vector2 + * @param dest + * @returns + */ + static quotient(vector: Vector2, vector2: Vector2, dest?: Vector2): Vector2 { + if (!dest) { + dest = new Vector2(); + } + + dest.x = vector.x / vector2.x; + dest.y = vector.y / vector2.y; + + return dest; + } +} diff --git a/src/jl-graphic/math/index.ts b/src/jl-graphic/math/index.ts new file mode 100644 index 0000000..3935efe --- /dev/null +++ b/src/jl-graphic/math/index.ts @@ -0,0 +1,4 @@ +/// 向量和矩阵代码源自开源代码:https://github.com/matthiasferch/tsm + +export * from './Constants'; +export * from './Vector2'; diff --git a/src/jl-graphic/message/WsMsgBroker.ts b/src/jl-graphic/message/WsMsgBroker.ts new file mode 100644 index 0000000..52d561a --- /dev/null +++ b/src/jl-graphic/message/WsMsgBroker.ts @@ -0,0 +1,248 @@ +import { + Client as StompClient, + StompSubscription, + type Frame, + type Message, + type messageCallbackType, +} from '@stomp/stompjs'; +import type { GraphicApp } from '../app/JlGraphicApp'; +import { GraphicState } from '../core/JlGraphic'; + +export interface StompCliOption { + /** + * websocket url地址 + */ + wsUrl: string; + /** + * 认证token + */ + token?: string; + /** + * 认证失败处理 + * @returns + */ + onAuthenticationFailed?: () => void; + reconnectDelay?: number; // 重连延时,默认3秒,设置为0不重连. + heartbeatIncoming?: number; // 服务端过来的心跳间隔,默认30秒 + heartbeatOutgoing?: number; // 到服务端的心跳间隔,默认30秒 +} + +const DefaultStompOption: StompCliOption = { + wsUrl: '', + token: '', + reconnectDelay: 3000, + heartbeatIncoming: 30000, + heartbeatOutgoing: 30000, +}; + +export class StompCli { + private static client: StompClient; + private static options: StompCliOption; + private static appMsgBroker: AppWsMsgBroker[] = []; + /** + * key-订阅路径 + */ + subscriptions: Map = new Map< + string, + AppStateSubscription + >(); + private static connected = false; + static new(options: StompCliOption) { + if (StompCli.client) { + // 已经创建 + return; + } + StompCli.options = Object.assign({}, DefaultStompOption, options); + StompCli.client = new StompClient({ + brokerURL: StompCli.options.wsUrl, + connectHeaders: { + Authorization: StompCli.options.token ? StompCli.options.token : '', + }, + reconnectDelay: StompCli.options.reconnectDelay, + heartbeatIncoming: StompCli.options.heartbeatIncoming, + heartbeatOutgoing: StompCli.options.heartbeatOutgoing, + }); + + StompCli.client.onConnect = () => { + // console.log('websocket连接(重连),重新订阅', StompCli.appMsgBroker.length) + StompCli.connected = true; + StompCli.emitConnectStateChangeEvent(); + StompCli.appMsgBroker.forEach((broker) => { + broker.resubscribe(); + }); + }; + + StompCli.client.onStompError = (frame: Frame) => { + const errMsg = frame.headers['message']; + if (errMsg === '401') { + console.warn('认证失败,断开WebSocket连接'); + StompCli.close(); + if (StompCli.options.onAuthenticationFailed) { + StompCli.options.onAuthenticationFailed(); + } + } else { + console.error('收到Stomp错误消息', frame); + } + }; + + StompCli.client.onDisconnect = (frame: Frame) => { + console.log('Stomp 断开连接', frame); + StompCli.connected = false; + StompCli.emitConnectStateChangeEvent(); + }; + StompCli.client.onWebSocketClose = (evt: CloseEvent) => { + console.log('websocket 关闭', evt); + StompCli.connected = false; + StompCli.emitConnectStateChangeEvent(); + }; + // websocket错误处理 + StompCli.client.onWebSocketError = (err: Event) => { + console.log('websocket错误', err); + }; + + StompCli.client.activate(); + } + + static emitConnectStateChangeEvent() { + StompCli.appMsgBroker.forEach((broker) => { + broker.app.emit('websocket-state-change', broker.app, StompCli.connected); + }); + } + + static isConnected(): boolean { + return StompCli.client && StompCli.client.connected; + } + + static trySubscribe( + destination: string, + handler: messageCallbackType + ): StompSubscription | undefined { + if (StompCli.isConnected()) { + return StompCli.client.subscribe(destination, handler, { + id: destination, + }); + } + return undefined; + } + + static registerAppMsgBroker(broker: AppWsMsgBroker) { + StompCli.appMsgBroker.push(broker); + } + + static removeAppMsgBroker(broker: AppWsMsgBroker) { + const index = StompCli.appMsgBroker.findIndex((mb) => mb == broker); + if (index >= 0) { + StompCli.appMsgBroker.splice(index, 1); + } + } + + static hasAppMsgBroker(): boolean { + return StompCli.appMsgBroker.length > 0; + } + + /** + * 关闭websocket连接 + */ + static close() { + StompCli.connected = false; + if (StompCli.client) { + StompCli.client.deactivate(); + } + } +} + +// 状态订阅消息转换器 +export type GraphicStateMessageConvert = ( + message: Uint8Array +) => GraphicState[]; + +// 订阅消息处理器 +export type SubscriptionMessageHandle = (message: Uint8Array) => void; + +// 图形app状态订阅 +export interface AppStateSubscription { + /** + * 订阅路径 + */ + destination: string; + /** + * 图形状态消息转换 + */ + messageConverter?: GraphicStateMessageConvert; + /** + * 订阅消息处理 + */ + messageHandle?: SubscriptionMessageHandle; + /** + * 订阅成功对象,用于取消订阅 + * 非客户端使用 + */ + subscription?: StompSubscription; +} + +/** + * 图形APP的websocket消息代理 + */ +export class AppWsMsgBroker { + app: GraphicApp; + subscriptions: Map = new Map< + string, + AppStateSubscription + >(); + + constructor(app: GraphicApp) { + this.app = app; + StompCli.registerAppMsgBroker(this); + } + + subscribe(sub: AppStateSubscription) { + this.unsbuscribe(sub.destination); // 先尝试取消之前订阅 + sub.subscription = StompCli.trySubscribe( + sub.destination, + (message: Message) => { + if (sub.messageConverter) { + const graphicStates = sub.messageConverter(message.binaryBody); + this.app.handleGraphicStates(graphicStates); + } else if (sub.messageHandle) { + sub.messageHandle(message.binaryBody); + } else { + console.error( + `订阅destination:${sub.destination}没有消息处理器或图形状态消息转换器` + ); + } + } + ); + // console.log('代理订阅结果', sub.subscription) + this.subscriptions.set(sub.destination, sub); + } + + resubscribe() { + this.subscriptions.forEach((record) => { + this.subscribe(record); + }); + } + + unsbuscribe(destination: string) { + const oldSub = this.subscriptions.get(destination); + if (oldSub) { + if (oldSub.subscription && StompCli.isConnected()) { + oldSub.subscription.unsubscribe(); + } + oldSub.subscription = undefined; + } + } + + unsbuscribeAll() { + this.subscriptions.forEach((record) => { + this.unsbuscribe(record.destination); + }); + } + + /** + * 取消所有订阅,从通用Stomp客户端移除此消息代理 + */ + close() { + StompCli.removeAppMsgBroker(this); + this.unsbuscribeAll(); + } +} diff --git a/src/jl-graphic/message/index.ts b/src/jl-graphic/message/index.ts new file mode 100644 index 0000000..fddbf3f --- /dev/null +++ b/src/jl-graphic/message/index.ts @@ -0,0 +1 @@ +export * from './WsMsgBroker'; diff --git a/src/jl-graphic/operation/JlOperation.ts b/src/jl-graphic/operation/JlOperation.ts new file mode 100644 index 0000000..5673930 --- /dev/null +++ b/src/jl-graphic/operation/JlOperation.ts @@ -0,0 +1,99 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { GraphicApp } from '../app/JlGraphicApp'; +import { JlGraphic } from '../core/JlGraphic'; + +/** + * 操作 + */ +export abstract class JlOperation { + type: string; // 操作类型/名称 + app: GraphicApp; + obj?: any; // 操作对象 + data?: any; // 操作数据 + description?: string = ''; // 操作描述 + + constructor(app: GraphicApp, type: string) { + this.app = app; + this.type = type; + } + + undo1(): void { + const updates = this.undo(); + if (updates) { + this.app.updateSelected(...updates); + } + } + redo1(): void { + const updates = this.redo(); + if (updates) { + this.app.updateSelected(...updates); + } + } + + abstract undo(): JlGraphic[] | void; + abstract redo(): JlGraphic[] | void; +} + +/** + * 操作记录 + */ +export class OperationRecord { + undoStack: JlOperation[] = []; + redoStack: JlOperation[] = []; + private maxLen: number; + + constructor(maxLen = 100) { + this.maxLen = maxLen; + } + + public get hasUndo(): boolean { + return this.undoStack.length > 0; + } + + public get hasRedo(): boolean { + return this.redoStack.length > 0; + } + + setMaxLen(v: number) { + this.maxLen = v; + const len = this.undoStack.length; + if (len > v) { + const removeCount = len - v; + this.undoStack.splice(0, removeCount); + } + } + /** + * 记录 + * @param op + */ + record(op: JlOperation) { + if (this.undoStack.length >= this.maxLen) { + this.undoStack.shift(); + } + // console.log('operation record', op) + this.undoStack.push(op); + this.redoStack.splice(0, this.redoStack.length); + } + /** + * 撤销 + */ + undo() { + const op = this.undoStack.pop(); + // console.log('撤销', op); + if (op) { + op.undo1(); + this.redoStack.push(op); + } + } + /** + * 重做 + */ + redo() { + const op = this.redoStack.pop(); + // console.log('重做', op); + if (op) { + op.redo1(); + this.undoStack.push(op); + } + } +} diff --git a/src/jl-graphic/operation/index.ts b/src/jl-graphic/operation/index.ts new file mode 100644 index 0000000..0d6da94 --- /dev/null +++ b/src/jl-graphic/operation/index.ts @@ -0,0 +1 @@ +export * from './JlOperation'; diff --git a/src/jl-graphic/plugins/AnimationManager.ts b/src/jl-graphic/plugins/AnimationManager.ts new file mode 100644 index 0000000..492a7fd --- /dev/null +++ b/src/jl-graphic/plugins/AnimationManager.ts @@ -0,0 +1,75 @@ +import { GraphicApp } from '../app'; +import { GraphicAnimation, JlGraphic } from '../core'; + +/** + * 图形动画管理 + */ +export class AnimationManager { + app: GraphicApp; + graphicAnimationMap: Map>; + constructor(app: GraphicApp) { + this.app = app; + this.graphicAnimationMap = new Map>(); + // 动画控制 + app.app.ticker.add((dt: number) => { + this.graphicAnimationMap.forEach((map) => { + map.forEach((animation) => { + if (animation.running) { + animation.run(dt); + } + }); + }); + }); + } + + static new(app: GraphicApp): AnimationManager { + return new AnimationManager(app); + } + + /** + * 图形对象的所有动画map + * @param graphic + * @returns + */ + animationMap(graphic: JlGraphic): Map { + let map = this.graphicAnimationMap.get(graphic.id); + if (!map) { + map = new Map(); + this.graphicAnimationMap.set(graphic.id, map); + } + return map; + } + + /** + * 注册图形动画 + * @param graphic + * @param animation + */ + registerAnimation(graphic: JlGraphic, animation: GraphicAnimation) { + this.animationMap(graphic).set(animation.name, animation); + } + /** + * 删除图形动画 + * @param graphic + * @param name + */ + unregisterAnimation(graphic: JlGraphic, name: string) { + this.animationMap(graphic).delete(name); + } + /** + * 删除所有图形动画 + * @param graphic + */ + unregisterGraphicAnimations(graphic: JlGraphic) { + this.animationMap(graphic).clear(); + } + /** + * 获取图形指定名称动画 + * @param graphic + * @param name + * @returns + */ + animation(graphic: JlGraphic, name: string): GraphicAnimation | undefined { + return this.animationMap(graphic).get(name); + } +} diff --git a/src/jl-graphic/plugins/CommonMousePlugin.ts b/src/jl-graphic/plugins/CommonMousePlugin.ts new file mode 100644 index 0000000..b7a33f1 --- /dev/null +++ b/src/jl-graphic/plugins/CommonMousePlugin.ts @@ -0,0 +1,328 @@ +import { DisplayObject, FederatedMouseEvent, Graphics, Point } from 'pixi.js'; +import { GraphicApp, JlCanvas } from '../app'; +import { JlGraphic } from '../core'; +import { + AppDragEvent, + AppInteractionPlugin, + ViewportMovePlugin, +} from './InteractionPlugin'; + +type GraphicSelectFilter = (graphic: JlGraphic) => boolean; + +export interface IMouseToolOptions { + /** + * 是否启用框选,默认启用 + */ + boxSelect?: boolean; + /** + * 是否启用视口拖拽(默认右键),默认启用 + */ + viewportDrag?: boolean; + /** + * 是否启用鼠标滚轮缩放,默认启用 + */ + wheelZoom?: boolean; + /** + * 可选择图形过滤器 + */ + selectFilter?: GraphicSelectFilter; +} + +class CompleteMouseToolOptions implements IMouseToolOptions { + boxSelect: boolean; + viewportDrag: boolean; + wheelZoom: boolean; + selectFilter?: GraphicSelectFilter | undefined; + constructor() { + this.boxSelect = true; + this.viewportDrag = true; + this.wheelZoom = true; + } + update(options: IMouseToolOptions) { + if (options.boxSelect != undefined) { + this.boxSelect = options.boxSelect; + } + if (options.viewportDrag != undefined) { + this.viewportDrag = options.viewportDrag; + } + if (options.wheelZoom != undefined) { + this.wheelZoom = options.wheelZoom; + } + this.selectFilter = options.selectFilter; + } +} + +const DefaultSelectToolOptions: CompleteMouseToolOptions = + new CompleteMouseToolOptions(); + +/** + * 通用交互工具 + */ +export class CommonMouseTool extends AppInteractionPlugin { + static Name = 'mouse-tool'; + static SelectBox = '__select_box'; + options: CompleteMouseToolOptions; + box: Graphics; + leftDownTarget: DisplayObject | null = null; + + drag = false; + graphicSelect = false; + + rightTarget: DisplayObject | null = null; + + constructor(graphicApp: GraphicApp) { + super(CommonMouseTool.Name, graphicApp); + this.options = DefaultSelectToolOptions; + + this.box = new Graphics(); + this.box.name = CommonMouseTool.SelectBox; + this.box.visible = false; + this.app.canvas.addAssistantAppends(this.box); + + graphicApp.on('options-update', (options) => { + if (options.mouseToolOptions) { + this.options.update(options.mouseToolOptions); + if (this.isActive()) { + this.pause(); + this.resume(); + } + } + }); + } + + static new(app: GraphicApp) { + return new CommonMouseTool(app); + } + + bind(): void { + const canvas = this.app.canvas; + canvas.on('mousedown', this.onMouseDown, this); + canvas.on('mouseup', this.onMouseUp, this); + this.app.on('drag_op_start', this.onDragStart, this); + this.app.on('drag_op_move', this.onDragMove, this); + this.app.on('drag_op_end', this.onDragEnd, this); + if (this.options.viewportDrag) { + this.app.viewport.drag({ + mouseButtons: 'right', + }); + canvas.on('rightdown', this.setCursor, this); + canvas.on('rightup', this.resumeCursor, this); + canvas.on('rightupoutside', this.resumeCursor, this); + } + if (this.options.wheelZoom) { + this.app.viewport.wheel({ + percent: 0.01, + }); + } + } + unbind(): void { + const canvas = this.app.canvas; + // 确保所有事件取消监听 + canvas.off('mousedown', this.onMouseDown, this); + canvas.off('mouseup', this.onMouseUp, this); + + this.app.off('drag_op_start', this.onDragStart, this); + this.app.off('drag_op_move', this.onDragMove, this); + this.app.off('drag_op_end', this.onDragEnd, this); + + this.app.viewport.plugins.remove('drag'); + canvas.off('rightdown', this.setCursor, this); + canvas.off('rightup', this.resumeCursor, this); + canvas.off('rightupoutside', this.resumeCursor, this); + + this.app.viewport.plugins.remove('wheel'); + this.clearCache(); + } + + onDragStart(event: AppDragEvent) { + // console.log( + // 'start', + // `pointerType:${event.original.pointerType},pointerId:${event.original.pointerId},button: ${event.original.button},buttons:${event.original.buttons}` + // ); + if (this.boxSelect && event.target.isCanvas() && event.isLeftButton) { + this.box.visible = true; + this.app.interactionPlugin(ViewportMovePlugin.Name).resume(); + } + this.drag = true; + } + + onDragMove(event: AppDragEvent) { + // console.log( + // 'moving', + // `pointerType:${event.original.pointerType},pointerId:${event.original.pointerId},button: ${event.original.button},buttons:${event.original.buttons}` + // ); + if (this.boxSelect && event.target.isCanvas()) { + this.boxSelectDraw(event.start, event.end); + } + } + onDragEnd(event: AppDragEvent) { + // console.log( + // 'end', + // `pointerType:${event.original.pointerType},pointerId:${event.original.pointerId},button: ${event.original.button},buttons:${event.original.buttons}` + // ); + if (this.boxSelect && event.target.isCanvas() && event.isLeftButton) { + this.boxSelectDraw(event.start, event.end); + this.boxSelectGraphicCheck(); + this.app.interactionPlugin(ViewportMovePlugin.Name).pause(); + this.box.clear(); + this.box.visible = false; + } + } + + setCursor(e: FederatedMouseEvent) { + this.rightTarget = e.target as DisplayObject; + if (e.target instanceof JlCanvas && this.app.app.view.style) { + this.app.app.view.style.cursor = 'grab'; + } + } + + resumeCursor() { + if ( + this.rightTarget && + this.rightTarget instanceof JlCanvas && + this.app.app.view.style + ) { + this.app.app.view.style.cursor = 'inherit'; + } + this.rightTarget = null; + } + + onMouseDown(e: FederatedMouseEvent) { + this.leftDownTarget = e.target as DisplayObject; + this.graphicSelect = false; + // 图形 + const graphic = this.leftDownTarget.getGraphic(); + if (graphic) { + const app = this.app; + // console.log(this.leftDownTarget.isGraphic()); + // 图形选中 + if (!e.ctrlKey && !graphic.selected && graphic.selectable) { + app.updateSelected(graphic); + graphic.childEdit = false; + this.graphicSelect = true; + } else if (!e.ctrlKey && graphic.selected && graphic.childEdit) { + if ( + this.leftDownTarget.isGraphicChild() && + this.leftDownTarget.selectable + ) { + graphic.setChildSelected(this.leftDownTarget); + } else { + graphic.exitChildEdit(); + } + } + } + } + + /** + * 选中处理 + * @param e + */ + onMouseUp(e: FederatedMouseEvent) { + const app = this.app; + if (!this.drag) { + const target = e.target as DisplayObject; + const graphic = (e.target as DisplayObject).getGraphic(); + if ( + graphic && + graphic.selected && + !this.graphicSelect && + app.selectedGraphics.length == 1 && + target === this.leftDownTarget && + target.isGraphicChild() && + target.selectable + ) { + graphic.childEdit = true; + } + if (e.ctrlKey) { + // 多选 + if (graphic) { + if (graphic.childEdit && target === this.leftDownTarget) { + graphic.invertChildSelected(target); + } else { + graphic.invertSelected(); + app.fireSelectedChange(graphic); + } + } + } else { + // 非多选 + if (e.target instanceof JlCanvas) { + this.app.updateSelected(); + } else { + if ( + graphic && + graphic.childEdit && + app.selectedGraphics.length === 1 && + target === this.leftDownTarget + ) { + graphic.setChildSelected(target); + } + } + } + // 多个图形选中,退出子元素编辑模式 + const selecteds = this.app.selectedGraphics; + if (selecteds.length > 1) { + selecteds.forEach((g) => g.exitChildEdit()); + } + } + this.clearCache(); + } + + /** + * 清理缓存 + */ + clearCache() { + this.drag = false; + this.leftDownTarget = null; + } + + public get boxSelect(): boolean | undefined { + return this.options.boxSelect; + } + + public get selectFilter(): GraphicSelectFilter | undefined { + return this.options.selectFilter; + } + + /** + * 框选图形绘制并检查 + */ + boxSelectDraw(start: Point, end: Point): void { + if (!this.drag) return; + // 绘制框选矩形框 + this.box.clear(); + this.box.lineStyle({ width: 1, color: 0x000000 }); + const dsx = end.x - start.x; + const dsy = end.y - start.y; + let { x, y } = start; + if (dsx < 0) { + x += dsx; + } + if (dsy < 0) { + y += dsy; + } + const width = Math.abs(dsx); + const height = Math.abs(dsy); + this.box.drawRect(x, y, width, height); + } + + /** + * 框选图形判断 + * @returns + */ + boxSelectGraphicCheck(): void { + if (!this.drag) return; + // 遍历筛选 + const boxRect = this.box.getLocalBounds(); + const app = this.app; + const selects: JlGraphic[] = []; + app.queryStore.getAllGraphics().forEach((g) => { + if (!this.selectFilter || this.selectFilter(g)) { + // 选择过滤器 + if (g.boxIntersectCheck(boxRect)) { + selects.push(g); + } + } + }); + app.updateSelected(...selects); + } +} diff --git a/src/jl-graphic/plugins/CopyPlugin.ts b/src/jl-graphic/plugins/CopyPlugin.ts new file mode 100644 index 0000000..2cbc71f --- /dev/null +++ b/src/jl-graphic/plugins/CopyPlugin.ts @@ -0,0 +1,141 @@ +import { Container, FederatedPointerEvent, Point } from 'pixi.js'; +import { GraphicApp, GraphicCreateOperation } from '../app'; +import { JlGraphic } from '../core'; +import { KeyListener } from './KeyboardPlugin'; + +export class GraphicCopyPlugin { + container: Container; + app: GraphicApp; + keyListeners: KeyListener[]; + copys: JlGraphic[]; + start?: Point; + running = false; + moveLimit?: 'x' | 'y'; + constructor(app: GraphicApp) { + this.app = app; + this.container = new Container(); + this.copys = []; + this.keyListeners = []; + this.keyListeners.push( + new KeyListener({ + // ESC 用于取消复制操作 + value: 'Escape', + global: true, + // combinations: [CombinationKey.Ctrl], + onPress: () => { + this.cancle(); + }, + }), + new KeyListener({ + // X 限制只能在x轴移动 + value: 'KeyX', + global: true, + // combinations: [CombinationKey.Ctrl], + onPress: () => { + this.updateMoveLimit('x'); + }, + }), + new KeyListener({ + // Y 限制只能在y轴移动 + value: 'KeyY', + global: true, + // combinations: [CombinationKey.Ctrl], + onPress: () => { + this.updateMoveLimit('y'); + }, + }) + ); + } + + updateMoveLimit(limit?: 'x' | 'y'): void { + if (this.moveLimit === limit) { + this.moveLimit = undefined; + } else { + this.moveLimit = limit; + } + } + + init(): void { + if (this.running) return; + if (this.app.selectedGraphics.length === 0) { + throw new Error('没有选中图形,复制取消'); + } + this.running = true; + this.copys = []; + this.container.alpha = 0.5; + this.app.canvas.addChild(this.container); + const app = this.app; + this.app.selectedGraphics.forEach((g) => { + const template = app.getGraphicTemplatesByType(g.type); + const clone = template.clone(g); + this.copys.push(clone); + this.container.position.set(0, 0); + this.container.addChild(clone); + clone.repaint(); + }); + this.app.canvas.on('mousemove', this.onPointerMove, this); + this.app.canvas.on('mouseup', this.onFinish, this); + this.app.canvas.on('rightup', this.cancle, this); + this.keyListeners.forEach((kl) => { + this.app.addKeyboardListener(kl); + }); + } + + clear(): void { + this.running = false; + this.start = undefined; + this.moveLimit = undefined; + this.copys = []; + this.container.removeChildren(); + this.app.canvas.removeChild(this.container); + this.app.canvas.off('mousemove', this.onPointerMove, this); + this.app.canvas.off('mouseup', this.onFinish, this); + this.app.canvas.off('rightup', this.cancle, this); + this.keyListeners.forEach((kl) => { + this.app.removeKeyboardListener(kl); + }); + } + + onPointerMove(e: FederatedPointerEvent): void { + const cp = this.app.toCanvasCoordinates(e.global); + if (!this.start) { + this.start = cp; + } else { + if (this.moveLimit === 'x') { + const dx = cp.x - this.start.x; + this.container.position.x = dx; + this.container.position.y = 0; + } else if (this.moveLimit === 'y') { + const dy = cp.y - this.start.y; + this.container.position.x = 0; + this.container.position.y = dy; + } else { + const dx = cp.x - this.start.x; + const dy = cp.y - this.start.y; + this.container.position.x = dx; + this.container.position.y = dy; + } + } + } + + onFinish(): void { + console.log('复制确认'); + // 将图形添加到app + this.copys.forEach((g) => { + g.position.x += this.container.position.x; + g.position.y += this.container.position.y; + }); + this.app.addGraphics(...this.copys); + // 创建图形对象操作记录 + this.app.opRecord.record(new GraphicCreateOperation(this.app, this.copys)); + this.app.detectRelations(); + this.app.updateSelected(...this.copys); + this.clear(); + } + + cancle(): void { + console.log('复制操作取消'); + this.app.canvas.removeChild(this.container); + this.clear(); + } +} diff --git a/src/jl-graphic/plugins/GraphicEditPlugin.ts b/src/jl-graphic/plugins/GraphicEditPlugin.ts new file mode 100644 index 0000000..9b1cc5b --- /dev/null +++ b/src/jl-graphic/plugins/GraphicEditPlugin.ts @@ -0,0 +1,514 @@ +import { + Color, + Container, + DisplayObject, + Graphics, + IDestroyOptions, + IPointData, + Point, +} from 'pixi.js'; +import { JlGraphic } from '../core'; +import { DraggablePoint } from '../graphic'; +import { + calculateDistanceFromPointToLine, + calculateFootPointFromPointToLine, + calculateLineSegmentingPoint, + calculateMirrorPoint, + convertToBezierParams, + distance2, + linePoint, + pointPolygon, +} from '../utils'; +import { GraphicTransformEvent, ShiftData } from './GraphicTransformPlugin'; + +export abstract class GraphicEditPlugin< + DO extends DisplayObject = DisplayObject +> extends Container { + graphic: DO; + constructor(g: DO) { + super(); + this.graphic = g; + this.zIndex = 2; + this.sortableChildren = true; + this.graphic.on('transformstart', this.hideAll, this); + this.graphic.on('transformend', this.showAll, this); + this.graphic.on('repaint', this.showAll, this); + } + + destroy(options?: boolean | IDestroyOptions | undefined): void { + this.graphic.off('transformstart', this.hideAll, this); + this.graphic.off('transformend', this.showAll, this); + this.graphic.off('repaint', this.showAll, this); + super.destroy(options); + } + + abstract updateEditedPointsPosition(): void; + + hideAll() { + this.visible = false; + } + showAll() { + this.updateEditedPointsPosition(); + this.visible = true; + } +} + +export interface ILineGraphic extends JlGraphic { + get linePoints(): IPointData[]; + set linePoints(points: IPointData[]); +} + +export abstract class LineEditPlugin extends GraphicEditPlugin { + linePoints: IPointData[]; + editedPoints: DraggablePoint[] = []; + constructor(g: ILineGraphic) { + super(g); + this.linePoints = g.linePoints; + this.graphic.on('dataupdate', this.reset, this); + } + + destroy(options?: boolean | IDestroyOptions | undefined): void { + this.graphic.off('dataupdate', this.reset, this); + super.destroy(options); + } + + reset(): void { + this.linePoints = this.graphic.linePoints; + this.removeChildren(); + this.editedPoints.splice(0, this.editedPoints.length); + this.initEditPoints(); + } + + abstract initEditPoints(): void; +} + +export function getWayLineIndex( + points: IPointData[], + p: IPointData +): { start: number; end: number } { + let start = 0; + let end = 0; + let minDistance = 0; + for (let i = 1; i < points.length; i++) { + const sp = points[i - 1]; + const ep = points[i]; + let distance = calculateDistanceFromPointToLine(sp, ep, p); + distance = Math.round(distance * 100) / 100; + if (i == 1) { + minDistance = distance; + } + if (distance == minDistance) { + const minX = Math.min(sp.x, ep.x); + const maxX = Math.max(sp.x, ep.x); + const minY = Math.min(sp.y, ep.y); + const maxY = Math.max(sp.y, ep.y); + const point = calculateFootPointFromPointToLine(sp, ep, p); + if ( + point.x >= minX && + point.x <= maxX && + point.y >= minY && + point.y <= maxY + ) { + start = i - 1; + } + } + if (distance < minDistance) { + minDistance = distance; + start = i - 1; + } + } + end = start + 1; + return { start, end }; +} + +export function getWaypointRangeIndex( + points: IPointData[], + curve: boolean, + p: IPointData, + lineWidth: number +): { start: number; end: number } { + let start = 0; + let end = 0; + if (!curve) { + // 直线 + for (let i = 1; i < points.length; i++) { + const sp = points[i - 1]; + const ep = points[i]; + const fp = calculateFootPointFromPointToLine(sp, ep, p); + if (linePoint(sp, ep, fp, 1, true)) { + start = i - 1; + end = i; + break; + } + } + } else { + // 贝塞尔曲线 + const bps = convertToBezierParams(points); + for (let i = 0; i < bps.length; i++) { + const bp = bps[i]; + if (pointPolygon(p, [bp.p1, bp.cp1, bp.cp2, bp.p2], lineWidth)) { + start = i * 3; + end = start + 3; + } + } + // assertBezierPoints(points); + // for (let i = 0; i < points.length - 3; i += 3) { + // const p1 = points[i]; + // const cp1 = points[i + 1]; + // const cp2 = points[i + 2]; + // const p2 = points[i + 3]; + // if (pointPolygon(p, [p1, cp1, cp2, p2], lineWidth)) { + // start = i; + // end = i + 3; + // } + // } + } + return { start, end }; +} + +export type onEditPointCreate = ( + g: ILineGraphic, + dp: DraggablePoint, + index: number +) => void; + +export interface IEditPointOptions { + /** + * 编辑点创建处理 + */ + onEditPointCreate?: onEditPointCreate; +} + +/** + * 折线编辑(兼容线段) + */ +export class PolylineEditPlugin extends LineEditPlugin { + static Name = 'line_points_edit'; + options: IEditPointOptions; + constructor(g: ILineGraphic, options?: IEditPointOptions) { + super(g); + this.options = Object.assign({}, options); + this.name = PolylineEditPlugin.Name; + this.initEditPoints(); + } + + initEditPoints() { + const cps = this.graphic.localToCanvasPoints(...this.linePoints); + for (let i = 0; i < cps.length; i++) { + const p = cps[i]; + const dp = new DraggablePoint(p); + + dp.on('transforming', () => { + const tlp = this.graphic.canvasToLocalPoint(dp.position); + const cp = this.linePoints[i]; + cp.x = tlp.x; + cp.y = tlp.y; + this.graphic.repaint(); + }); + if (this.options.onEditPointCreate) { + this.options.onEditPointCreate(this.graphic, dp, i); + } + this.editedPoints.push(dp); + } + this.addChild(...this.editedPoints); + } + updateEditedPointsPosition() { + const cps = this.graphic.localToCanvasPoints(...this.linePoints); + if (cps.length === this.editedPoints.length) { + for (let i = 0; i < cps.length; i++) { + const cp = cps[i]; + this.editedPoints[i].position.copyFrom(cp); + } + } + } +} + +export interface BezierCurveEditPointOptions extends IEditPointOptions { + // 曲线控制点辅助连线颜色 + auxiliaryLineColor?: string; + // // 拖拽点颜色 + // pointColor?: string; + // 连接点处是否平滑(点左右控制点是否在一条直线),默认true + smooth?: boolean; + // 控制点是否完全对称(对称必平滑) + symmetry?: boolean; +} + +export interface ICompleteBezierCurveEditPointOptions + extends BezierCurveEditPointOptions { + smooth: boolean; +} + +export function addWayPoint( + graphic: ILineGraphic, + curve: boolean, + start: number, + end: number, + p: IPointData +) { + if (!curve) { + addLineWayPoint(graphic, start, end, p); + } else { + addBezierWayPoint(graphic, start, end, p); + } +} + +export function addLineWayPoint( + graphic: ILineGraphic, + start: number, + end: number, + p: IPointData +) { + const linePoints = graphic.linePoints; + const points = linePoints.slice(0, start + 1); + points.push(new Point(p.x, p.y)); + points.push(...linePoints.slice(end)); + graphic.linePoints = points; +} + +export function addPolygonSegmentingPoint( + graphic: ILineGraphic, + start: number, + end: number, + knife = 2 +) { + const linePoints = graphic.linePoints; + const points = linePoints.slice(0, start + 1); + points.push( + ...calculateLineSegmentingPoint(linePoints[start], linePoints[end], knife) + ); + points.push(...linePoints.slice(end)); + graphic.linePoints = points; +} + +function assertBezierWayPoint(i: number) { + const c = i % 3; + if (c !== 0) { + throw new Error(`i=${i}的点不是路径点`); + } +} + +export function addBezierWayPoint( + graphic: ILineGraphic, + start: number, + end: number, + p: IPointData +) { + if (start === end) { + console.error('添加贝塞尔曲线路径点开始结束点相等', start); + throw new Error('开始结束点不能一致'); + } + assertBezierWayPoint(start); + assertBezierWayPoint(end); + const linePoints = graphic.linePoints; + const points = linePoints.slice(0, start + 2); + const ap = new Point(p.x, p.y); + points.push(ap.clone(), ap.clone(), ap.clone()); + points.push(...linePoints.slice(end - 1)); + graphic.linePoints = points; +} + +export function removeWayPoint( + graphic: ILineGraphic, + curve: boolean, + i: number +) { + if (!curve) { + removeLineWayPoint(graphic, i); + } else { + removeBezierWayPoint(graphic, i); + } +} + +export function removeLineWayPoint(graphic: ILineGraphic, i: number) { + const linePoints = graphic.linePoints; + if (linePoints.length > 2) { + const points = linePoints.slice(0, i); + points.push(...linePoints.slice(i + 1)); + graphic.linePoints = points; + } +} + +export function removeBezierWayPoint(graphic: ILineGraphic, i: number) { + let points; + const linePoints = graphic.linePoints; + const c = i % 3; + if (c !== 0) { + throw new Error(`i=${i}的点${linePoints[i]}不是路径点`); + } + if (i === 0) { + // 第一个点 + if (linePoints.length > 4) { + points = linePoints.slice(3); + } else { + console.error('不能移除:剩余点数不足'); + } + } else if (i === linePoints.length - 1) { + // 最后一个点 + if (linePoints.length > 4) { + points = linePoints.slice(0, linePoints.length - 3); + } else { + console.error('无法移除:剩余点数不足'); + } + } else { + // 中间点 + points = linePoints.slice(0, i - 1); + points.push(...linePoints.slice(i + 2)); + } + if (points) { + graphic.linePoints = points; + } +} + +/** + * 清除路径点(只留端点),适用于直线和贝塞尔曲线 + * @param graphic + * @param curve + */ +export function clearWayPoint(graphic: ILineGraphic, curve: boolean) { + const linePoints = graphic.linePoints; + if (!curve) { + if (linePoints.length > 2) { + const points = linePoints.slice(0, 1); + points.push(...linePoints.slice(-1)); + graphic.linePoints = points; + } + } else { + if (linePoints.length > 4) { + const points = linePoints.slice(0, 2); + points.push(...linePoints.slice(-2)); + graphic.linePoints = points; + } + } +} + +/** + * 贝塞尔曲线编辑 + */ +export class BezierCurveEditPlugin extends LineEditPlugin { + static Name = 'bezier_curve_points_edit'; + options: ICompleteBezierCurveEditPointOptions; + // 曲线控制点辅助线 + auxiliaryLines: Graphics[] = []; + constructor(g: ILineGraphic, options?: BezierCurveEditPointOptions) { + super(g); + this.options = Object.assign({}, { smooth: true }, options); + this.name = BezierCurveEditPlugin.Name; + this.initEditPoints(); + } + + reset(): void { + this.auxiliaryLines.splice(0, this.auxiliaryLines.length); + super.reset(); + } + + initEditPoints() { + // console.log('initEditPoints'); + const cps = this.graphic.localToCanvasPoints(...this.linePoints); + for (let i = 0; i < cps.length; i++) { + const p = cps[i]; + const dp = new DraggablePoint(p); + const startOrEnd = i == 0 || i == cps.length - 1; + const c = i % 3; + if (c === 1) { + // 前一路径点的控制点 + dp.zIndex = 2; + const fp = cps[i - 1]; + const line = new Graphics(); + this.drawAuxiliaryLine(line, fp, p); + this.auxiliaryLines.push(line); + } else if (c === 2) { + // 后一路径点的控制点 + dp.zIndex = 3; + const np = cps[i + 1]; + const line = new Graphics(); + this.drawAuxiliaryLine(line, p, np); + this.auxiliaryLines.push(line); + } + dp.on('transforming', (e: GraphicTransformEvent) => { + const tlp = this.graphic.canvasToLocalPoint(dp.position); + const cp = this.linePoints[i]; + cp.x = tlp.x; + cp.y = tlp.y; + if (this.options.smooth || this.options.symmetry) { + if (c === 0 && !startOrEnd) { + const shiftData = e.getData(); + const fp = this.linePoints[i - 1]; + const np = this.linePoints[i + 1]; + fp.x = fp.x + shiftData.dx; + fp.y = fp.y + shiftData.dy; + np.x = np.x + shiftData.dx; + np.y = np.y + shiftData.dy; + } else if (c === 1 && i !== 1) { + const bp = this.linePoints[i - 1]; + const fp2 = this.linePoints[i - 2]; + let mp; + if (this.options.symmetry) { + mp = calculateMirrorPoint(bp, cp); + } else { + const distance = distance2(bp, fp2); + mp = calculateMirrorPoint(bp, cp, distance); + } + fp2.x = mp.x; + fp2.y = mp.y; + } else if (c === 2 && i !== cps.length - 2) { + const bp = this.linePoints[i + 1]; + const np2 = this.linePoints[i + 2]; + let mp; + if (this.options.symmetry) { + mp = calculateMirrorPoint(bp, cp); + } else { + const distance = distance2(bp, np2); + mp = calculateMirrorPoint(bp, cp, distance); + } + np2.x = mp.x; + np2.y = mp.y; + } + } + this.graphic.repaint(); + }); + if (this.options.onEditPointCreate) { + this.options.onEditPointCreate(this.graphic, dp, i); + } + this.editedPoints.push(dp); + if (this.auxiliaryLines.length > 0) { + this.addChild(...this.auxiliaryLines); + } + } + this.addChild(...this.editedPoints); + } + + drawAuxiliaryLine(line: Graphics, p1: IPointData, p2: IPointData) { + line.clear(); + if (this.options.auxiliaryLineColor) { + line.lineStyle(1, new Color(this.options.auxiliaryLineColor)); + } else { + line.lineStyle(1, new Color('blue')); + } + line.moveTo(p1.x, p1.y); + line.lineTo(p2.x, p2.y); + } + + updateEditedPointsPosition() { + const cps = this.graphic.localToCanvasPoints(...this.linePoints); + if (cps.length === this.editedPoints.length) { + for (let i = 0; i < cps.length; i++) { + const cp = cps[i]; + this.editedPoints[i].position.copyFrom(cp); + const c = i % 3; + const d = Math.floor(i / 3); + if (c === 1 || c === 2) { + const li = d * 2 + c - 1; + const line = this.auxiliaryLines[li]; + if (c === 1) { + const fp = cps[i - 1]; + this.drawAuxiliaryLine(line, fp, cp); + } else { + const np = cps[i + 1]; + this.drawAuxiliaryLine(line, cp, np); + } + } + } + } + } +} diff --git a/src/jl-graphic/plugins/GraphicTransformPlugin.ts b/src/jl-graphic/plugins/GraphicTransformPlugin.ts new file mode 100644 index 0000000..e80025d --- /dev/null +++ b/src/jl-graphic/plugins/GraphicTransformPlugin.ts @@ -0,0 +1,899 @@ +import { + Container, + DisplayObject, + Graphics, + IDestroyOptions, + Point, + Polygon, +} from 'pixi.js'; +import { + AppDragEvent, + InteractionPluginBase, + InteractionPluginType, + KeyListener, +} from '.'; +import { GraphicApp } from '../app'; +import { JlGraphic } from '../core'; +import { AbsorbablePosition, VectorText } from '../graphic'; +import { DraggablePoint } from '../graphic/DraggablePoint'; +import { + angleToAxisx, + calculateLineMidpoint, + convertRectangleToPolygonPoints, + distance, + recursiveChildren, +} from '../utils'; + +export class ShiftData { + /** + * 起始位置 + */ + startPosition: Point; + /** + * 上一次终点位置 + */ + lastPosition?: Point; + /** + * 当前位置 + */ + currentPosition?: Point; + constructor( + startPosition: Point, + currentPosition?: Point, + lastPosition?: Point + ) { + this.startPosition = startPosition; + this.lastPosition = lastPosition; + this.currentPosition = currentPosition; + } + static new( + startPosition: Point, + currentPosition?: Point, + lastPosition?: Point + ) { + return new ShiftData(startPosition, currentPosition, lastPosition); + } + + public get dx(): number { + if (!this.lastPosition || !this.currentPosition) { + throw new Error('错误的位移数据或阶段'); + } + return this.currentPosition.x - this.lastPosition.x; + } + + public get dy(): number { + if (!this.lastPosition || !this.currentPosition) { + throw new Error('错误的位移数据或阶段'); + } + return this.currentPosition.y - this.lastPosition.y; + } + + public get dsx(): number { + if (!this.currentPosition) { + throw new Error('错误的位移数据或阶段'); + } + return this.currentPosition.x - this.startPosition.x; + } + + public get dsy(): number { + if (!this.currentPosition) { + throw new Error('错误的位移数据或阶段'); + } + return this.currentPosition.y - this.startPosition.y; + } +} + +export class ScaleData { + start: Point; + current?: Point; + last?: Point; + constructor(start: Point, current?: Point, last?: Point) { + this.start = start; + this.current = current; + this.last = last; + } + static new(start: Point, current?: Point, last?: Point) { + return new ScaleData(start, current, last); + } +} + +export type TransformData = ShiftData | null; + +/** + * 图形平移事件 + */ +export class GraphicTransformEvent { + /** + * 图形对象 + */ + target: DisplayObject; + type: 'shift' | 'rotate' | 'scale' | 'skew'; + data: TransformData; + + constructor( + target: DisplayObject, + type: 'shift' | 'rotate' | 'scale' | 'skew', + data: TransformData + ) { + this.target = target; + this.type = type; + this.data = data; + } + + getData(): D { + return this.data as D; + } + + static shift(target: DisplayObject, data: ShiftData) { + return new GraphicTransformEvent(target, 'shift', data); + } + + static scale(target: DisplayObject) { + return new GraphicTransformEvent(target, 'scale', null); + } + + static rotate(target: DisplayObject) { + return new GraphicTransformEvent(target, 'rotate', null); + } + + static skew(target: DisplayObject) { + return new GraphicTransformEvent(target, 'skew', null); + } + + isShift(): boolean { + return this.type === 'shift'; + } + isRotate(): boolean { + return this.type === 'rotate'; + } + isScale(): boolean { + return this.type === 'scale'; + } + isSkew(): boolean { + return this.type === 'skew'; + } +} + +export class GraphicTransformPlugin extends InteractionPluginBase { + static Name = '__graphic_transform_plugin'; + + /** + * 可吸附位置列表 + */ + absorbablePositions?: AbsorbablePosition[]; + apContainer: Container; + static AbsorbablePosisiontsName = '__AbsorbablePosisionts'; + + constructor(app: GraphicApp) { + super(app, GraphicTransformPlugin.Name, InteractionPluginType.Other); + this.apContainer = new Container(); + this.apContainer.name = GraphicTransformPlugin.AbsorbablePosisiontsName; + this.app.canvas.addAssistantAppend(this.apContainer); + app.on('options-update', (options) => { + if (options.absorbablePositions) { + this.absorbablePositions = this.filterAbsorbablePositions( + options.absorbablePositions + ); + } + }); + } + + /** + * 过滤重复的吸附位置 + * @param positions + * @returns + */ + filterAbsorbablePositions( + positions: AbsorbablePosition[] + ): AbsorbablePosition[] { + const aps: AbsorbablePosition[] = []; + for (let i = 0; i < positions.length; i++) { + const ap1 = positions[i]; + let ap: AbsorbablePosition | null = ap1; + for (let j = positions.length - 1; j > i; j--) { + const ap2 = positions[j]; + if (ap.isOverlapping(ap2) && ap.compareTo(ap2) <= 0) { + ap = null; + break; + } + } + if (ap != null) { + aps.push(ap); + } + } + // console.log(positions, aps); + return aps; + } + + static new(app: GraphicApp) { + return new GraphicTransformPlugin(app); + } + + bind(): void { + this.app.on('drag_op_start', this.onDragStart, this); + this.app.on('drag_op_move', this.onDragMove, this); + this.app.on('drag_op_end', this.onDragEnd, this); + this.app.on('graphicselectedchange', this.onGraphicSelectedChange, this); + this.app.on( + 'graphicchildselectedchange', + this.onGraphicSelectedChange, + this + ); + } + unbind(): void { + this.app.off('drag_op_start', this.onDragStart, this); + this.app.off('drag_op_move', this.onDragMove, this); + this.app.off('drag_op_end', this.onDragEnd, this); + this.app.off('graphicselectedchange', this.onGraphicSelectedChange, this); + this.app.off( + 'graphicchildselectedchange', + this.onGraphicSelectedChange, + this + ); + } + + getDraggedTargets(e: AppDragEvent): DisplayObject[] { + const targets: DisplayObject[] = []; + if (e.target.isGraphicChild() && e.target.selected && e.target.draggable) { + const graphic = e.target.getGraphic() as JlGraphic; + // 图形子元素 + recursiveChildren(graphic, (child) => { + if (child.selected && child.draggable) { + targets.push(child); + } + }); + } else if ( + (e.target.isGraphic() || e.target.isGraphicChild()) && + e.target.getGraphic()?.draggable + ) { + // 图形对象 + targets.push(...this.app.selectedGraphics); + } else if (e.target.draggable) { + targets.push(e.target); + } + return targets; + } + onDragStart(e: AppDragEvent) { + if (!e.target.isCanvas() && e.isLeftButton) { + const targets: DisplayObject[] = this.getDraggedTargets(e); + if (targets.length > 0) { + targets.forEach((target) => { + target.shiftStartPoint = target.position.clone(); + target.emit( + 'transformstart', + GraphicTransformEvent.shift( + target, + ShiftData.new(target.shiftStartPoint) + ) + ); + }); + // 显示吸附图形 + if (this.absorbablePositions && this.absorbablePositions.length > 0) { + this.apContainer.removeChildren(); + this.apContainer.addChild(...this.absorbablePositions); + } + } + } + } + + onDragMove(e: AppDragEvent) { + if (!e.target.isCanvas() && e.isLeftButton) { + const targets: DisplayObject[] = this.getDraggedTargets(e); + if (targets.length > 0) { + // 处理位移 + targets.forEach((target) => { + if (target.shiftStartPoint) { + target.shiftLastPoint = target.position.clone(); + const { dx, dy } = e.toTargetShiftLen(target.parent); + target.position.set( + target.shiftStartPoint.x + dx, + target.shiftStartPoint.y + dy + ); + } + }); + // 处理吸附 + if (this.absorbablePositions) { + for (let i = 0; i < this.absorbablePositions.length; i++) { + const ap = this.absorbablePositions[i]; + ap.tryAbsorb(...targets); + } + } + // 事件发布 + targets.forEach((target) => { + if (target.shiftStartPoint && target.shiftLastPoint) { + target.emit( + 'transforming', + GraphicTransformEvent.shift( + target, + ShiftData.new( + target.shiftStartPoint, + target.position.clone(), + target.shiftLastPoint + ) + ) + ); + } + }); + } + } + } + + onDragEnd(e: AppDragEvent) { + if (!e.target.isCanvas() && e.isLeftButton) { + const targets: DisplayObject[] = this.getDraggedTargets(e); + targets.forEach((target) => { + if (target.shiftStartPoint) { + target.emit( + 'transformend', + GraphicTransformEvent.shift( + target, + ShiftData.new(target.shiftStartPoint, target.position.clone()) + ) + ); + } + target.shiftStartPoint = null; + }); + } + this.clearCache(); + } + + /** + * 清理缓存 + */ + clearCache() { + // 移除吸附图形 + this.absorbablePositions = []; + this.apContainer.removeChildren(); + } + + onGraphicSelectedChange(g: DisplayObject, selected: boolean) { + let br = g.getAssistantAppend(BoundsGraphic.Name); + if (!br) { + // 绘制辅助包围框 + br = new BoundsGraphic(g); + } + + if (selected) { + if (br) { + br.redraw(); + br.visible = true; + } + } else { + if (br) { + br.visible = false; + } + } + if (g.scalable || g.rotatable) { + // 缩放点 + let sp = g.getAssistantAppend(TransformPoints.Name); + if (!sp) { + sp = new TransformPoints(g); + } + if (selected) { + sp.update(); + sp.visible = true; + } else { + sp.visible = false; + } + } + } + + // onGraphicChildSelectedChange(child: DisplayObject, selected: boolean) { + // let br = child.getAssistantAppend(BoundsGraphic.Name); + // if (!br) { + // // 绘制辅助包围框 + // br = new BoundsGraphic(child); + // } + // if (selected) { + // br.redraw(); + // br.visible = true; + // } else { + // br.visible = false; + // } + // } +} + +/** + * 缩放、旋转辅助 + */ +export class TransformPoints extends Container { + static Name = 'transformPoints'; + static MinLength = 40; + static LeftTopName = 'lt-scale-point'; + static TopName = 't-scale-point'; + static RightTopName = 'rt-scale-point'; + static RightName = 'r-scale-point'; + static RightBottomName = 'rb-scale-point'; + static BottomName = 'b-scale-point'; + static LeftBottomName = 'lb-scale-point'; + static LeftName = 'l-scale-point'; + + static RotateName = 'rotate-point'; + obj: DisplayObject; + + ltScalePoint: DraggablePoint; + ltLocal: Point = new Point(); + tScalePoint: DraggablePoint; + tLocal: Point = new Point(); + tCanvas: Point = new Point(); + rtScalePoint: DraggablePoint; + rtLocal: Point = new Point(); + rScalePoint: DraggablePoint; + rLocal: Point = new Point(); + rbScalePoint: DraggablePoint; + rbLocal: Point = new Point(); + bScalePoint: DraggablePoint; + bLocal: Point = new Point(); + lbScalePoint: DraggablePoint; + lbLocal: Point = new Point(); + lScalePoint: DraggablePoint; + lLocal: Point = new Point(); + originScale: Point = new Point(); + scalePivot: Point = new Point(); + + /** + * 旋转拖拽点 + */ + rotatePoint: DraggablePoint; + /** + * 旋转中心坐标 + */ + rotatePivot: Point; + /** + * 起始旋转坐标 + */ + rotateLastPoint: Point; + /** + * 起始图形角度 + */ + startAngle = 0; + /** + * 当前角度信息文本辅助 + */ + angleAssistantText: VectorText; + /** + * 旋转角度步长 + */ + angleStep = 1; + /** + * 修改旋转步长键盘监听 + */ + rotateAngleStepKeyListeners: KeyListener[] = []; + + constructor(obj: DisplayObject) { + super(); + this.obj = obj; + this.name = TransformPoints.Name; + + this.angleAssistantText = new VectorText(''); + this.angleAssistantText.setVectorFontSize(16); + this.angleAssistantText.anchor.set(0.5); + + // 创建缩放拖拽点 + this.ltScalePoint = new DraggablePoint(new Point()); + this.ltScalePoint.name = TransformPoints.LeftTopName; + this.addChild(this.ltScalePoint); + this.tScalePoint = new DraggablePoint(new Point()); + this.tScalePoint.name = TransformPoints.TopName; + this.addChild(this.tScalePoint); + this.rtScalePoint = new DraggablePoint(new Point()); + this.rtScalePoint.name = TransformPoints.RightTopName; + this.addChild(this.rtScalePoint); + this.rScalePoint = new DraggablePoint(new Point()); + this.rScalePoint.name = TransformPoints.RightName; + this.addChild(this.rScalePoint); + this.rbScalePoint = new DraggablePoint(new Point()); + this.rbScalePoint.name = TransformPoints.RightBottomName; + this.addChild(this.rbScalePoint); + this.bScalePoint = new DraggablePoint(new Point()); + this.bScalePoint.name = TransformPoints.BottomName; + this.addChild(this.bScalePoint); + this.lbScalePoint = new DraggablePoint(new Point()); + this.lbScalePoint.name = TransformPoints.LeftBottomName; + this.addChild(this.lbScalePoint); + this.lScalePoint = new DraggablePoint(new Point()); + this.lScalePoint.name = TransformPoints.LeftName; + this.addChild(this.lScalePoint); + this.obj.on('transformstart', this.onObjTransformStart, this); + this.obj.on('transformend', this.onObjTransformEnd, this); + + if (this.obj.children && this.obj.children.length > 0) { + recursiveChildren(this.obj as Container, (child) => { + child.on('transformstart', this.onObjTransformStart, this); + child.on('transformend', this.onObjTransformEnd, this); + }); + } + const pg = this.obj.getGraphic(); + if (pg != null) { + pg.on('transformstart', this.onObjTransformStart, this); + pg.on('transformend', this.onObjTransformEnd, this); + } + + this.obj.on('repaint', this.onGraphicRepaint, this); + this.children.forEach((dp) => { + dp.on('transformstart', this.onScaleDragStart, this); + dp.on('transforming', this.onScaleDragMove, this); + dp.on('transformend', this.onScaleDragEnd, this); + }); + + // 创建旋转拖拽点 + this.rotatePoint = new DraggablePoint(new Point()); + this.addChild(this.rotatePoint); + this.rotatePoint.on('transformstart', this.onRotateStart, this); + this.rotatePoint.on('transforming', this.onRotateMove, this); + this.rotatePoint.on('transformend', this.onRotateEnd, this); + this.rotatePivot = new Point(); + this.rotateLastPoint = new Point(); + // 初始化旋转角度修改键盘监听器 + for (let i = 1; i < 10; i++) { + this.rotateAngleStepKeyListeners.push( + KeyListener.create({ + value: '' + i, + onPress: () => { + // console.log('修改角度step'); + this.angleStep = i; + }, + }) + ); + } + + this.obj.addAssistantAppend(this); + } + + onObjTransformStart() { + this.visible = false; + } + onObjTransformEnd() { + this.update(); + this.visible = true; + } + onGraphicRepaint() { + if (this.visible) { + this.update(); + } + } + + /** + * 旋转开始 + * @param de + */ + onRotateStart(de: GraphicTransformEvent) { + this.hideAll(); + const assistantPoint = this.obj.localToCanvasPoint(this.obj.pivot); + this.rotatePivot.copyFrom(assistantPoint); + this.rotateLastPoint.copyFrom(de.target.position); + this.startAngle = this.obj.angle; + const app = this.obj.getGraphicApp(); + this.rotateAngleStepKeyListeners.forEach((listener) => + app.addKeyboardListener(listener) + ); + this.obj.emit('transformstart', GraphicTransformEvent.rotate(this.obj)); + // app.emit('transformstart', app.selectedGraphics); + this.obj.getCanvas().addAssistantAppends(this.angleAssistantText); + this.updateAngleAssistantText(de); + } + updateAngleAssistantText(de: GraphicTransformEvent) { + this.angleAssistantText.text = this.obj.angle + '°'; + let cursorPoint = de.data?.startPosition; + if (de.data?.currentPosition) { + cursorPoint = de.data?.currentPosition; + } + if (cursorPoint) { + this.angleAssistantText.position.x = cursorPoint.x; + this.angleAssistantText.position.y = cursorPoint.y - 10; + } + } + /** + * 旋转移动 + * @param de + */ + onRotateMove(de: GraphicTransformEvent) { + // 旋转角度计算逻辑:取锚点y负方向一点作为旋转点,求旋转点和锚点所形成的直线与x轴角度,此角度+90°即为最终旋转角度,再将旋转角度限制到(-180,180]之间 + let angle = angleToAxisx(this.rotatePivot, de.target.position); + angle = Math.floor(angle / this.angleStep) * this.angleStep; + const parentAngle = this.obj.parent.worldAngle; + angle = (angle + 90 - parentAngle) % 360; + if (angle > 180) { + angle = angle - 360; + } + this.obj.angle = angle; + this.updateAngleAssistantText(de); + // this.obj.emit('rotatemove', this.obj); + } + /** + * 旋转结束 + * @param de + */ + onRotateEnd() { + this.showAll(); + this.obj.getCanvas().removeAssistantAppends(this.angleAssistantText); + this.rotateAngleStepKeyListeners.forEach((listener) => + this.obj.getGraphicApp().removeKeyboardListener(listener) + ); + this.obj.emit('transformend', GraphicTransformEvent.rotate(this.obj)); + } + + /** + * 缩放开始 + */ + onScaleDragStart() { + this.hideAll(); + const points = convertRectangleToPolygonPoints(this.obj.getLocalBounds()); + const p0 = points[0]; + const p1 = points[1]; + const p2 = points[2]; + const p3 = points[3]; + this.scalePivot = this.obj.pivot.clone(); + this.ltLocal.copyFrom(p0); + this.tCanvas.copyFrom( + this.obj.localToCanvasPoint(calculateLineMidpoint(p0, p1)) + ); + this.tLocal.copyFrom(calculateLineMidpoint(p0, p1)); + this.rtLocal.copyFrom(p1); + this.rLocal.copyFrom(calculateLineMidpoint(p1, p2)); + this.rbLocal.copyFrom(p2); + this.bLocal.copyFrom(calculateLineMidpoint(p2, p3)); + this.lbLocal.copyFrom(p3); + this.lLocal.copyFrom(calculateLineMidpoint(p0, p3)); + this.originScale = this.obj.scale.clone(); + this.obj.emit('transformstart', GraphicTransformEvent.scale(this.obj)); + } + + onScaleDragMove(e: GraphicTransformEvent) { + // 缩放计算逻辑:共8个方向缩放点,根据所拖拽的方向: + // 1,计算缩放为1时的此点在拖拽开始时的位置到锚点x、y距离, + // 2,计算拖拽点的当前位置到锚点的x、y方向距离, + // PS:以上两个计算都是在local(也就是图形对象本地)坐标系, + // 用当前距离除以原始距离即为缩放比例 + const defaultScale = new Point(1, 1); + let originWidth = 0; + let originHeight = 0; + let width = 0; + let height = 0; + this.obj.scale.copyFrom(defaultScale); + const point = this.obj.toLocal( + e.target.parent.localToScreenPoint(e.target.position) + ); + if (e.target === this.ltScalePoint) { + // 左上角 + originWidth = Math.abs(this.ltLocal.x - this.scalePivot.x); + originHeight = Math.abs(this.ltLocal.y - this.scalePivot.y); + width = Math.abs(point.x - this.scalePivot.x); + height = Math.abs(point.y - this.scalePivot.y); + } else if (e.target == this.tScalePoint) { + // 上 + originHeight = Math.abs(this.tLocal.y - this.scalePivot.y); + height = Math.abs(point.y - this.scalePivot.y); + } else if (e.target == this.rtScalePoint) { + // 右上 + originWidth = Math.abs(this.rtLocal.x - this.scalePivot.x); + originHeight = Math.abs(this.rtLocal.y - this.scalePivot.y); + width = Math.abs(point.x - this.scalePivot.x); + height = Math.abs(point.y - this.scalePivot.y); + } else if (e.target == this.rScalePoint) { + // 右 + originWidth = Math.abs(this.rLocal.x - this.scalePivot.x); + width = Math.abs(point.x - this.scalePivot.x); + } else if (e.target == this.rbScalePoint) { + // 右下 + originWidth = Math.abs(this.rbLocal.x - this.scalePivot.x); + originHeight = Math.abs(this.rbLocal.y - this.scalePivot.y); + width = Math.abs(point.x - this.scalePivot.x); + height = Math.abs(point.y - this.scalePivot.y); + } else if (e.target == this.bScalePoint) { + // 下 + originHeight = Math.abs(this.bLocal.y - this.scalePivot.y); + height = Math.abs(point.y - this.scalePivot.y); + } else if (e.target == this.lbScalePoint) { + // 左下 + originWidth = Math.abs(this.lbLocal.x - this.scalePivot.x); + originHeight = Math.abs(this.lbLocal.y - this.scalePivot.y); + width = Math.abs(point.x - this.scalePivot.x); + height = Math.abs(point.y - this.scalePivot.y); + } else { + // 左 + originWidth = Math.abs(this.lLocal.x - this.scalePivot.x); + width = Math.abs(point.x - this.scalePivot.x); + } + // 计算缩放比例,并根据是否保持纵横比两种情况进行缩放处理 + const sx = originWidth == 0 ? this.originScale.x : width / originWidth; + const sy = originHeight == 0 ? this.originScale.y : height / originHeight; + // console.log(originWidth, originHeight, width, height, sx, sy); + if (this.obj.keepAspectRatio) { + let max = Math.max(sx, sy); + if (originWidth == 0) { + max = sy; + } else if (originHeight == 0) { + max = sx; + } + this.obj.scale.set(max, max); + } else { + this.obj.scale.x = sx; + this.obj.scale.y = sy; + } + } + + onScaleDragEnd() { + this.showAll(); + this.obj.emit('transformend', GraphicTransformEvent.scale(this.obj)); + } + + hideOthers(dg: DisplayObject) { + this.children.forEach((child) => { + if (child.name !== dg.name) { + child.visible = false; + } + }); + } + + hideAll() { + this.children.forEach((child) => (child.visible = false)); + } + + showAll() { + this.update(); + this.children.forEach((child) => (child.visible = true)); + } + + getObjBounds(): { width: number; height: number } { + const points = this.obj.localBoundsToCanvasPoints(); + const p0 = points[0]; + const p1 = points[1]; + const p3 = points[3]; + const width = distance(p0.x, p0.y, p1.x, p1.y); + const height = distance(p0.x, p0.y, p3.x, p3.y); + return { width, height }; + } + + /** + * 更新位置和cursor + * @returns + */ + update() { + if (this.obj.scalable) { + this.updateScalePoints(); + } + if (this.obj.rotatable) { + this.updateRotatePoint(); + } + } + + updateRotatePoint() { + const rect = this.obj.getLocalBounds(); + const lp = this.obj.pivot.clone(); + const dy = 10 / this.obj.scale.y; + lp.y = rect.y - dy; + const p = this.obj.localToCanvasPoint(lp); + this.rotatePoint.position.copyFrom(p); + } + + updateScalePoints() { + const points = this.obj.localBoundsToCanvasPoints(); + this.ltScalePoint.position.copyFrom(points[0]); + this.tScalePoint.position.copyFrom( + calculateLineMidpoint(points[0], points[1]) + ); + this.rtScalePoint.position.copyFrom(points[1]); + this.rScalePoint.position.copyFrom( + calculateLineMidpoint(points[1], points[2]) + ); + this.rbScalePoint.position.copyFrom(points[2]); + this.bScalePoint.position.copyFrom( + calculateLineMidpoint(points[2], points[3]) + ); + this.lbScalePoint.position.copyFrom(points[3]); + this.lScalePoint.position.copyFrom( + calculateLineMidpoint(points[3], points[0]) + ); + const angle = this.obj.worldAngle; + const angle360 = (360 + angle) % 360; + if ( + (angle >= -22.5 && angle <= 22.5) || + (angle360 >= 180 - 22.5 && angle360 <= 180 + 22.5) + ) { + this.ltScalePoint.cursor = 'nw-resize'; + this.tScalePoint.cursor = 'n-resize'; + this.rtScalePoint.cursor = 'ne-resize'; + this.rScalePoint.cursor = 'e-resize'; + this.rbScalePoint.cursor = 'se-resize'; + this.bScalePoint.cursor = 's-resize'; + this.lbScalePoint.cursor = 'sw-resize'; + this.lScalePoint.cursor = 'w-resize'; + } else if ( + (angle >= 22.5 && angle <= 67.5) || + (angle360 >= 180 + 22.5 && angle360 <= 180 + 67.5) + ) { + this.ltScalePoint.cursor = 'n-resize'; + this.tScalePoint.cursor = 'ne-resize'; + this.rtScalePoint.cursor = 'e-resize'; + this.rScalePoint.cursor = 'se-resize'; + this.rbScalePoint.cursor = 's-resize'; + this.bScalePoint.cursor = 'sw-resize'; + this.lbScalePoint.cursor = 'w-resize'; + this.lScalePoint.cursor = 'nw-resize'; + } else if ( + (angle >= 67.5 && angle < 112.5) || + (angle360 >= 180 + 67.5 && angle360 <= 180 + 112.5) + ) { + this.ltScalePoint.cursor = 'ne-resize'; + this.tScalePoint.cursor = 'e-resize'; + this.rtScalePoint.cursor = 'se-resize'; + this.rScalePoint.cursor = 's-resize'; + this.rbScalePoint.cursor = 'sw-resize'; + this.bScalePoint.cursor = 'w-resize'; + this.lbScalePoint.cursor = 'nw-resize'; + this.lScalePoint.cursor = 'n-resize'; + } else { + this.ltScalePoint.cursor = 'e-resize'; + this.tScalePoint.cursor = 'se-resize'; + this.rtScalePoint.cursor = 's-resize'; + this.rScalePoint.cursor = 'sw-resize'; + this.rbScalePoint.cursor = 'w-resize'; + this.bScalePoint.cursor = 'nw-resize'; + this.lbScalePoint.cursor = 'n-resize'; + this.lScalePoint.cursor = 'ne-resize'; + } + } +} + +/** + * 包围盒矩形图形,现使用外边框转画布多边形实现 + */ +export class BoundsGraphic extends Graphics { + static Name = '_BoundsRect'; + static BoundsLineStyle = { + width: 1, + color: 0x29b6f2, + alpha: 1, + }; + obj: DisplayObject; + constructor(graphic: DisplayObject) { + super(); + this.obj = graphic; + this.name = BoundsGraphic.Name; + this.visible = false; + this.obj.on('transformstart', this.onObjTransformStart, this); + this.obj.on('transformend', this.onObjTransformEnd, this); + if (this.obj.children && this.obj.children.length > 0) { + recursiveChildren(this.obj as Container, (child) => { + child.on('transformstart', this.onObjTransformStart, this); + child.on('transformend', this.onObjTransformEnd, this); + }); + } + const pg = this.obj.getGraphic(); + if (pg != null) { + pg.on('transformstart', this.onObjTransformStart, this); + pg.on('transformend', this.onObjTransformEnd, this); + } + this.obj.on('repaint', this.onGraphicRepaint, this); + graphic.addAssistantAppend(this); + } + + onObjTransformStart(): void { + this.visible = false; + } + onObjTransformEnd(): void { + this.redraw(); + this.visible = true; + } + + onGraphicRepaint(): void { + if (this.visible) { + this.redraw(); + this.visible = true; + } + } + + destroy(options?: boolean | IDestroyOptions | undefined): void { + if (this.obj.isGraphic()) { + this.obj.off('repaint', this.onGraphicRepaint, this); + } + super.destroy(options); + } + + redraw() { + this.visible = false; // 屏蔽包围框本身 + const bounds = new Polygon(this.obj.localBoundsToCanvasPoints()); + this.clear().lineStyle(BoundsGraphic.BoundsLineStyle).drawShape(bounds); + } +} diff --git a/src/jl-graphic/plugins/InteractionPlugin.ts b/src/jl-graphic/plugins/InteractionPlugin.ts new file mode 100644 index 0000000..70226d6 --- /dev/null +++ b/src/jl-graphic/plugins/InteractionPlugin.ts @@ -0,0 +1,489 @@ +import { + DisplayObject, + FederatedMouseEvent, + FederatedPointerEvent, + Point, +} from 'pixi.js'; +import { GraphicApp, IGraphicAppConfig } from '../app/JlGraphicApp'; +import { JlGraphic } from '../core/JlGraphic'; + +export enum InteractionPluginType { + App = 'app', + Graphic = 'graphic', + Other = 'other', +} + +/** + * 交互插件 + */ +export interface InteractionPlugin { + readonly _type: string; + name: string; // 唯一标识 + app: GraphicApp; + + /** + * 恢复 + */ + resume(): void; + /** + * 停止 + */ + pause(): void; + /** + * 是否生效 + */ + isActive(): boolean; + isAppPlugin(): boolean; + isOtherPlugin(): boolean; + isGraphicPlugin(): boolean; +} + +export abstract class InteractionPluginBase implements InteractionPlugin { + readonly _type: string; + name: string; // 唯一标识 + app: GraphicApp; + _pause: boolean; + + constructor(app: GraphicApp, name: string, type: string) { + this._type = type; + this.app = app; + this.name = name; + this._pause = true; + app.registerInteractionPlugin(this); + } + + /** + * 恢复 + */ + resume(): void { + this.bind(); + this._pause = false; + this.app.emit('interaction-plugin-resume', this); + } + /** + * 停止 + */ + pause(): void { + this.unbind(); + this._pause = true; + this.app.emit('interaction-plugin-pause', this); + } + + abstract bind(): void; + abstract unbind(): void; + /** + * 是否生效 + */ + isActive(): boolean { + return !this._pause; + } + isGraphicPlugin(): boolean { + return this._type === InteractionPluginType.Graphic; + } + isAppPlugin(): boolean { + return this._type === InteractionPluginType.App; + } + isOtherPlugin(): boolean { + return this._type === InteractionPluginType.Other; + } +} + +export abstract class OtherInteractionPlugin extends InteractionPluginBase { + constructor(app: GraphicApp, name: string) { + super(app, name, InteractionPluginType.Other); + } +} + +export class AppDragEvent { + app: GraphicApp; + type: 'start' | 'move' | 'end'; + target: DisplayObject; + original: FederatedPointerEvent; + start: Point; // 画布坐标 + constructor( + app: GraphicApp, + type: 'start' | 'move' | 'end', + target: DisplayObject, + original: FederatedPointerEvent, + start: Point + ) { + this.app = app; + this.type = type; + this.target = target; + this.original = original; + this.start = start; + } + + public get isMouse(): boolean { + return this.original.pointerType === 'mouse'; + } + + public get isLeftButton(): boolean { + return ( + this.isMouse && + ((this.original.button === -1 && this.original.buttons === 1) || + (this.original.button === 0 && this.original.buttons === 0)) + ); + } + + public get isRightButton(): boolean { + return ( + this.isMouse && + ((this.original.button === -1 && this.original.buttons === 2) || + (this.original.button === 2 && this.original.buttons === 0)) + ); + } + + public get isMiddleButton(): boolean { + return ( + this.isMouse && + ((this.original.button === -1 && this.original.buttons === 4) || + (this.original.button === 1 && this.original.buttons === 0)) + ); + } + + public get isTouch(): boolean { + return this.original.pointerType === 'touch'; + } + + /** + * 终点坐标(画布坐标) + */ + public get end(): Point { + return this.app.toCanvasCoordinates(this.original.global); + } + + public get dx(): number { + const move = this.original.movement; + return move.x / this.app.viewport.scaled; + } + + public get dy(): number { + const move = this.original.movement; + return move.y / this.app.viewport.scaled; + } + + public get dsx(): number { + return this.end.x - this.start.x; + } + + public get dsy(): number { + return this.end.y - this.start.y; + } + + /** + * 转换为目标对象的位移距离 + */ + toTargetShiftLen(target: DisplayObject): { dx: number; dy: number } { + const sl = target.canvasToLocalPoint(this.start); + const el = target.canvasToLocalPoint(this.end); + return { dx: el.x - sl.x, dy: el.y - sl.y }; + } +} + +/** + * 拖拽操作插件 + */ +export class DragPlugin extends OtherInteractionPlugin { + static Name = '__drag_operation_plugin'; + private threshold = 3; + target: DisplayObject | null = null; + start: Point | null = null; + startClientPoint: Point | null = null; + drag = false; + constructor(app: GraphicApp) { + super(app, DragPlugin.Name); + app.on('options-update', (options: IGraphicAppConfig) => { + if (options.threshold !== undefined) { + this.threshold = options.threshold; + } + }); + } + static new(app: GraphicApp) { + return new DragPlugin(app); + } + bind(): void { + const canvas = this.app.canvas; + canvas.on('pointerdown', this.onPointerDown, this); + } + unbind(): void { + const canvas = this.app.canvas; + canvas.off('pointerdown', this.onPointerDown, this); + canvas.off('pointerup', this.onPointerUp, this); + canvas.off('pointerupoutside', this.onPointerUp, this); + } + onPointerDown(e: FederatedPointerEvent) { + this.target = e.target as DisplayObject; + this.start = this.app.toCanvasCoordinates(e.global); + this.startClientPoint = e.global.clone(); + const canvas = this.app.canvas; + canvas.on('pointermove', this.onPointerMove, this); + canvas.on('pointerup', this.onPointerUp, this); + canvas.on('pointerupoutside', this.onPointerUp, this); + } + onPointerMove(e: FederatedPointerEvent) { + if (this.start && this.startClientPoint) { + const current = e.global; + const sgp = this.startClientPoint; + const dragStart = + Math.abs(current.x - sgp.x) > this.threshold || + Math.abs(current.y - sgp.y) > this.threshold; + if (this.target && this.start && !this.drag && dragStart) { + this.app.emit( + 'drag_op_start', + new AppDragEvent(this.app, 'start', this.target, e, this.start) + ); + this.drag = true; + } + + // drag移动处理 + if (this.target && this.drag && this.start) { + // console.log('drag move', e.movement); + this.app.emit( + 'drag_op_move', + new AppDragEvent(this.app, 'move', this.target, e, this.start) + ); + } + } + } + + onPointerUp(e: FederatedPointerEvent) { + if (this.target && this.drag && this.start) { + // console.log('drag end'); + this.app.emit( + 'drag_op_end', + new AppDragEvent(this.app, 'end', this.target, e, this.start) + ); + } else if (this.target && this.start && !this.drag) { + // this.target.emit('click', this.target); + const ade = new AppDragEvent(this.app, 'end', this.target, e, this.start); + const graphic = this.target.getGraphic(); + if (ade.isRightButton) { + this.target.emit('_rightclick', e); + if (graphic != null) { + graphic.emit('_rightclick', e); + } + } else if (ade.isLeftButton) { + this.target.emit('_leftclick', e); + if (graphic != null) { + graphic.emit('_leftclick', e); + } + } + } + const canvas = this.app.canvas; + canvas.off('mousemove', this.onPointerMove, this); + canvas.off('mouseup', this.onPointerUp, this); + canvas.off('mouseupoutside', this.onPointerUp, this); + this.clearCache(); + } + /** + * 清理缓存 + */ + clearCache() { + this.drag = false; + this.start = null; + this.startClientPoint = null; + this.target = null; + } +} + +/** + * 视口移动插件 + */ +export class ViewportMovePlugin extends OtherInteractionPlugin { + static Name = '__viewport_move_plugin'; + + static MoveInterval = 20; // 移动间隔,单位ms + static TriggerRange = 100; // 边界触发范围,单位px + static DefaultMoveSpeed = 200 / ViewportMovePlugin.MoveInterval; // 默认移动速度 + + moveHandler: NodeJS.Timeout | null = null; + moveSpeedx = 0; + moveSpeedy = 0; + + constructor(app: GraphicApp) { + super(app, ViewportMovePlugin.Name); + } + + static new(app: GraphicApp): ViewportMovePlugin { + return new ViewportMovePlugin(app); + } + pause(): void { + super.pause(); + this.stopMove(); + } + bind(): void { + this.app.canvas.on('pointermove', this.viewportMove, this); + } + + unbind(): void { + this.app.canvas.off('pointermove', this.viewportMove, this); + } + + startMove(moveSpeedx: number, moveSpeedy: number) { + this.moveSpeedx = moveSpeedx; + this.moveSpeedy = moveSpeedy; + if (this.moveHandler == null) { + const viewport = this.app.viewport; + this.moveHandler = setInterval(() => { + viewport.moveCorner( + viewport.corner.x + this.moveSpeedx, + viewport.corner.y + this.moveSpeedy + ); + }, ViewportMovePlugin.MoveInterval); + } + } + + stopMove() { + if (this.moveHandler != null) { + clearInterval(this.moveHandler); + this.moveHandler = null; + this.app.canvas.cursor = 'auto'; + } + } + + private calculateBoundaryMoveSpeed(sp: Point): { + moveSpeedx: number; + moveSpeedy: number; + } { + let moveSpeedx = 0; + let moveSpeedy = 0; + const range = ViewportMovePlugin.TriggerRange; + const viewport = this.app.viewport; + if (sp.x < range) { + moveSpeedx = this.calculateMoveSpeed(sp.x - range); + } else if (sp.x > viewport.screenWidth - range) { + moveSpeedx = this.calculateMoveSpeed(sp.x + range - viewport.screenWidth); + } else { + moveSpeedx = 0; + } + if (sp.y < range) { + moveSpeedy = this.calculateMoveSpeed(sp.y - range); + } else if (sp.y > viewport.screenHeight - range) { + moveSpeedy = this.calculateMoveSpeed( + sp.y + range - viewport.screenHeight + ); + } else { + moveSpeedy = 0; + } + return { moveSpeedx, moveSpeedy }; + } + + calculateMoveSpeed(dd: number): number { + return ( + (dd / ViewportMovePlugin.TriggerRange) * + ViewportMovePlugin.DefaultMoveSpeed + ); + } + + viewportMove(e: FederatedMouseEvent) { + const sp = e.global; + const { moveSpeedx, moveSpeedy } = this.calculateBoundaryMoveSpeed(sp); + if (moveSpeedx == 0 && moveSpeedy == 0) { + this.app.canvas.cursor = 'auto'; + this.stopMove(); + } else { + this.app.canvas.cursor = 'grab'; + this.startMove(moveSpeedx, moveSpeedy); + } + } +} + +/** + * 应用交互插件,同时只能生效一个 + */ +export abstract class AppInteractionPlugin extends InteractionPluginBase { + constructor(name: string, app: GraphicApp) { + super(app, name, InteractionPluginType.App); + } + + /** + * 恢复,app交互插件同时只能生效一个 + */ + resume(): void { + this.app.pauseAppInteractionPlugins(); + super.resume(); + } +} + +/** + * 图形交互插件,可同时生效 + */ +export abstract class GraphicInteractionPlugin + implements InteractionPlugin +{ + readonly _type = InteractionPluginType.Graphic; + app: GraphicApp; + name: string; // 唯一标识 + _pause: boolean; + constructor(name: string, app: GraphicApp) { + this.app = app; + this.name = name; + this._pause = true; + app.registerInteractionPlugin(this); + this.resume(); + // 新增的图形对象绑定 + this.app.on('graphicstored', (g) => { + if (this.isActive()) { + this.binds(this.filter(g)); + } + }); + this.app.on('graphicdeleted', (g) => { + if (this.isActive()) { + this.unbinds(this.filter(g)); + } + }); + } + + isActive(): boolean { + return !this._pause; + } + isAppPlugin(): boolean { + return false; + } + isOtherPlugin(): boolean { + return false; + } + isGraphicPlugin(): boolean { + return true; + } + + resume(): void { + const list = this.filter(...this.app.queryStore.getAllGraphics()); + this.binds(list); + this._pause = false; + this.app.emit('interaction-plugin-resume', this); + } + pause(): void { + const list = this.filter(...this.app.queryStore.getAllGraphics()); + this.unbinds(list); + this._pause = true; + this.app.emit('interaction-plugin-pause', this); + } + + /** + * 过滤需要的图形对象 + */ + abstract filter(...grahpics: JlGraphic[]): G[] | undefined; + + binds(list?: G[]): void { + if (list) { + list.forEach((g) => this.bind(g)); + } + } + unbinds(list?: G[]): void { + if (list) { + list.forEach((g) => this.unbind(g)); + } + } + /** + * 绑定图形对象的交互处理 + * @param g 图形对象 + */ + abstract bind(g: G): void; + /** + * 取消图形对象的交互处理 + * @param g 图形对象 + */ + abstract unbind(g: G): void; +} diff --git a/src/jl-graphic/plugins/KeyboardPlugin.ts b/src/jl-graphic/plugins/KeyboardPlugin.ts new file mode 100644 index 0000000..31cd104 --- /dev/null +++ b/src/jl-graphic/plugins/KeyboardPlugin.ts @@ -0,0 +1,351 @@ +import { GraphicApp } from '../app/JlGraphicApp'; + +let target: Node | undefined; + +export class GlobalKeyboardHelper { + appKeyboardPluginMap: JlGraphicAppKeyboardPlugin[] = []; + + constructor() { + window.onkeydown = (e: KeyboardEvent) => { + this.appKeyboardPluginMap.forEach((plugin) => { + const listenerMap = plugin.getKeyListener(e); + listenerMap?.forEach((listener) => { + if (listener.global) { + listener.press(e, plugin.app); + } + }); + }); + if (e.ctrlKey) { + if (e.code == 'KeyS') { + // 屏蔽全局Ctrl+S保存操作 + // console.log('屏蔽全局Ctrl+S') + return false; + } + } + if (target && target.nodeName == 'CANVAS') { + // 事件的目标是画布时,屏蔽总的键盘操作操作 + if (e.ctrlKey) { + if (e.code == 'KeyA' || e.code == 'KeyS') { + // 屏蔽Canvas上的Ctrl+A、Ctrl+S操作 + return false; + } + } + } + return true; + }; + window.onkeyup = (e: KeyboardEvent) => { + this.appKeyboardPluginMap.forEach((plugin) => { + const listenerMap = plugin.getKeyListener(e); + listenerMap?.forEach((listener) => { + if (listener.global) { + listener.release(e, plugin.app); + } + }); + }); + }; + } + + registerGAKPlugin(plugin: JlGraphicAppKeyboardPlugin) { + if (!this.appKeyboardPluginMap.find((pg) => pg == plugin)) { + this.appKeyboardPluginMap.push(plugin); + } + } + + removeGAKPlugin(plugin: JlGraphicAppKeyboardPlugin) { + const index = this.appKeyboardPluginMap.findIndex((pg) => pg == plugin); + if (index >= 0) { + this.appKeyboardPluginMap.splice(index, 1); + } + } +} + +const GlobalKeyboardPlugin = new GlobalKeyboardHelper(); + +export class JlGraphicAppKeyboardPlugin { + app: GraphicApp; + /** + * 结构为Map> + */ + keyListenerMap: Map> = new Map< + number | string, + Map + >(); // 键值监听map + keyListenerStackMap: Map = new Map< + string, + KeyListener[] + >(); // 键值监听栈(多次注册相同的监听会把之前注册的监听器入栈,移除最新的监听会从栈中弹出一个作为指定事件监听处理器) + + constructor(app: GraphicApp) { + this.app = app; + GlobalKeyboardPlugin.registerGAKPlugin(this); + const onMouseUpdateTarget = (e: MouseEvent) => { + const node = e.target as Node; + target = node; + // console.log('Mousedown Event', node.nodeName, node.nodeType, node.nodeValue) + }; + const keydownHandle = (e: KeyboardEvent) => { + console.debug(e.key, e.code, e.keyCode); + if (target && target == this.app.dom.getElementsByTagName('canvas')[0]) { + const listenerMap = this.getKeyListener(e); + listenerMap?.forEach((listener) => { + if (!listener.global) { + listener.press(e, this.app); + } + }); + } + }; + const keyupHandle = (e: KeyboardEvent) => { + if (target && target == this.app.dom.getElementsByTagName('canvas')[0]) { + const listenerMap = this.getKeyListener(e); + listenerMap?.forEach((listener) => { + if (!listener.global) { + listener.release(e, this.app); + } + }); + } + }; + + document.addEventListener('mousedown', onMouseUpdateTarget, false); + document.addEventListener('keydown', keydownHandle, false); + document.addEventListener('keyup', keyupHandle, false); + this.app.on('destroy', () => { + document.removeEventListener('mousedown', onMouseUpdateTarget, false); + document.removeEventListener('keydown', keydownHandle, false); + document.removeEventListener('keyup', keyupHandle, false); + }); + } + + private getOrInit(key: string | number): Map { + let map = this.keyListenerMap.get(key); + if (map === undefined) { + map = new Map(); + this.keyListenerMap.set(key, map); + } + return map; + } + + private getOrInitStack(key: string): KeyListener[] { + let stack = this.keyListenerStackMap.get(key); + if (stack === undefined) { + stack = []; + this.keyListenerStackMap.set(key, stack); + } + return stack; + } + + /** + * 注册按键监听,若有旧的,旧的入栈 + * @param keyListener + */ + addKeyListener(keyListener: KeyListener) { + const map = this.getOrInit(keyListener.value); + // 查询是否有旧的监听,若有入栈 + const old = map.get(keyListener.identifier); + if (old) { + const stack = this.getOrInitStack(keyListener.identifier); + stack.push(old); + } + map.set(keyListener.identifier, keyListener); + // console.log(this.getAllListenedKeys()); + } + /** + * 移除按键监听,若是当前注册的监听,尝试从栈中取出作为按键监听器,若是旧的,则同时移除栈中的监听 + * @param keyListener + */ + removeKeyListener(keyListener: KeyListener) { + keyListener.onRemove(); + const map = this.getOrInit(keyListener.value); + const old = map.get(keyListener.identifier); + map.delete(keyListener.identifier); + const stack = this.getOrInitStack(keyListener.identifier); + if (old && old === keyListener) { + // 是旧的监听 + const listener = stack.pop(); + if (listener) { + map.set(keyListener.identifier, listener); + } + } else { + // 移除栈中的 + const index = stack.findIndex((ls) => ls === keyListener); + if (index >= 0) { + stack.splice(index, 1); + } + } + // console.log(this); + } + + getKeyListenerBy(key: string | number): Map | undefined { + return this.keyListenerMap.get(key); + } + + getKeyListener(e: KeyboardEvent): Map | undefined { + return ( + this.getKeyListenerBy(e.key) || + this.getKeyListenerBy(e.code) || + this.getKeyListenerBy(e.keyCode) + ); + } + + isKeyListened(key: string | number): boolean { + return this.getOrInit(key).size > 0; + } + + /** + * 获取所有注册监听的键值(组合键) + */ + getAllListenedKeys(): string[] { + const keys: string[] = []; + this.keyListenerMap.forEach((v) => + v.forEach((_listener, ck) => keys.push(ck)) + ); + return keys; + } +} + +type KeyboardKeyHandler = (e: KeyboardEvent, app: GraphicApp) => void; + +export enum CombinationKey { + Ctrl = 'Ctrl', + Alt = 'Alt', + Shift = 'Shift', +} +export interface KeyListenerOptions { + // 具体的键值,可以是key/code/keycode(keycode已经弃用,建议优先使用key或code),例如:KeyA/(a/A)分别表示键盘A建,其中KeyA为键盘事件的code字段,a/A为键盘事件的key字段 + value: string | number; + // 组合键 + combinations?: CombinationKey[]; + // 是否监听全局,为false则只在画布为焦点时才处理 + global?: boolean; + // 按下操作处理 + onPress?: KeyboardKeyHandler; + // 按下操作是否每次触发,默认一次 + pressTriggerAsOriginalEvent?: boolean; + // 释放/抬起操作处理 + onRelease?: KeyboardKeyHandler; +} + +export interface ICompleteKeyListenerOptions { + // 具体的键值,可以是key/code/keycode(keycode已经弃用,建议优先使用key或code),例如:KeyA/(a/A)分别表示键盘A建,其中KeyA为键盘事件的code字段,a/A为键盘事件的key字段 + value: string | number; + // 组合键 + combinations: CombinationKey[]; + // 是否监听全局,为false则只在画布为焦点时才处理 + global: boolean; + // 按下操作处理 + onPress?: KeyboardKeyHandler; + pressTriggerAsOriginalEvent: boolean; + // 释放/抬起操作处理 + onRelease?: KeyboardKeyHandler; +} + +const DefaultKeyListenerOptions: ICompleteKeyListenerOptions = { + value: '', + combinations: [], + global: false, + onPress: undefined, + pressTriggerAsOriginalEvent: false, + onRelease: undefined, +}; + +export class KeyListener { + // value 支持keyCode,key,code三种值 + readonly options: ICompleteKeyListenerOptions; + private isPress = false; + + constructor(options: KeyListenerOptions) { + this.options = Object.assign({}, DefaultKeyListenerOptions, options); + } + + static create(options: KeyListenerOptions): KeyListener { + return new KeyListener(options); + } + + public get value(): string | number { + return this.options.value; + } + + public get combinations(): string[] { + return this.options.combinations; + } + + public get identifier(): string { + return this.options.combinations.join('+') + '+' + this.options.value; + } + + public get global(): boolean | undefined { + return this.options.global; + } + + public get onPress(): KeyboardKeyHandler | undefined { + return this.options.onPress; + } + + public set onPress(v: KeyboardKeyHandler | undefined) { + this.options.onPress = v; + } + + public get onRelease(): KeyboardKeyHandler | undefined { + return this.options.onRelease; + } + + public set onRelease(v: KeyboardKeyHandler | undefined) { + this.options.onRelease = v; + } + + public get pressTriggerEveryTime(): boolean { + return this.options.pressTriggerAsOriginalEvent; + } + + public set pressTriggerEveryTime(v: boolean) { + this.options.pressTriggerAsOriginalEvent = v; + } + + press(e: KeyboardEvent, app: GraphicApp): void { + if (!this.checkCombinations(e)) { + console.debug('组合键不匹配, 不执行press', e, this); + return; + } + if (this.pressTriggerEveryTime || !this.isPress) { + // console.log('Keydown: ', e, this.onPress); + this.isPress = true; + if (this.onPress) { + this.onPress(e, app); + } + } + } + /** + * 检查组合键是否匹配 + */ + checkCombinations(e: KeyboardEvent): boolean { + const cbs = this.combinations; + if (cbs.length > 0) { + if ( + ((e.altKey && cbs.includes(CombinationKey.Alt)) || + (!e.altKey && !cbs.includes(CombinationKey.Alt))) && + ((e.ctrlKey && cbs.includes(CombinationKey.Ctrl)) || + (!e.ctrlKey && !cbs.includes(CombinationKey.Ctrl))) && + ((e.shiftKey && cbs.includes(CombinationKey.Shift)) || + (!e.shiftKey && !cbs.includes(CombinationKey.Shift))) + ) { + return true; + } + } else { + return !e.altKey && !e.ctrlKey && !e.shiftKey; + } + return false; + } + + release(e: KeyboardEvent, app: GraphicApp): void { + if (this.isPress) { + // console.log('Keyup : ', e.key, e); + this.isPress = false; + if (this.onRelease) { + this.onRelease(e, app); + } + } + } + onRemove(): void { + // 重置按下状态 + this.isPress = false; + } +} diff --git a/src/jl-graphic/plugins/index.ts b/src/jl-graphic/plugins/index.ts new file mode 100644 index 0000000..75c00d9 --- /dev/null +++ b/src/jl-graphic/plugins/index.ts @@ -0,0 +1,6 @@ +export * from './InteractionPlugin'; +export * from './CommonMousePlugin'; +export * from './KeyboardPlugin'; +export * from './CopyPlugin'; +export * from './GraphicTransformPlugin'; +export * from './AnimationManager'; diff --git a/src/jl-graphic/ui/ContextMenu.ts b/src/jl-graphic/ui/ContextMenu.ts new file mode 100644 index 0000000..f69746a --- /dev/null +++ b/src/jl-graphic/ui/ContextMenu.ts @@ -0,0 +1,774 @@ +import { Color, Container, Graphics, Point, Rectangle, Text } from 'pixi.js'; +import { GraphicApp } from '../app'; +import { OutOfBound } from '../utils'; +import { + DefaultWhiteMenuOptions, + MenuCompletionItemStyle, + MenuCompletionOptions, + MenuCompletionStyleOptions, + MenuGroupOptions, + MenuItemOptions, + MenuOptions, +} from './Menu'; + +export class ContextMenuPlugin { + app: GraphicApp; + contextMenuMap: Map = new Map(); + + constructor(app: GraphicApp) { + this.app = app; + const canvas = this.app.canvas; + canvas.on('pointerdown', () => { + this.contextMenuMap.forEach((menu) => { + menu.close(); + }); + }); + } + + registerMenu(menu: ContextMenu) { + this.contextMenuMap.set(menu.menuName, menu); + menu.plugin = this; + } + + /** + * 获取视口屏幕宽度 + */ + public get screenWidth(): number { + return this.app.viewport.screenWidth; + } + + /** + * 获取视口屏幕高度 + */ + public get screenHeight(): number { + return this.app.viewport.screenHeight; + } + + /** + * 打开菜单 + * @param menu + * @param global + */ + open(menu: ContextMenu, global: Point) { + if (!menu.opened) { + menu.opened = true; + this.app.app.stage.addChild(menu); + } + // 处理超出显示范围 + const screenHeight = this.screenHeight; + const bottomY = global.y + menu.height; + + let oob = this.oob(menu, global); + const pos = global.clone(); + if (oob.right) { + pos.x = global.x - menu.width; + } + if (oob.bottom) { + const py = global.y - menu.height; + if (py > 0) { + pos.y = py; + } else { + pos.y = global.y - (bottomY - screenHeight); + } + } + // 移动后是否左上超出 + oob = this.oob(menu, pos); + if (oob.left) { + pos.x = 0; + } + if (oob.top) { + pos.y = 0; + } + menu.position.copyFrom(pos); + } + /** + * 关闭菜单 + * @param menu + */ + close(menu: ContextMenu) { + if (menu.opened) { + menu.opened = false; + this.app.app.stage.removeChild(menu); + } + } + /** + * 越界检查 + * @param menu + * @param global + * @returns + */ + oob(menu: ContextMenu, global: Point): OutOfBound { + const screenWidth = this.screenWidth; + const screenHeight = this.screenHeight; + const bound = new Rectangle(0, 0, screenWidth, screenHeight); + const menuRect = new Rectangle(global.x, global.y, menu.width, menu.height); + return OutOfBound.check(menuRect, bound); + } +} + +/** + * 上下文菜单,多级嵌套 + */ +export class ContextMenu extends Container { + _plugin?: ContextMenuPlugin; + parentMenuItem?: ContextMenuItem; + openedSubMenu?: ContextMenu; + menuOptions: MenuCompletionOptions; + opened = false; + bg: Graphics; + title?: Text; + groups: MenuGroup[]; + private padding = 5; + _active = false; // 激活状态 + timeoutCloseHandle?: NodeJS.Timeout; + + constructor(menuOptions: MenuOptions, parentMenuItem?: ContextMenuItem) { + super(); + this.menuOptions = Object.assign({}, DefaultWhiteMenuOptions, menuOptions); + this.name = this.menuOptions.name; + this.bg = new Graphics(); + this.addChild(this.bg); + this.groups = []; + this.init(); + this.parentMenuItem = parentMenuItem; + } + + static init(options: MenuOptions): ContextMenu { + return new ContextMenu(options); + } + + public get style(): MenuCompletionStyleOptions { + return this.menuOptions.style; + } + + /** + * 父级菜单 + */ + public get parentMenu(): ContextMenu | undefined { + return this.parentMenuItem?.menu; + } + + /** + * 最顶级菜单 + */ + public get rootMenu(): ContextMenu { + if (this.parentMenu) { + return this.parentMenu.rootMenu; + } + return this; + } + + /** + * 是否存在激活的菜单项 + * @returns + */ + hasActiveItem(): boolean { + for (let i = 0; i < this.groups.length; i++) { + const group = this.groups[i]; + if (group.hasActiveItem()) { + return true; + } + } + return false; + } + + public get active(): boolean { + return ( + this._active || + this.hasActiveItem() || + (this.parentMenuItem != undefined && this.parentMenuItem._active) + ); + } + + public set active(v: boolean) { + this._active = v; + this.onActiveChanged(); + } + + onActiveChanged() { + if (this.parentMenuItem) { + this.parentMenuItem.onActiveChanged(); + if (!this.active) { + this.timeoutCloseHandle = setTimeout(() => { + this.close(); + }, 500); + } else { + if (this.timeoutCloseHandle) { + clearTimeout(this.timeoutCloseHandle); + } + } + } + } + + setOptions(menuOptions: MenuOptions) { + this.menuOptions = Object.assign({}, DefaultWhiteMenuOptions, menuOptions); + this.init(); + } + + /** + * 初始化 + */ + init() { + // this.initTitle(); + this.groups = []; + const options = this.menuOptions; + let maxItemWidth = 0; + let borderHeight = 0; + options.groups.forEach((group) => { + const menuGroup = new MenuGroup(this, group); + this.groups.push(menuGroup); + borderHeight += menuGroup.totalHeight; + if (menuGroup.maxWidth > maxItemWidth) { + maxItemWidth = menuGroup.maxWidth; + } + }); + + const splitLineWidth = 1; + + const bgWidth = maxItemWidth + this.padding * 2; + const bgHeight = + borderHeight + + this.groups.length * this.padding * 2 + + (this.groups.length - 1) * splitLineWidth; + + if (options.style.border) { + this.bg.lineStyle( + options.style.borderWidth, + new Color(options.style.borderColor) + ); + } + this.bg.beginFill(new Color(options.style.backgroundColor)); + if (options.style.borderRoundRadius > 0) { + this.bg.drawRoundedRect( + 0, + 0, + bgWidth, + bgHeight, + options.style.borderRoundRadius + ); + } else { + this.bg.drawRect(0, 0, bgWidth, bgHeight); + } + this.bg.endFill(); + let groupHeight = 0; + this.bg.lineStyle(splitLineWidth, new Color(options.style.borderColor)); + for (let i = 0; i < this.groups.length; i++) { + const group = this.groups[i]; + group.updateItemBox(maxItemWidth); + group.position.set(this.padding, groupHeight + this.padding); + if (i === this.groups.length - 1) { + // 最后一个 + break; + } + const splitLineY = groupHeight + group.height + this.padding * 2; + this.bg.moveTo(0, splitLineY); + this.bg.lineTo(bgWidth, splitLineY); + groupHeight = splitLineY + splitLineWidth; + } + + this.addChild(...this.groups); + + this.eventMode = 'static'; + this.on('pointerover', () => { + this.active = true; + }); + this.on('pointerout', () => { + this.active = false; + }); + } + + initGroups() { + this.groups = []; + const options = this.menuOptions; + options.groups.forEach((group) => { + const menuGroup = new MenuGroup(this, group); + this.groups.push(menuGroup); + }); + this.addChild(...this.groups); + } + + initTitle() { + if (this.menuOptions.title) { + this.title = new Text(this.menuOptions.title, { align: 'left' }); + } + } + + updateBg() { + this.bg.clear(); + const options = this.menuOptions; + let maxItemWidth = 0; + let borderHeight = 0; + const splitLineWidth = 1; + + this.groups.forEach((menuGroup) => { + borderHeight += menuGroup.totalHeight; + if (menuGroup.maxWidth > maxItemWidth) { + maxItemWidth = menuGroup.maxWidth; + } + }); + + const bgWidth = maxItemWidth + this.padding * 2; + const bgHeight = + borderHeight + + this.groups.length * this.padding * 2 + + (this.groups.length - 1) * splitLineWidth; + + if (options.style.border) { + this.bg.lineStyle( + options.style.borderWidth, + new Color(options.style.borderColor) + ); + } + this.bg.beginFill(new Color(options.style.backgroundColor)); + if (options.style.borderRoundRadius > 0) { + this.bg.drawRoundedRect( + 0, + 0, + bgWidth, + bgHeight, + options.style.borderRoundRadius + ); + } else { + this.bg.drawRect(0, 0, bgWidth, bgHeight); + } + this.bg.endFill(); + let groupHeight = 0; + this.bg.lineStyle(splitLineWidth, new Color(options.style.borderColor)); + for (let i = 0; i < this.groups.length; i++) { + const group = this.groups[i]; + group.updateItemBox(maxItemWidth); + group.position.set(this.padding, groupHeight + this.padding); + if (i === this.groups.length - 1) { + // 最后一个 + break; + } + const splitLineY = groupHeight + group.height + this.padding * 2; + this.bg.moveTo(0, splitLineY); + this.bg.lineTo(bgWidth, splitLineY); + groupHeight = splitLineY + splitLineWidth; + } + } + + update() { + this.groups.forEach((group) => group.update()); + this.updateBg(); + } + + public get menuName(): string { + return this.menuOptions.name; + } + + public get plugin(): ContextMenuPlugin { + if (this.parentMenu) { + return this.parentMenu.plugin; + } + if (this._plugin) { + return this._plugin; + } + throw new Error(`上下文菜单name=${this.menuOptions.name}没有添加到插件中`); + } + + public set plugin(v: ContextMenuPlugin) { + this._plugin = v; + } + + /** + * 显示菜单 + */ + open(global: Point): void { + if (this.parentMenu) { + this.parentMenu.openSub(this, global); + } else { + this.update(); + this.plugin.open(this, global); + } + } + + /** + * 关闭菜单 + */ + close(): void { + if (this.openedSubMenu) { + this.openedSubMenu.close(); + this.openedSubMenu = undefined; + } + this.plugin.close(this); + } + + /** + * 打开子菜单 + * @param subMenu + * @param global + */ + private openSub(subMenu: ContextMenu, global: Point) { + if (this.openedSubMenu) { + this.openedSubMenu.close(); + } + const pos = global.clone(); + const oob = this.plugin.oob(subMenu, global); + if (oob.right) { + pos.x = this.position.x - subMenu.width + this.padding; + } + if (oob.bottom) { + pos.y = this.plugin.screenHeight - subMenu.height - this.padding; + } + this.plugin.open(subMenu, pos); + this.openedSubMenu = subMenu; + } +} + +class MenuGroup extends Container { + private gutter = 3; // 名称、快捷键、箭头文本间隙 + config: MenuGroupOptions; + menu: ContextMenu; + items: ContextMenuItem[] = []; + constructor(menu: ContextMenu, config: MenuGroupOptions) { + super(); + this.config = config; + this.menu = menu; + config.items.forEach((item) => { + this.items.push(new ContextMenuItem(menu, item)); + }); + + this.addChild(...this.items); + } + + hasActiveItem(): boolean { + for (let i = 0; i < this.items.length; i++) { + const item = this.items[i]; + if (item.active) { + return true; + } + } + return false; + } + + public get maxWidth(): number { + const maxNameWidth = this.items + .map((item) => item.nameBounds.width) + .sort((a, b) => a - b) + .reverse()[0]; + const maxShortcutWidth = this.items + .map((item) => item.shortcutKeyBounds.width) + .sort((a, b) => a - b) + .reverse()[0]; + const maxWidth = + maxNameWidth + + this.gutter + + maxShortcutWidth + + this.items[0].paddingLeft + + this.items[0].paddingRight; + return maxWidth; + } + + public get totalHeight(): number { + let total = 0; + this.items.forEach((item) => (total += item.totalHeight)); + return total; + } + + update() { + let i = 0; + this.items.forEach((item) => { + item.update(); + if (item.visible) { + item.position.y = i * item.totalHeight; + i++; + } + }); + // this.items.forEach() + // for (let i = 0; i < this.items.length; i++) { + // const item = this.items[i]; + // if (item.visible) { + // item.position.y = i * item.totalHeight; + // } + // } + } + + updateItemBox(maxItemWidth: number) { + this.items.forEach((item) => + item.updateBox(maxItemWidth, item.totalHeight) + ); + } +} + +/** + * 菜单项 + */ +class ContextMenuItem extends Container { + menu: ContextMenu; + config: MenuItemOptions; + /** + * 名称文本 + */ + nameText: Text; + /** + * 快捷键文本 + */ + shortcutKeyText?: Text; + private gutter = 3; // 名称、快捷键、箭头文本间隙 + arrowText?: Text; + box: Graphics; + subMenu?: ContextMenu; + _active = false; // 激活状态 + + constructor(menu: ContextMenu, config: MenuItemOptions) { + super(); + this.menu = menu; + this.config = config; + this.box = new Graphics(); + this.addChild(this.box); + + this.nameText = new Text(this.config.name, { + fontSize: this.fontSize, + fill: this.fontColor, + }); + this.addChild(this.nameText); + + this.initShortcutKeyText(); + this.initSubMenu(); + } + + registerEventHandler() { + this.eventMode = 'static'; + this.cursor = 'pointer'; + this.on('pointerover', () => { + this.active = true; + if (this.config.disabled) { + this.cursor = 'not-allowed'; + } else { + this.cursor = 'pointer'; + } + if (this.subMenu) { + const p = this.toGlobal(new Point(this.width)); + this.subMenu.open(p); + } + }); + this.on('pointerout', () => { + this.active = false; + }); + this.on('pointertap', () => { + if (this.config.disabled) { + // 禁用,不处理 + return; + } + if (this.config.handler) { + this.menu.plugin.app.emit('pre-menu-handle', this.config); + this.config.handler(); + this.menu.plugin.app.emit('post-menu-handle', this.config); + } + if (!this.config.subMenu || this.config.subMenu.length === 0) { + this.active = false; + this.menu.active = false; + this.menu.rootMenu.close(); + } + }); + } + + public get active(): boolean { + return this._active || (this.subMenu != undefined && this.subMenu.active); + } + + public set active(v: boolean) { + this._active = v; + if (this.subMenu) { + this.subMenu.onActiveChanged(); + } + this.onActiveChanged(); + } + + onActiveChanged() { + if (this.active) { + this.box.alpha = 1; + } else { + this.box.alpha = 0; + } + } + + public get textWidth(): number { + return this.nameBounds.width + this.shortcutKeyBounds.width + this.gutter; + } + + public get nameGraphic(): Text { + if (this.nameText) { + return this.nameText; + } + throw new Error(`菜单项name=${this.config.name}没有初始化名称图形对象`); + } + + public get totalHeight(): number { + if (this.config.visible === false) { + return 0; + } else { + return this.paddingTop + this.paddingBottom + this.nameGraphic.height; + } + } + + public get nameBounds(): Rectangle { + return this.nameGraphic.getLocalBounds(); + } + + public get shortcutKeyBounds(): Rectangle { + if (this.shortcutKeyText) { + return this.shortcutKeyText.getLocalBounds(); + } else { + return new Rectangle(0, 0, 0, 0); + } + } + + public get style(): MenuCompletionItemStyle { + return this.menu.style.itemStyle; + } + + private checkPadding(padding: number | number[]) { + if (Array.isArray(padding)) { + if (padding.length !== 2 && padding.length !== 4) { + throw new Error('错误的padding数据'); + } + } + } + + private toWholePadding(padding: number | number[]): number[] { + this.checkPadding(padding); + if (Array.isArray(padding)) { + if (padding.length == 2) { + return [padding[0], padding[1], padding[0], padding[1]]; + } else { + return padding; + } + } else { + return [padding, padding, padding, padding]; + } + } + + public get paddingTop(): number { + return this.toWholePadding(this.menu.style.itemStyle.padding)[0]; + } + public get paddingBottom(): number { + return this.toWholePadding(this.menu.style.itemStyle.padding)[2]; + } + public get paddingLeft(): number { + return this.toWholePadding(this.menu.style.itemStyle.padding)[3]; + } + public get paddingRight(): number { + return this.toWholePadding(this.menu.style.itemStyle.padding)[1]; + } + + public get hoverColor(): string { + return this.style.hoverColor; + } + + public get fontSize(): number { + return this.style.fontSize; + } + + public get fontColor(): string { + if (this.config.disabled) { + return this.style.disabledFontColor; + } else if (this.config.fontColor) { + return this.config.fontColor; + } + return this.style.fontColor; + } + + initShortcutKeyText(): Text | undefined { + if (this.config.shortcutKeys && this.config.shortcutKeys.length > 0) { + this.shortcutKeyText = new Text(this.config.shortcutKeys.join('+'), { + fontSize: this.fontSize, + fill: this.fontColor, + }); + this.addChild(this.shortcutKeyText); + return this.shortcutKeyText; + } + return undefined; + } + + initSubMenu() { + if (this.config.subMenu && this.config.subMenu.length > 0) { + this.arrowText = new Text('>', { + fontSize: this.fontSize, + fill: this.fontColor, + }); + this.addChild(this.arrowText); + this.subMenu = new ContextMenu( + { + name: `${this.config.name}子菜单`, + groups: this.config.subMenu, + style: this.menu.style, + }, + this + ); + } + } + + updateBackground(width: number, height: number) { + this.box.clear(); + const box = this.box; + const style = this.menu.style; + if (!style.itemStyle.hoverColor) { + throw new Error('未设置菜单项的hoverColor'); + } + let hoverColor = style.itemStyle.hoverColor; + if (this.style && this.style.hoverColor) { + hoverColor = this.style.hoverColor; + } + box.beginFill(new Color(hoverColor)); + if (style.borderRoundRadius > 0) { + box.drawRoundedRect(0, 0, width, height, style.borderRoundRadius); + } else { + box.drawRect(0, 0, width, height); + } + box.endFill(); + box.alpha = 0; + } + + updateBox(width: number, height: number) { + this.removeAllListeners(); + this.updateBackground(width, height); + this.nameText?.position.set(this.paddingLeft, this.paddingTop); + if (this.shortcutKeyText) { + const skTextWidth = this.shortcutKeyBounds.width; + this.shortcutKeyText.position.set( + width - skTextWidth - this.paddingRight, + this.paddingTop + ); + } + if (this.arrowText) { + this.arrowText.position.set( + width - this.paddingRight - this.gutter, + this.paddingTop + ); + } + + // 事件监听 + this.hitArea = new Rectangle(0, 0, width, height); + this.registerEventHandler(); + } + + update() { + if (this.config.visible === false) { + this.visible = false; + return; + } + this.visible = true; + this.nameText.text = this.config.name; + this.nameText.style.fontSize = this.fontSize; + this.nameText.style.fill = this.fontColor; + + if (this.shortcutKeyText) { + if (this.config.shortcutKeys && this.config.shortcutKeys.length > 0) { + this.shortcutKeyText.text = this.config.shortcutKeys.join('+'); + this.shortcutKeyText.style.fontSize = this.fontSize; + this.shortcutKeyText.style.fill = this.fontColor; + } else { + this.shortcutKeyText.visible = false; + } + } else { + this.initShortcutKeyText(); + } + + if (this.subMenu) { + this.subMenu.update(); + } + } +} diff --git a/src/jl-graphic/ui/Menu.ts b/src/jl-graphic/ui/Menu.ts new file mode 100644 index 0000000..a500216 --- /dev/null +++ b/src/jl-graphic/ui/Menu.ts @@ -0,0 +1,177 @@ +/** + * 菜单配置项 + */ +export interface MenuOptions { + /** + * 菜单名称,需唯一 + */ + name: string; + /** + * 菜单标题 + */ + title?: string; + /** + * 菜单分组 + */ + groups: MenuGroupOptions[]; + /** + * 菜单样式 + */ + style?: MenuStyleOptions; +} +/** + * 菜单分组 + */ +export interface MenuGroupOptions { + /** + * 分组命名 + */ + name?: string; + /** + * 菜单项 + */ + items: MenuItemOptions[]; +} + +export interface MenuCompletionOptions extends MenuOptions { + style: MenuCompletionStyleOptions; +} +/** + * 菜单样式配置项 + */ +export interface MenuStyleOptions { + /** + * 菜单标题样式 + */ + titleStyle?: MenuItemStyle; + /** + * 菜单背景色 + */ + backgroundColor?: string; + /** + * 菜单边框线宽度,默认1,0为无线框 + */ + borderWidth?: number; + /** + * 菜单边框颜色 + */ + borderColor?: string; + /** + * 包围框是否圆角,圆角的半径,0为直角 + */ + borderRoundRadius?: number; + /** + * 菜单项样式 + */ + itemStyle?: MenuItemStyle; +} + +export interface MenuCompletionStyleOptions extends MenuStyleOptions { + titleStyle: MenuItemStyle; + backgroundColor: string; + border: boolean; + borderWidth: number; + borderColor: string; + borderRoundRadius: number; + itemStyle: MenuCompletionItemStyle; +} + +export interface MenuItemOptions { + /** + * 名称 + */ + name: string; + /** + * 是否禁用,默认不禁用 + */ + disabled?: boolean; + /** + * 是否显示,默认显示 + */ + visible?: boolean; + /** + * 快捷键 + */ + shortcutKeys?: string[]; + /** + * 菜单逻辑处理 + */ + handler?: () => void; + fontColor?: string; + /** + * 子菜单 + */ + subMenu?: MenuGroupOptions[]; +} + +export interface MenuItemStyle { + /** + * 字体大小 + */ + fontSize: number; + /** + * 字体颜色 + */ + fontColor?: string; + /** + * hover颜色 + */ + hoverColor?: string; + /** + * 禁用下字体颜色 + */ + disabledFontColor?: string; + /** + * 内边距 + */ + padding: number[] | number; // 内边距 +} +export interface MenuCompletionItemStyle extends MenuItemStyle { + /** + * 文字颜色 + */ + fontColor: string; + /** + * 激活颜色 + */ + hoverColor: string; + /** + * 禁用下字体颜色 + */ + disabledFontColor: string; +} + +/** + * 默认的白色样式 + */ +export const DefaultWhiteStyleOptions: MenuCompletionStyleOptions = { + titleStyle: { + fontSize: 16, + fontColor: '#000000', + padding: [5, 15], + }, + backgroundColor: '#ffffff', + border: true, + borderWidth: 1, + borderColor: '#4C4C4C', + /** + * 默认圆角 + */ + borderRoundRadius: 5, + itemStyle: { + fontSize: 16, + fontColor: '#000000', + padding: [5, 25], + hoverColor: '#1E78DB', + disabledFontColor: '#9D9D9D', + }, +}; + +/** + * 默认的白色菜单配置 + */ +export const DefaultWhiteMenuOptions: MenuCompletionOptions = { + name: '', + style: DefaultWhiteStyleOptions, + groups: [], +}; diff --git a/src/jl-graphic/utils/GraphicUtils.ts b/src/jl-graphic/utils/GraphicUtils.ts new file mode 100644 index 0000000..b8e5109 --- /dev/null +++ b/src/jl-graphic/utils/GraphicUtils.ts @@ -0,0 +1,695 @@ +import { + Container, + DisplayObject, + IPointData, + Point, + Rectangle, +} from 'pixi.js'; +import { floatEquals, isZero } from '../math'; +import Vector2 from '../math/Vector2'; + +/** + * 递归父节点执行逻辑 + * @param obj + * @param handler + */ +export function recursiveParents( + obj: DisplayObject, + handler: (parent: Container) => void +): void { + if (obj.parent) { + handler(obj.parent); + recursiveParents(obj.parent, handler); + } +} + +/** + * 递归父节点查询父节点对象 + * @param obj + * @param finder + * @returns + */ +export function recursiveFindParent( + obj: DisplayObject, + finder: (parent: Container) => boolean +): Container | null { + if (obj.parent) { + if (finder(obj.parent)) { + return obj.parent; + } else { + return recursiveFindParent(obj.parent, finder); + } + } + return null; +} + +/** + * 递归子节点执行逻辑 + * @param container + * @param handler + */ +export function recursiveChildren( + container: Container, + handler: (child: DisplayObject) => void +): void { + container.children.forEach((child) => { + handler(child); + if (child.children) { + recursiveChildren(child as Container, handler); + } + }); +} + +/** + * 递归子节点查询子节点对象 + */ +export function recursiveFindChild( + container: Container, + finder: (child: DisplayObject) => boolean +): DisplayObject | null { + let result = null; + for (let i = 0; i < container.children.length; i++) { + const child = container.children[i]; + if (finder(child)) { + return child; + } else if (child.children) { + result = recursiveFindChild(child as Container, finder); + } + } + return result; +} + +export interface BezierParam { + p1: IPointData; + p2: IPointData; + cp1: IPointData; + cp2: IPointData; +} + +/** + * 判断贝塞尔曲线数据是否正确 + * @param points + */ +export function assertBezierPoints(points: IPointData[]) { + if (points.length < 4 || points.length % 3 !== 1) { + throw new Error(`bezierCurve 数据错误: ${points}`); + } +} + +/** + * 转换为贝塞尔曲线参数 + * @param points + * @returns + */ +export function convertToBezierParams(points: IPointData[]): BezierParam[] { + assertBezierPoints(points); + const bps: BezierParam[] = []; + for (let i = 0; i < points.length - 3; i += 3) { + const p1 = new Point(points[i].x, points[i].y); + const p2 = new Point(points[i + 3].x, points[i + 3].y); + const cp1 = new Point(points[i + 1].x, points[i + 1].y); + const cp2 = new Point(points[i + 2].x, points[i + 2].y); + bps.push({ + p1, + p2, + cp1, + cp2, + }); + } + return bps; +} + +/** + * 根据分段数计算贝塞尔曲线所有点坐标 + * @param basePoints + * @param segmentsCount + * @returns + */ +export function calculateBezierPoints( + basePoints: IPointData[], + segmentsCount: number +): Point[] { + const bps = convertToBezierParams(basePoints); + const points: Point[] = []; + bps.forEach((bp) => { + points.push( + ...calculateOneBezierPoints(bp.p1, bp.p2, bp.cp1, bp.cp2, segmentsCount) + ); + }); + return points; +} + +/** + * 根据分段数计算贝塞尔曲线所有点坐标 + * @param basePoints + * @param segmentsCount + * @returns + */ +export function calculateOneBezierPoints( + p1: IPointData, + p2: IPointData, + cp1: IPointData, + cp2: IPointData, + segmentsCount: number +): Point[] { + const points: Point[] = []; + const fromX = p1.x; + const fromY = p1.y; + const n = segmentsCount; + let dt = 0; + let dt2 = 0; + let dt3 = 0; + let t2 = 0; + let t3 = 0; + const cpX = cp1.x; + const cpY = cp1.y; + const cpX2 = cp2.x; + const cpY2 = cp2.y; + const toX = p2.x; + const toY = p2.y; + points.push(new Point(p1.x, p1.y)); + for (let i = 1, j = 0; i <= n; ++i) { + j = i / n; + dt = 1 - j; + dt2 = dt * dt; + dt3 = dt2 * dt; + t2 = j * j; + t3 = t2 * j; + const px = dt3 * fromX + 3 * dt2 * j * cpX + 3 * dt * t2 * cpX2 + t3 * toX; + const py = dt3 * fromY + 3 * dt2 * j * cpY + 3 * dt * t2 * cpY2 + t3 * toY; + points.push(new Point(px, py)); + } + return points; +} + +/** + * 计算矩形中点 + */ +export function getRectangleCenter(rectangle: Rectangle): Point { + return new Point( + rectangle.x + rectangle.width / 2, + rectangle.y + rectangle.height / 2 + ); +} + +/** + * 计算两个矩形中心对齐的坐标, PS: 计算的是较大包围框的中心 + * @param rect1 + * @param rect2 + * @returns + */ +export function getCenterOfTwoRectangle( + rect1: Rectangle, + rect2: Rectangle +): Point { + const x = Math.abs(rect1.width - rect2.width) / 2; + const y = Math.abs(rect1.height - rect2.height) / 2; + return new Point(x, y); +} + +/** + * 序列化图形变换 + * @param obj + * @returns + */ +export function serializeTransform(obj: DisplayObject): number[] { + const position = obj.position; + const scale = obj.scale; + const angle = obj.angle; + const skew = obj.skew; + return [position.x, position.y, scale.x, scale.y, angle, skew.x, skew.y]; +} +/** + * 反序列化变换数据到图形对象 + * @param obj + * @param transform + */ +export function deserializeTransformInto( + obj: DisplayObject, + transform: number[] +): void { + if (transform.length === 7) { + obj.position.set(transform[0], transform[1]); + obj.scale.set(transform[2], transform[3]); + obj.angle = transform[4]; + obj.skew.set(transform[5], transform[6]); + } else if (transform.length > 0) { + console.warn('错误的变换数据', transform); + } +} + +/** + * 将直线转换为多边形 + * @param p1 + * @param p2 + * @param thick + * @returns + */ +export function convertLineToPolygonPoints( + p1: IPointData, + p2: IPointData, + thick: number +): IPointData[] { + const angle = Math.atan2(p2.y - p1.y, p2.x - p1.x) - Math.PI / 2; + const half = thick / 2; + const cos = Math.cos(angle) * half; + const sin = Math.sin(angle) * half; + return [ + new Point(p1.x - cos, p1.y - sin), + new Point(p2.x - cos, p2.y - sin), + new Point(p2.x + cos, p2.y + sin), + new Point(p1.x + cos, p1.y + sin), + ]; +} + +/** + * 转换矩形为多边形点坐标 + * @param rect 矩形 + * @returns + */ +export function convertRectangleToPolygonPoints(rect: Rectangle): IPointData[] { + return [ + new Point(rect.x, rect.y), + new Point(rect.x + rect.width, rect.y), + new Point(rect.x + rect.width, rect.y + rect.height), + new Point(rect.x, rect.y + rect.height), + ]; +} + +/** + * 计算线段中点坐标 + * @param p1 + * @param p2 + * @returns + */ +export function calculateLineMidpoint(p1: IPointData, p2: IPointData): Point { + const x = (p1.x + p2.x) / 2; + const y = (p1.y + p2.y) / 2; + return new Point(x, y); +} + +/** + * 计算线段细分坐标--线段分成几份 + * @param p1 + * @param p2 + * @param knife + * @returns + */ +export function calculateLineSegmentingPoint( + p1: IPointData, + p2: IPointData, + knife: number +): IPointData[] { + const segmentingPoints: IPointData[] = []; + const x = p1.x < p2.x ? p1.x : p2.x; + const y = p1.y < p2.y ? p1.y : p2.y; + const w = Math.abs(p1.x - p2.x); + const h = Math.abs(p1.y - p2.y); + for (let i = 0; i < knife - 1; i++) { + const pointX = x + (w * (i + 1)) / knife; + const pointy = y + (h * (i + 1)) / knife; + segmentingPoints.push(new Point(pointX, pointy)); + } + return segmentingPoints; +} + +/** + * 计算点到直线距离 + * @param p1 + * @param p2 + * @param p + */ +export function calculateDistanceFromPointToLine( + p1: IPointData, + p2: IPointData, + p: IPointData +): number { + // 求直线的一般方程参数ABC,直线的一般式方程AX+BY+C=0 + const A = p1.y - p2.y; + const B = p2.x - p1.x; + const C = p1.x * p2.y - p1.y * p2.x; + // 计算点到直线垂直距离: d = |Ax+By+C|/sqrt(A*A+B*B),其中x,y为点坐标 + const dl = Math.abs(A * p.x + B * p.y + C) / Math.sqrt(A * A + B * B); + return dl; +} + +/** + * 计算点到直线的垂足坐标 + * @param p + * @param p1 + * @param p2 + */ +export function calculateFootPointFromPointToLine( + p1: IPointData, + p2: IPointData, + p: IPointData +): Point { + if (p1.x == p2.x && p1.y == p2.y) { + throw new Error(`直线两坐标点相等:${p1}`); + } + const k = -( + ((p1.x - p.x) * (p2.x - p1.x) + (p1.y - p.y) * (p2.y - p1.y)) / + (Math.pow(p1.x - p2.x, 2) + Math.pow(p1.y - p2.y, 2)) + ); + if (isZero(k)) { + return new Point(p.x, p.y); + } + const xf = k * (p2.x - p1.x) + p1.x; + const yf = k * (p2.y - p1.y) + p1.y; + return new Point(xf, yf); +} + +/** + * 计算直线与圆的交点 + * 1用直线到圆心的距离和半径相比,判断是否和圆有交点; + * 2求出圆心在直线上面的垂点; + * 3算出直线的单位向量e; + * 4求出一侧交点(Intersection)到projectPoint的长度(sideLength); + * 5求出sideLength和这侧端点到projectPoint距离的比例(ratio); + * 6projectPoint +/- ratio * e = 两侧交点; + * @param p0 圆心坐标 + * @param radius 圆半径 + * @param p1 直线坐标1 + * @param p2 直线坐标2 + * @returns 交点坐标,可能2/1/0个 + */ +export function calculateIntersectionPointOfCircleAndLine( + p0: IPointData, + radius: number, + p1: IPointData, + p2: IPointData +): Point[] { + const distance = calculateDistanceFromPointToLine(p1, p2, p0); + if (distance <= radius) { + // 有交点 + // 计算垂点 + const pr = calculateFootPointFromPointToLine(p1, p2, p0); + if (floatEquals(distance, radius)) { + // 切线 + return [pr]; + } + const vpr = new Vector2([pr.x, pr.y]); + const vc = new Vector2([p0.x, p0.y]); + // 计算直线单位向量 + const v1 = new Vector2([p1.x, p1.y]); + const v2 = new Vector2([p2.x, p2.y]); + const ve = Vector2.direction(v2, v1); + const base = Math.sqrt( + Math.abs(radius * radius - Vector2.difference(vpr, vc).squaredLength()) + ); + const vl = ve.scale(base); + const ip1 = Vector2.sum(vpr, vl); + const ip2 = Vector2.difference(vpr, vl); + return [new Point(ip1.x, ip1.y), new Point(ip2.x, ip2.y)]; + } else { + // 无交点 + return []; + } +} + +/** + * 计算圆心与圆心外一点与圆的交点(取圆心到点的向量与圆的交点) + * @param p0 圆心坐标 + * @param radius 圆半径 + * @param p 点坐标 + * @returns + */ +export function calculateIntersectionPointOfCircleAndPoint( + p0: IPointData, + radius: number, + p: IPointData +): Point { + const points = calculateIntersectionPointOfCircleAndLine(p0, radius, p0, p); + const vc = new Vector2([p0.x, p0.y]); + const vp = new Vector2([p.x, p.y]); + const vecp = Vector2.direction(vp, vc); + for (let i = 0; i < points.length; i++) { + const ip = points[i]; + const ve = Vector2.direction(new Vector2([ip.x, ip.y]), vc); + if (ve.equals(vecp)) { + return ip; + } + } + throw new Error('计算圆心与圆心外一点与圆的交点逻辑错误'); +} + +/** + * 计算点基于点的镜像点坐标 + * @param bp 基准点 + * @param p 待镜像的点坐标 + * @param distance 镜像点到基准点的距离,默认为p到基准点的距离,即对称 + * @returns + */ +export function calculateMirrorPoint( + bp: IPointData, + p: IPointData, + distance?: number +): Point { + const vbp = Vector2.from(bp); + const vp = Vector2.from(p); + const direction = Vector2.direction(vbp, vp); + if (distance == undefined) { + distance = Vector2.distance(vbp, vp); + } + const vmp = Vector2.sum(vbp, direction.scale(distance)); + return new Point(vmp.x, vmp.y); +} + +/** + * 计算基于给定轴的给定点的镜像点坐标 + * @param pa 给定轴线的坐标 + * @param pb 给定轴线的坐标 + * @param p 待镜像点坐标 + * @param distance + * @returns + */ +export function calculateMirrorPointBasedOnAxis( + pa: IPointData, + pb: IPointData, + p: IPointData, + distance?: number +): Point { + const fp = calculateFootPointFromPointToLine(pa, pb, p); + if (fp.equals(p)) { + return fp; + } else { + return calculateMirrorPoint(fp, p, distance); + } +} + +/** + * 计算直线与水平夹角,角度按顺时针,从0开始 + * @param p1 + * @param p2 + * @returns 角度,范围[0, 360) + */ +export function angleToAxisx(p1: IPointData, p2: IPointData): number { + if (p1.x == p2.x && p1.y == p2.y) { + throw new Error('一个点无法计算角度'); + } + const dx = Math.abs(p1.x - p2.x); + const dy = Math.abs(p1.y - p2.y); + + if (p2.x == p1.x) { + if (p2.y > p1.y) { + return 90; + } else { + return 270; + } + } + if (p2.y == p1.y) { + if (p2.x > p1.x) { + return 0; + } else { + return 180; + } + } + const angle = (Math.atan2(dy, dx) * 180) / Math.PI; + if (p2.x > p1.x) { + if (p2.y > p1.y) { + return angle; + } else if (p2.y < p1.y) { + return 360 - angle; + } + } else if (p2.x < p1.x) { + if (p2.y > p1.y) { + return 180 - angle; + } else { + return 180 + angle; + } + } + return angle; +} + +/** + * 计算两线夹角,pc与pa,pb的夹角,顺时针为正,逆时针为负 + * @param pa 交点 + * @param pb 锚定 + * @param pc + * @returns 夹角, [-180, 180] + */ +export function angleOfIncludedAngle( + pa: IPointData, + pb: IPointData, + pc: IPointData +): number { + const abAngle = angleToAxisx(pa, pb); + const acAngle = angleToAxisx(pa, pc); + let angle = acAngle - abAngle; + if (angle < -180) { + angle = 360 + angle; + } else if (angle > 180) { + angle = -(360 - angle); + } + return angle; +} + +/** + * 计算两点连线的法向量 + * @param point1 + * @param point2 + * @returns 单位法向量 + */ +export function getNormalVector( + point1: IPointData, + point2: IPointData +): number[] { + const x1 = point1.x, + y1 = point1.y; + const x2 = point2.x, + y2 = point2.y; + const length = Math.sqrt((y2 - y1) ** 2 + (x2 - x1) ** 2); + return [(y2 - y1) / length, (x1 - x2) / length]; +} + +/** + * 点延向量方向移动 + * @param point + * @param normal 单位向量 + * @param length 平移长度 + * @returns 移动后的点 + */ +export function movePointAlongNormal( + point: IPointData, + normal: number[], + length: number +): Point { + const newPoint = new Point( + point.x + length * normal[0], + point.y + length * normal[1] + ); + return newPoint; +} + +/** + * 计算两组点各自组成直线的相交点(若两线平行 返回第一组坐标第一个点) + * @param line1 两点坐标列表 + * @param line2 两点坐标列表 + * @returns 相交点 + */ +export function getIntersectionPoint(line1: number[], line2: number[]) { + const a1 = line1[0], + b1 = line1[1]; + const a2 = line1[2], + b2 = line1[3]; + const a3 = line2[0], + b3 = line2[1]; + const a4 = line2[2], + b4 = line2[3]; + const denominator = (a3 - a4) * (b1 - b2) - (a1 - a2) * (b3 - b4); + if (denominator === 0) { + return new Point(a1, b1); + } + const x = + ((a3 - a4) * (a2 * b1 - a1 * b2) - (a1 - a2) * (a4 * b3 - a3 * b4)) / + denominator; + const y = + ((b3 - b4) * (b2 * a1 - b1 * a2) - (b1 - b2) * (b4 * a3 - b3 * a4)) / + -denominator; + return new Point(x, y); +} + +/** + * 是否平行线 + * @param p1 + * @param p2 + * @param pa + * @param pb + * @returns + */ +export function isParallelLines( + p1: IPointData, + p2: IPointData, + pa: IPointData, + pb: IPointData +): boolean { + const vle1 = Vector2.direction(Vector2.from(p1), Vector2.from(p2)); + const vle2 = Vector2.direction(Vector2.from(pa), Vector2.from(pb)); + if (vle2.equals(vle1)) { + return true; + } + return vle1.equals(Vector2.direction(Vector2.from(pb), Vector2.from(pa))); +} + +/** + * 点是否在线段上 + * @param p1 + * @param p2 + * @param p + * @returns + */ +export function isPointOnLine( + p1: IPointData, + p2: IPointData, + p: IPointData +): boolean { + const vp1 = Vector2.from(p1); + const vp2 = Vector2.from(p2); + const vp = Vector2.from(p); + if (vp1.equals(vp) || vp2.equals(vp)) { + return true; + } + const vle = Vector2.direction(vp1, Vector2.from(p2)); + const vpe = Vector2.direction(vp1, vp); + if (vle.equals(vpe)) { + return ( + Vector2.difference(vp1, vp2).squaredLength() >= + Vector2.difference(vp1, vp).squaredLength() + ); + } + return false; +} +/** + * 两条线段是否存在包含关系 + * @param line1 + * @param line2 + * @returns + */ +export function isLineContainOther( + line1: { p1: IPointData; p2: IPointData }, + line2: { p1: IPointData; p2: IPointData } +): boolean { + return ( + (isPointOnLine(line1.p1, line1.p2, line2.p1) && + isPointOnLine(line1.p1, line1.p2, line2.p2)) || + (isPointOnLine(line2.p1, line2.p2, line1.p1) && + isPointOnLine(line2.p1, line2.p2, line1.p2)) + ); +} + +/** 均分线段, 返回各线段端点 */ +export function splitLineEvenly( + p1: IPointData, + p2: IPointData, + count: number +): IPointData[][] { + const [stepX, stepY] = [(p2.x - p1.x) / count, (p2.y - p1.y) / count]; + return Array(count) + .fill(1) + .map((_, i) => { + return [ + { x: p1.x + stepX * i, y: p1.y + stepY * i }, + { x: p1.x + stepX * (i + 1), y: p1.y + stepY * (i + 1) }, + ]; + }); +} diff --git a/src/jl-graphic/utils/IntersectUtils.ts b/src/jl-graphic/utils/IntersectUtils.ts new file mode 100644 index 0000000..2217a28 --- /dev/null +++ b/src/jl-graphic/utils/IntersectUtils.ts @@ -0,0 +1,362 @@ +import { IPointData, Point, Rectangle } from 'pixi.js'; +// /** +// * 点线碰撞检测 +// * @param pa 线段a端坐标 +// * @param pb 线段b端坐标 +// * @param p 点坐标 +// * @param tolerance 容忍度,越大检测范围越大 +// * @returns +// */ +// export function linePoint(pa: Point, pb: Point, p: Point, tolerance: number): boolean { +// return (Math.abs(distanceSquared(pa.x, pa.y, pb.x, pb.y) - (distanceSquared(pa.x, pa.y, p.x, p.y) + distanceSquared(pb.x, pb.y, p.x, p.y))) <= tolerance) +// } + +/** + * 根据点到直线的垂直距离计算碰撞 + * @param pa 线段a端坐标 + * @param pb 线段b端坐标 + * @param p 点坐标 + * @param lineWidth 线宽 + * @param exact 是否精确(使用给定线宽,否则线宽会设置为8) + * @returns + */ +export function linePoint( + pa: IPointData, + pb: IPointData, + p: IPointData, + lineWidth: number, + exact = false +): boolean { + if (!exact && lineWidth < 6) { + lineWidth = 6; + } + // 求直线的一般方程参数ABC,直线的一般式方程AX+BY+C=0 + const A = pa.y - pb.y; + const B = pb.x - pa.x; + const C = pa.x * pb.y - pa.y * pb.x; + // 计算点到直线垂直距离: d = |Ax+By+C|/sqrt(A*A+B*B),其中x,y为点坐标 + const dl = Math.abs(A * p.x + B * p.y + C) / Math.sqrt(A * A + B * B); + const intersect = dl <= lineWidth / 2; + if (intersect) { + // 距离在线宽范围内,再判断点是否超过线段两端点范围外(两端点外会有一点误差,两端点线宽一半半径的圆范围内) + const da = distance(pa.x, pa.y, p.x, p.y); + const db = distance(pb.x, pb.y, p.x, p.y); + const dab = distance(pa.x, pa.y, pb.x, pb.y); + return da <= dl + dab && db <= dl + dab; + } + return false; +} + +/** + * 折线与点碰撞 + * @param points 折线端点列表 + * @param p 点座标 + * @param lineWidth 线宽 + */ +export function polylinePoint( + points: IPointData[], + p: IPointData, + lineWidth: number +) { + const len = points.length; + for (let i = 0; i < len - 1; i++) { + if (linePoint(points[i], points[i + 1], p, lineWidth)) { + return true; + } + } + return false; +} + +/** + * 线线碰撞检测 + * @param pa 线段1a端坐标 + * @param pb 线段1b端坐标 + * @param p1 线段2a端坐标 + * @param p2 线段2b端坐标 + * @returns + */ +export function lineLine( + pa: IPointData, + pb: IPointData, + p1: IPointData, + p2: IPointData +): boolean { + const x1 = pa.x; + const y1 = pa.y; + const x2 = pb.x; + const y2 = pb.y; + const x3 = p1.x; + const y3 = p1.y; + const x4 = p2.x; + const y4 = p2.y; + const s1_x = x2 - x1; + const s1_y = y2 - y1; + const s2_x = x4 - x3; + const s2_y = y4 - y3; + const s = + (-s1_y * (x1 - x3) + s1_x * (y1 - y3)) / (-s2_x * s1_y + s1_x * s2_y); + const t = + (s2_x * (y1 - y3) - s2_y * (x1 - x3)) / (-s2_x * s1_y + s1_x * s2_y); + return s >= 0 && s <= 1 && t >= 0 && t <= 1; +} +/** + * 点和矩形碰撞检测 + * @param p 点作弊 + * @param rect 矩形 + * @returns + */ +export function pointBox(p: IPointData, rect: Rectangle): boolean { + const { x, y, width, height } = rect; + const x2 = p.x; + const y2 = p.y; + return x2 >= x && x2 <= x + width && y2 >= y && y2 <= y + height; +} +/** + * 线和矩形碰撞检测 + * @param pa 线段a端坐标 + * @param pb 线段b端坐标 + * @param rect 矩形 + * @returns + */ +export function lineBox( + pa: IPointData, + pb: IPointData, + rect: Rectangle +): boolean { + if (pointBox(pa, rect) || pointBox(pb, rect)) { + return true; + } + const { x, y, width, height } = rect; + const rp1 = new Point(x, y); + const rp2 = new Point(x + width, y); + const rp3 = new Point(x + width, y + height); + const rp4 = new Point(x, y + height); + return ( + lineLine(pa, pb, rp1, rp2) || + lineLine(pa, pb, rp2, rp3) || + lineLine(pa, pb, rp3, rp4) || + lineLine(pa, pb, rp1, rp4) + ); +} + +/** + * 多线段和矩形碰撞检测 + * @param points + * @param rect + * @returns false / 碰撞的线段序号 + */ +export function polylineBox(points: IPointData[], rect: Rectangle): boolean { + if (points.length < 2) { + return false; + } + + for (let i = 0; i < points.length - 1; i++) { + const p1 = points[i]; + const p2 = points[i + 1]; + + if (lineBox(p1, p2, rect)) { + return true; + } + } + return false; +} + +/** + * 两点碰撞检测 + * @param p1 + * @param p2 + * @param tolerance + * @returns + */ +export function pointPoint2( + p1: IPointData, + p2: IPointData, + tolerance: number +): boolean { + return pointPoint(p1.x, p1.y, p2.x, p2.y, tolerance); +} + +/** + * 两点碰撞检测 + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @param tolerance 容忍度/两点半径和 + * @returns + */ +export function pointPoint( + x1: number, + y1: number, + x2: number, + y2: number, + tolerance: number +): boolean { + return distance(x1, y1, x2, y2) <= tolerance; +} + +/** + * 两点距离 + * @param x1 + * @param y1 + * @param x2 + * @param y2 + * @returns + */ +export function distance(x1: number, y1: number, x2: number, y2: number) { + return Math.sqrt(Math.pow(x1 - x2, 2) + Math.pow(y1 - y2, 2)); +} + +/** + * 两点距离 + * @param p1 + * @param p2 + * @returns + */ +export function distance2(p1: IPointData, p2: IPointData): number { + return distance(p1.x, p1.y, p2.x, p2.y); +} + +/** + * 圆和点的碰撞检测 + * @param x1 圆心x + * @param y1 圆心y + * @param r1 圆半径 + * @param x2 点x + * @param y2 点y + * @returns + */ +export function circlePoint( + x1: number, + y1: number, + r1: number, + x2: number, + y2: number +) { + const x = x2 - x1; + const y = y2 - y1; + return x * x + y * y <= r1 * r1; +} + +/** + * 圆和点的碰撞检测--不包括圆内部 + */ +export function circlePoint2( + x1: number, + y1: number, + r1: number, + x2: number, + y2: number, + tolerance: number +) { + const x = x2 - x1; + const y = y2 - y1; + return ( + x * x + y * y <= (r1 + tolerance) * (r1 + tolerance) && + x * x + y * y >= (r1 - tolerance) * (r1 - tolerance) + ); +} + +/** + * 点和多边形碰撞检测 + */ +export function pointPolygon( + p: IPointData, + points: IPointData[], + lineWidth: number +): boolean { + const { x, y } = p; + const length = points.length; + let c = false; + let i, j; + for (i = 0, j = length - 1; i < length; i++) { + if ( + points[i].y > y !== points[j].y > y && + x < + ((points[j].x - points[i].x) * (y - points[i].y)) / + (points[j].y - points[i].y) + + points[i].x + ) { + c = !c; + } + j = i; + } + if (c) { + return true; + } + for (i = 0; i < length - 1; i++) { + let p1, p2; + if (i === length - 1) { + p1 = points[i]; + p2 = points[0]; + } else { + p1 = points[i]; + p2 = points[i + 1]; + } + if (linePoint(p1, p2, p, lineWidth)) { + return true; + } + } + return false; +} + +/** + * 线和多边形碰撞检测 + * @param p1 + * @param p2 + * @param points + * @param tolerance 多边形包围线宽 + * @returns + */ +export function linePolygon( + p1: IPointData, + p2: IPointData, + points: IPointData[], + lineWidth: number, + polygonWidth: number +): boolean { + if (pointPolygon(p1, points, polygonWidth)) { + return true; + } + const length = points.length; + for (let i = 0; i < length; i++) { + let pa, pb; + if (i === length - 1) { + pa = points[i]; + pb = points[0]; + } else { + pa = points[i]; + pb = points[i + 1]; + } + // TODO:此处后续需考虑有线宽的情况 + if (lineLine(pa, pb, p1, p2)) { + return true; + } + } + return false; +} + +/** + * 多边线与多边形碰撞检测 + * @param polylinePoints 多边线所有点坐标 + * @param polygonPoints 多边形所有点坐标 + * @param polylineWidth 多边线的线宽 + * @param polygonWidth 多边形线宽 + * @returns + */ +export function polylinePolygon( + polylinePoints: IPointData[], + polygonPoints: IPointData[], + polylineWidth: number, + polygonWidth: number +): boolean { + const length = polylinePoints.length; + for (let i = 0; i < length - 1; i++) { + const p1 = polylinePoints[i]; + const p2 = polylinePoints[i + 1]; + if (linePolygon(p1, p2, polygonPoints, polylineWidth, polygonWidth)) { + return true; + } + } + return false; +} diff --git a/src/jl-graphic/utils/index.ts b/src/jl-graphic/utils/index.ts new file mode 100644 index 0000000..57ec464 --- /dev/null +++ b/src/jl-graphic/utils/index.ts @@ -0,0 +1,53 @@ +import { Point, Rectangle } from 'pixi.js'; + +export * from './GraphicUtils'; +export * from './IntersectUtils'; + +export const UP: Point = new Point(0, -1); +export const DOWN: Point = new Point(0, 1); +export const LEFT: Point = new Point(-1, 0); +export const RIGHT: Point = new Point(1, 0); + +/** + * 越界结果 + */ +export class OutOfBound { + left: boolean; + top: boolean; + right: boolean; + bottom: boolean; + constructor(left: boolean, top: boolean, right: boolean, bottom: boolean) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + static check(rect: Rectangle, bound: Rectangle): OutOfBound { + const left = rect.left < bound.left; + const top = rect.top < bound.top; + const right = rect.right > bound.right; + const bottom = rect.bottom > bound.bottom; + return new OutOfBound(left, top, right, bottom); + } + static none(): OutOfBound { + return new OutOfBound(false, false, false, false); + } + static leftOut(): OutOfBound { + return new OutOfBound(true, false, false, false); + } + static topOut(): OutOfBound { + return new OutOfBound(false, true, false, false); + } + static rightOut(): OutOfBound { + return new OutOfBound(false, false, true, false); + } + static bottomOut(): OutOfBound { + return new OutOfBound(false, false, false, true); + } + static leftTopOut(): OutOfBound { + return new OutOfBound(true, true, false, false); + } + static rightBottomOut(): OutOfBound { + return new OutOfBound(false, false, true, true); + } +} diff --git a/src/layouts/DrawLayout.vue b/src/layouts/DrawLayout.vue new file mode 100644 index 0000000..e6b6726 --- /dev/null +++ b/src/layouts/DrawLayout.vue @@ -0,0 +1,361 @@ + + + diff --git a/src/layouts/LineLayout.vue b/src/layouts/LineLayout.vue new file mode 100644 index 0000000..404f66b --- /dev/null +++ b/src/layouts/LineLayout.vue @@ -0,0 +1,81 @@ + + + diff --git a/src/layouts/MainLayout.vue b/src/layouts/MainLayout.vue new file mode 100644 index 0000000..356ecc8 --- /dev/null +++ b/src/layouts/MainLayout.vue @@ -0,0 +1,74 @@ + + + diff --git a/src/pages/DraftManage.vue b/src/pages/DraftManage.vue new file mode 100644 index 0000000..a157213 --- /dev/null +++ b/src/pages/DraftManage.vue @@ -0,0 +1,365 @@ + + + diff --git a/src/pages/ErrorNotFound.vue b/src/pages/ErrorNotFound.vue new file mode 100644 index 0000000..f4e0bb8 --- /dev/null +++ b/src/pages/ErrorNotFound.vue @@ -0,0 +1,27 @@ + + + diff --git a/src/pages/IndexPage.vue b/src/pages/IndexPage.vue new file mode 100644 index 0000000..d0684cb --- /dev/null +++ b/src/pages/IndexPage.vue @@ -0,0 +1,7 @@ + + + diff --git a/src/pages/LineInfoManage.vue b/src/pages/LineInfoManage.vue new file mode 100644 index 0000000..a348f11 --- /dev/null +++ b/src/pages/LineInfoManage.vue @@ -0,0 +1,270 @@ + + + diff --git a/src/pages/LineMonitorPage.vue b/src/pages/LineMonitorPage.vue new file mode 100644 index 0000000..abd5510 --- /dev/null +++ b/src/pages/LineMonitorPage.vue @@ -0,0 +1,69 @@ + + + diff --git a/src/pages/MonitorPage.vue b/src/pages/MonitorPage.vue new file mode 100644 index 0000000..38ec6b1 --- /dev/null +++ b/src/pages/MonitorPage.vue @@ -0,0 +1,91 @@ + + + diff --git a/src/pages/PublishManage.vue b/src/pages/PublishManage.vue new file mode 100644 index 0000000..4faa6d5 --- /dev/null +++ b/src/pages/PublishManage.vue @@ -0,0 +1,182 @@ + + + diff --git a/src/pages/UserLogin.vue b/src/pages/UserLogin.vue new file mode 100644 index 0000000..1e0c96c --- /dev/null +++ b/src/pages/UserLogin.vue @@ -0,0 +1,90 @@ + + + + + diff --git a/src/pages/UserManage.vue b/src/pages/UserManage.vue new file mode 100644 index 0000000..43f81ba --- /dev/null +++ b/src/pages/UserManage.vue @@ -0,0 +1,215 @@ + + + diff --git a/src/pages/UserRegister.vue b/src/pages/UserRegister.vue new file mode 100644 index 0000000..901f83b --- /dev/null +++ b/src/pages/UserRegister.vue @@ -0,0 +1,97 @@ + + + + + diff --git a/src/protos/Device.ts b/src/protos/Device.ts new file mode 100644 index 0000000..ce53f65 --- /dev/null +++ b/src/protos/Device.ts @@ -0,0 +1,566 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: Device.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export class Device extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + reportId?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("reportId" in data && data.reportId != undefined) { + this.reportId = data.reportId; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get reportId() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set reportId(value: number) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + lineId?: number; + reportId?: number; + }): Device { + const message = new Device({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.reportId != null) { + message.reportId = data.reportId; + } + return message; + } + toObject() { + const data: { + lineId?: number; + reportId?: number; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.reportId != null) { + data.reportId = this.reportId; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.reportId != 0) + writer.writeInt32(2, this.reportId); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Device { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Device(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.reportId = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Device { + return Device.deserialize(bytes); + } +} +export class DeviceDetail extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + deviceType?: string; + deviceName?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("deviceType" in data && data.deviceType != undefined) { + this.deviceType = data.deviceType; + } + if ("deviceName" in data && data.deviceName != undefined) { + this.deviceName = data.deviceName; + } + } + } + get deviceType() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set deviceType(value: string) { + pb_1.Message.setField(this, 1, value); + } + get deviceName() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set deviceName(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + deviceType?: string; + deviceName?: string; + }): DeviceDetail { + const message = new DeviceDetail({}); + if (data.deviceType != null) { + message.deviceType = data.deviceType; + } + if (data.deviceName != null) { + message.deviceName = data.deviceName; + } + return message; + } + toObject() { + const data: { + deviceType?: string; + deviceName?: string; + } = {}; + if (this.deviceType != null) { + data.deviceType = this.deviceType; + } + if (this.deviceName != null) { + data.deviceName = this.deviceName; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.deviceType.length) + writer.writeString(1, this.deviceType); + if (this.deviceName.length) + writer.writeString(2, this.deviceName); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): DeviceDetail { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new DeviceDetail(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.deviceType = reader.readString(); + break; + case 2: + message.deviceName = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): DeviceDetail { + return DeviceDetail.deserialize(bytes); + } +} +export class Track extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + device?: Device; + detail?: DeviceDetail; + speedLimit?: number; + limitType?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("device" in data && data.device != undefined) { + this.device = data.device; + } + if ("detail" in data && data.detail != undefined) { + this.detail = data.detail; + } + if ("speedLimit" in data && data.speedLimit != undefined) { + this.speedLimit = data.speedLimit; + } + if ("limitType" in data && data.limitType != undefined) { + this.limitType = data.limitType; + } + } + } + get device() { + return pb_1.Message.getWrapperField(this, Device, 1) as Device; + } + set device(value: Device) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_device() { + return pb_1.Message.getField(this, 1) != null; + } + get detail() { + return pb_1.Message.getWrapperField(this, DeviceDetail, 2) as DeviceDetail; + } + set detail(value: DeviceDetail) { + pb_1.Message.setWrapperField(this, 2, value); + } + get has_detail() { + return pb_1.Message.getField(this, 2) != null; + } + get speedLimit() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set speedLimit(value: number) { + pb_1.Message.setField(this, 3, value); + } + get limitType() { + return pb_1.Message.getFieldWithDefault(this, 4, 0) as number; + } + set limitType(value: number) { + pb_1.Message.setField(this, 4, value); + } + static fromObject(data: { + device?: ReturnType; + detail?: ReturnType; + speedLimit?: number; + limitType?: number; + }): Track { + const message = new Track({}); + if (data.device != null) { + message.device = Device.fromObject(data.device); + } + if (data.detail != null) { + message.detail = DeviceDetail.fromObject(data.detail); + } + if (data.speedLimit != null) { + message.speedLimit = data.speedLimit; + } + if (data.limitType != null) { + message.limitType = data.limitType; + } + return message; + } + toObject() { + const data: { + device?: ReturnType; + detail?: ReturnType; + speedLimit?: number; + limitType?: number; + } = {}; + if (this.device != null) { + data.device = this.device.toObject(); + } + if (this.detail != null) { + data.detail = this.detail.toObject(); + } + if (this.speedLimit != null) { + data.speedLimit = this.speedLimit; + } + if (this.limitType != null) { + data.limitType = this.limitType; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_device) + writer.writeMessage(1, this.device, () => this.device.serialize(writer)); + if (this.has_detail) + writer.writeMessage(2, this.detail, () => this.detail.serialize(writer)); + if (this.speedLimit != 0) + writer.writeFloat(3, this.speedLimit); + if (this.limitType != 0) + writer.writeInt32(4, this.limitType); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Track { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Track(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.device, () => message.device = Device.deserialize(reader)); + break; + case 2: + reader.readMessage(message.detail, () => message.detail = DeviceDetail.deserialize(reader)); + break; + case 3: + message.speedLimit = reader.readFloat(); + break; + case 4: + message.limitType = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Track { + return Track.deserialize(bytes); + } +} +export class Platform extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + device?: Device; + detail?: DeviceDetail; + stopTime?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("device" in data && data.device != undefined) { + this.device = data.device; + } + if ("detail" in data && data.detail != undefined) { + this.detail = data.detail; + } + if ("stopTime" in data && data.stopTime != undefined) { + this.stopTime = data.stopTime; + } + } + } + get device() { + return pb_1.Message.getWrapperField(this, Device, 1) as Device; + } + set device(value: Device) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_device() { + return pb_1.Message.getField(this, 1) != null; + } + get detail() { + return pb_1.Message.getWrapperField(this, DeviceDetail, 2) as DeviceDetail; + } + set detail(value: DeviceDetail) { + pb_1.Message.setWrapperField(this, 2, value); + } + get has_detail() { + return pb_1.Message.getField(this, 2) != null; + } + get stopTime() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set stopTime(value: number) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + device?: ReturnType; + detail?: ReturnType; + stopTime?: number; + }): Platform { + const message = new Platform({}); + if (data.device != null) { + message.device = Device.fromObject(data.device); + } + if (data.detail != null) { + message.detail = DeviceDetail.fromObject(data.detail); + } + if (data.stopTime != null) { + message.stopTime = data.stopTime; + } + return message; + } + toObject() { + const data: { + device?: ReturnType; + detail?: ReturnType; + stopTime?: number; + } = {}; + if (this.device != null) { + data.device = this.device.toObject(); + } + if (this.detail != null) { + data.detail = this.detail.toObject(); + } + if (this.stopTime != null) { + data.stopTime = this.stopTime; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_device) + writer.writeMessage(1, this.device, () => this.device.serialize(writer)); + if (this.has_detail) + writer.writeMessage(2, this.detail, () => this.detail.serialize(writer)); + if (this.stopTime != 0) + writer.writeInt32(3, this.stopTime); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Platform { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Platform(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.device, () => message.device = Device.deserialize(reader)); + break; + case 2: + reader.readMessage(message.detail, () => message.detail = DeviceDetail.deserialize(reader)); + break; + case 3: + message.stopTime = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Platform { + return Platform.deserialize(bytes); + } +} +export class Switch extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + device?: Device; + detail?: DeviceDetail; + speedLimit?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("device" in data && data.device != undefined) { + this.device = data.device; + } + if ("detail" in data && data.detail != undefined) { + this.detail = data.detail; + } + if ("speedLimit" in data && data.speedLimit != undefined) { + this.speedLimit = data.speedLimit; + } + } + } + get device() { + return pb_1.Message.getWrapperField(this, Device, 1) as Device; + } + set device(value: Device) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_device() { + return pb_1.Message.getField(this, 1) != null; + } + get detail() { + return pb_1.Message.getWrapperField(this, DeviceDetail, 2) as DeviceDetail; + } + set detail(value: DeviceDetail) { + pb_1.Message.setWrapperField(this, 2, value); + } + get has_detail() { + return pb_1.Message.getField(this, 2) != null; + } + get speedLimit() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set speedLimit(value: number) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + device?: ReturnType; + detail?: ReturnType; + speedLimit?: number; + }): Switch { + const message = new Switch({}); + if (data.device != null) { + message.device = Device.fromObject(data.device); + } + if (data.detail != null) { + message.detail = DeviceDetail.fromObject(data.detail); + } + if (data.speedLimit != null) { + message.speedLimit = data.speedLimit; + } + return message; + } + toObject() { + const data: { + device?: ReturnType; + detail?: ReturnType; + speedLimit?: number; + } = {}; + if (this.device != null) { + data.device = this.device.toObject(); + } + if (this.detail != null) { + data.detail = this.detail.toObject(); + } + if (this.speedLimit != null) { + data.speedLimit = this.speedLimit; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_device) + writer.writeMessage(1, this.device, () => this.device.serialize(writer)); + if (this.has_detail) + writer.writeMessage(2, this.detail, () => this.detail.serialize(writer)); + if (this.speedLimit != 0) + writer.writeFloat(3, this.speedLimit); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Switch { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Switch(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.device, () => message.device = Device.deserialize(reader)); + break; + case 2: + reader.readMessage(message.detail, () => message.detail = DeviceDetail.deserialize(reader)); + break; + case 3: + message.speedLimit = reader.readFloat(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Switch { + return Switch.deserialize(bytes); + } +} diff --git a/src/protos/LineNetTrainOffset.ts b/src/protos/LineNetTrainOffset.ts new file mode 100644 index 0000000..5b99242 --- /dev/null +++ b/src/protos/LineNetTrainOffset.ts @@ -0,0 +1,234 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: LineNetTrainOffset.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export class LineNetTrainOffset extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + groupId?: string; + dir?: number; + show?: boolean; + windowNo?: number; + windowOffset?: number; + destinationId?: string; + backId?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + if ("dir" in data && data.dir != undefined) { + this.dir = data.dir; + } + if ("show" in data && data.show != undefined) { + this.show = data.show; + } + if ("windowNo" in data && data.windowNo != undefined) { + this.windowNo = data.windowNo; + } + if ("windowOffset" in data && data.windowOffset != undefined) { + this.windowOffset = data.windowOffset; + } + if ("destinationId" in data && data.destinationId != undefined) { + this.destinationId = data.destinationId; + } + if ("backId" in data && data.backId != undefined) { + this.backId = data.backId; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 2, value); + } + get dir() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set dir(value: number) { + pb_1.Message.setField(this, 3, value); + } + get show() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set show(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get windowNo() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set windowNo(value: number) { + pb_1.Message.setField(this, 5, value); + } + get windowOffset() { + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; + } + set windowOffset(value: number) { + pb_1.Message.setField(this, 6, value); + } + get destinationId() { + return pb_1.Message.getFieldWithDefault(this, 7, "") as string; + } + set destinationId(value: string) { + pb_1.Message.setField(this, 7, value); + } + get backId() { + return pb_1.Message.getFieldWithDefault(this, 8, "") as string; + } + set backId(value: string) { + pb_1.Message.setField(this, 8, value); + } + static fromObject(data: { + lineId?: number; + groupId?: string; + dir?: number; + show?: boolean; + windowNo?: number; + windowOffset?: number; + destinationId?: string; + backId?: string; + }): LineNetTrainOffset { + const message = new LineNetTrainOffset({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + if (data.dir != null) { + message.dir = data.dir; + } + if (data.show != null) { + message.show = data.show; + } + if (data.windowNo != null) { + message.windowNo = data.windowNo; + } + if (data.windowOffset != null) { + message.windowOffset = data.windowOffset; + } + if (data.destinationId != null) { + message.destinationId = data.destinationId; + } + if (data.backId != null) { + message.backId = data.backId; + } + return message; + } + toObject() { + const data: { + lineId?: number; + groupId?: string; + dir?: number; + show?: boolean; + windowNo?: number; + windowOffset?: number; + destinationId?: string; + backId?: string; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + if (this.dir != null) { + data.dir = this.dir; + } + if (this.show != null) { + data.show = this.show; + } + if (this.windowNo != null) { + data.windowNo = this.windowNo; + } + if (this.windowOffset != null) { + data.windowOffset = this.windowOffset; + } + if (this.destinationId != null) { + data.destinationId = this.destinationId; + } + if (this.backId != null) { + data.backId = this.backId; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.groupId.length) + writer.writeString(2, this.groupId); + if (this.dir != 0) + writer.writeInt32(3, this.dir); + if (this.show != false) + writer.writeBool(4, this.show); + if (this.windowNo != 0) + writer.writeInt32(5, this.windowNo); + if (this.windowOffset != 0) + writer.writeInt32(6, this.windowOffset); + if (this.destinationId.length) + writer.writeString(7, this.destinationId); + if (this.backId.length) + writer.writeString(8, this.backId); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): LineNetTrainOffset { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new LineNetTrainOffset(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.groupId = reader.readString(); + break; + case 3: + message.dir = reader.readInt32(); + break; + case 4: + message.show = reader.readBool(); + break; + case 5: + message.windowNo = reader.readInt32(); + break; + case 6: + message.windowOffset = reader.readInt32(); + break; + case 7: + message.destinationId = reader.readString(); + break; + case 8: + message.backId = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): LineNetTrainOffset { + return LineNetTrainOffset.deserialize(bytes); + } +} diff --git a/src/protos/LineNetTrainOffsetDiagram.ts b/src/protos/LineNetTrainOffsetDiagram.ts new file mode 100644 index 0000000..392c1e5 --- /dev/null +++ b/src/protos/LineNetTrainOffsetDiagram.ts @@ -0,0 +1,236 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: LineNetTrainOffsetDiagram.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export namespace diagram { + export class LineNetTrainOffsetDiagram extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + groupId?: string; + dir?: number; + show?: boolean; + windowNo?: number; + windowOffset?: number; + destinationId?: string; + backId?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + if ("dir" in data && data.dir != undefined) { + this.dir = data.dir; + } + if ("show" in data && data.show != undefined) { + this.show = data.show; + } + if ("windowNo" in data && data.windowNo != undefined) { + this.windowNo = data.windowNo; + } + if ("windowOffset" in data && data.windowOffset != undefined) { + this.windowOffset = data.windowOffset; + } + if ("destinationId" in data && data.destinationId != undefined) { + this.destinationId = data.destinationId; + } + if ("backId" in data && data.backId != undefined) { + this.backId = data.backId; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 2, value); + } + get dir() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set dir(value: number) { + pb_1.Message.setField(this, 3, value); + } + get show() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set show(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get windowNo() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set windowNo(value: number) { + pb_1.Message.setField(this, 5, value); + } + get windowOffset() { + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; + } + set windowOffset(value: number) { + pb_1.Message.setField(this, 6, value); + } + get destinationId() { + return pb_1.Message.getFieldWithDefault(this, 7, "") as string; + } + set destinationId(value: string) { + pb_1.Message.setField(this, 7, value); + } + get backId() { + return pb_1.Message.getFieldWithDefault(this, 8, "") as string; + } + set backId(value: string) { + pb_1.Message.setField(this, 8, value); + } + static fromObject(data: { + lineId?: number; + groupId?: string; + dir?: number; + show?: boolean; + windowNo?: number; + windowOffset?: number; + destinationId?: string; + backId?: string; + }): LineNetTrainOffsetDiagram { + const message = new LineNetTrainOffsetDiagram({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + if (data.dir != null) { + message.dir = data.dir; + } + if (data.show != null) { + message.show = data.show; + } + if (data.windowNo != null) { + message.windowNo = data.windowNo; + } + if (data.windowOffset != null) { + message.windowOffset = data.windowOffset; + } + if (data.destinationId != null) { + message.destinationId = data.destinationId; + } + if (data.backId != null) { + message.backId = data.backId; + } + return message; + } + toObject() { + const data: { + lineId?: number; + groupId?: string; + dir?: number; + show?: boolean; + windowNo?: number; + windowOffset?: number; + destinationId?: string; + backId?: string; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + if (this.dir != null) { + data.dir = this.dir; + } + if (this.show != null) { + data.show = this.show; + } + if (this.windowNo != null) { + data.windowNo = this.windowNo; + } + if (this.windowOffset != null) { + data.windowOffset = this.windowOffset; + } + if (this.destinationId != null) { + data.destinationId = this.destinationId; + } + if (this.backId != null) { + data.backId = this.backId; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.groupId.length) + writer.writeString(2, this.groupId); + if (this.dir != 0) + writer.writeInt32(3, this.dir); + if (this.show != false) + writer.writeBool(4, this.show); + if (this.windowNo != 0) + writer.writeInt32(5, this.windowNo); + if (this.windowOffset != 0) + writer.writeInt32(6, this.windowOffset); + if (this.destinationId.length) + writer.writeString(7, this.destinationId); + if (this.backId.length) + writer.writeString(8, this.backId); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): LineNetTrainOffsetDiagram { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new LineNetTrainOffsetDiagram(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.groupId = reader.readString(); + break; + case 3: + message.dir = reader.readInt32(); + break; + case 4: + message.show = reader.readBool(); + break; + case 5: + message.windowNo = reader.readInt32(); + break; + case 6: + message.windowOffset = reader.readInt32(); + break; + case 7: + message.destinationId = reader.readString(); + break; + case 8: + message.backId = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): LineNetTrainOffsetDiagram { + return LineNetTrainOffsetDiagram.deserialize(bytes); + } + } +} diff --git a/src/protos/device_info.ts b/src/protos/device_info.ts new file mode 100644 index 0000000..baa1e88 --- /dev/null +++ b/src/protos/device_info.ts @@ -0,0 +1,327 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: device_info.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as dependency_1 from "./stationLayoutGraphics"; +import * as pb_1 from "google-protobuf"; +export namespace state { + export class Section extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + id?: string; + code?: string; + type?: dependency_1.graphicData.Section.SectionType; + children?: Section[]; + kilometerSystem?: dependency_1.graphicData.KilometerSystem[]; + convertKilometer?: number[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [4, 5, 7], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("type" in data && data.type != undefined) { + this.type = data.type; + } + if ("children" in data && data.children != undefined) { + this.children = data.children; + } + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; + } + if ("convertKilometer" in data && data.convertKilometer != undefined) { + this.convertKilometer = data.convertKilometer; + } + } + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 1, value); + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get type() { + return pb_1.Message.getFieldWithDefault(this, 3, dependency_1.graphicData.Section.SectionType.Physical) as dependency_1.graphicData.Section.SectionType; + } + set type(value: dependency_1.graphicData.Section.SectionType) { + pb_1.Message.setField(this, 3, value); + } + get children() { + return pb_1.Message.getRepeatedWrapperField(this, Section, 4) as Section[]; + } + set children(value: Section[]) { + pb_1.Message.setRepeatedWrapperField(this, 4, value); + } + get kilometerSystem() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.graphicData.KilometerSystem, 5) as dependency_1.graphicData.KilometerSystem[]; + } + set kilometerSystem(value: dependency_1.graphicData.KilometerSystem[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } + get convertKilometer() { + return pb_1.Message.getFieldWithDefault(this, 7, []) as number[]; + } + set convertKilometer(value: number[]) { + pb_1.Message.setField(this, 7, value); + } + static fromObject(data: { + id?: string; + code?: string; + type?: dependency_1.graphicData.Section.SectionType; + children?: ReturnType[]; + kilometerSystem?: ReturnType[]; + convertKilometer?: number[]; + }): Section { + const message = new Section({}); + if (data.id != null) { + message.id = data.id; + } + if (data.code != null) { + message.code = data.code; + } + if (data.type != null) { + message.type = data.type; + } + if (data.children != null) { + message.children = data.children.map(item => Section.fromObject(item)); + } + if (data.kilometerSystem != null) { + message.kilometerSystem = data.kilometerSystem.map(item => dependency_1.graphicData.KilometerSystem.fromObject(item)); + } + if (data.convertKilometer != null) { + message.convertKilometer = data.convertKilometer; + } + return message; + } + toObject() { + const data: { + id?: string; + code?: string; + type?: dependency_1.graphicData.Section.SectionType; + children?: ReturnType[]; + kilometerSystem?: ReturnType[]; + convertKilometer?: number[]; + } = {}; + if (this.id != null) { + data.id = this.id; + } + if (this.code != null) { + data.code = this.code; + } + if (this.type != null) { + data.type = this.type; + } + if (this.children != null) { + data.children = this.children.map((item: Section) => item.toObject()); + } + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.map((item: dependency_1.graphicData.KilometerSystem) => item.toObject()); + } + if (this.convertKilometer != null) { + data.convertKilometer = this.convertKilometer; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.id.length) + writer.writeString(1, this.id); + if (this.code.length) + writer.writeString(2, this.code); + if (this.type != dependency_1.graphicData.Section.SectionType.Physical) + writer.writeEnum(3, this.type); + if (this.children.length) + writer.writeRepeatedMessage(4, this.children, (item: Section) => item.serialize(writer)); + if (this.kilometerSystem.length) + writer.writeRepeatedMessage(5, this.kilometerSystem, (item: dependency_1.graphicData.KilometerSystem) => item.serialize(writer)); + if (this.convertKilometer.length) + writer.writePackedInt64(7, this.convertKilometer); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Section { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Section(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.id = reader.readString(); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.type = reader.readEnum(); + break; + case 4: + reader.readMessage(message.children, () => pb_1.Message.addToRepeatedWrapperField(message, 4, Section.deserialize(reader), Section)); + break; + case 5: + reader.readMessage(message.kilometerSystem, () => pb_1.Message.addToRepeatedWrapperField(message, 5, dependency_1.graphicData.KilometerSystem.deserialize(reader), dependency_1.graphicData.KilometerSystem)); + break; + case 7: + message.convertKilometer = reader.readPackedInt64(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Section { + return Section.deserialize(bytes); + } + } + export class Switch extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + id?: string; + code?: string; + kilometerSystem?: dependency_1.graphicData.KilometerSystem[]; + convertKilometer?: number[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [3, 4], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; + } + if ("convertKilometer" in data && data.convertKilometer != undefined) { + this.convertKilometer = data.convertKilometer; + } + } + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 1, value); + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get kilometerSystem() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.graphicData.KilometerSystem, 3) as dependency_1.graphicData.KilometerSystem[]; + } + set kilometerSystem(value: dependency_1.graphicData.KilometerSystem[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); + } + get convertKilometer() { + return pb_1.Message.getFieldWithDefault(this, 4, []) as number[]; + } + set convertKilometer(value: number[]) { + pb_1.Message.setField(this, 4, value); + } + static fromObject(data: { + id?: string; + code?: string; + kilometerSystem?: ReturnType[]; + convertKilometer?: number[]; + }): Switch { + const message = new Switch({}); + if (data.id != null) { + message.id = data.id; + } + if (data.code != null) { + message.code = data.code; + } + if (data.kilometerSystem != null) { + message.kilometerSystem = data.kilometerSystem.map(item => dependency_1.graphicData.KilometerSystem.fromObject(item)); + } + if (data.convertKilometer != null) { + message.convertKilometer = data.convertKilometer; + } + return message; + } + toObject() { + const data: { + id?: string; + code?: string; + kilometerSystem?: ReturnType[]; + convertKilometer?: number[]; + } = {}; + if (this.id != null) { + data.id = this.id; + } + if (this.code != null) { + data.code = this.code; + } + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.map((item: dependency_1.graphicData.KilometerSystem) => item.toObject()); + } + if (this.convertKilometer != null) { + data.convertKilometer = this.convertKilometer; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.id.length) + writer.writeString(1, this.id); + if (this.code.length) + writer.writeString(2, this.code); + if (this.kilometerSystem.length) + writer.writeRepeatedMessage(3, this.kilometerSystem, (item: dependency_1.graphicData.KilometerSystem) => item.serialize(writer)); + if (this.convertKilometer.length) + writer.writePackedInt64(4, this.convertKilometer); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Switch { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Switch(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.id = reader.readString(); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + reader.readMessage(message.kilometerSystem, () => pb_1.Message.addToRepeatedWrapperField(message, 3, dependency_1.graphicData.KilometerSystem.deserialize(reader), dependency_1.graphicData.KilometerSystem)); + break; + case 4: + message.convertKilometer = reader.readPackedInt64(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Switch { + return Switch.deserialize(bytes); + } + } +} diff --git a/src/protos/device_status.ts b/src/protos/device_status.ts new file mode 100644 index 0000000..0aecd19 --- /dev/null +++ b/src/protos/device_status.ts @@ -0,0 +1,4489 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: device_status.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export namespace state { + export enum DeviceType { + UNKNOW = 0, + RTU = 1, + STATION = 2, + SIGNAL = 3, + SWITCH = 4, + TRACK = 5, + ENTRY = 6, + PLATFORM = 7, + SCADA = 8, + WATERPROOF_DOOR = 9, + WORK_AREA = 10, + GAMA = 11 + } + export class Rtu extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ipRtuStusDown?: boolean; + ipRtuStusInLocalCtrl?: boolean; + ipRtuStusInCentralCtrl?: boolean; + ipRtuStusInEmergencyCtrl?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ipRtuStusDown" in data && data.ipRtuStusDown != undefined) { + this.ipRtuStusDown = data.ipRtuStusDown; + } + if ("ipRtuStusInLocalCtrl" in data && data.ipRtuStusInLocalCtrl != undefined) { + this.ipRtuStusInLocalCtrl = data.ipRtuStusInLocalCtrl; + } + if ("ipRtuStusInCentralCtrl" in data && data.ipRtuStusInCentralCtrl != undefined) { + this.ipRtuStusInCentralCtrl = data.ipRtuStusInCentralCtrl; + } + if ("ipRtuStusInEmergencyCtrl" in data && data.ipRtuStusInEmergencyCtrl != undefined) { + this.ipRtuStusInEmergencyCtrl = data.ipRtuStusInEmergencyCtrl; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get ipRtuStusDown() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ipRtuStusDown(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get ipRtuStusInLocalCtrl() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set ipRtuStusInLocalCtrl(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get ipRtuStusInCentralCtrl() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set ipRtuStusInCentralCtrl(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get ipRtuStusInEmergencyCtrl() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set ipRtuStusInEmergencyCtrl(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 5, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 5, value); + } + static fromObject(data: { + ipRtuStusDown?: boolean; + ipRtuStusInLocalCtrl?: boolean; + ipRtuStusInCentralCtrl?: boolean; + ipRtuStusInEmergencyCtrl?: boolean; + id?: string; + }): Rtu { + const message = new Rtu({}); + if (data.ipRtuStusDown != null) { + message.ipRtuStusDown = data.ipRtuStusDown; + } + if (data.ipRtuStusInLocalCtrl != null) { + message.ipRtuStusInLocalCtrl = data.ipRtuStusInLocalCtrl; + } + if (data.ipRtuStusInCentralCtrl != null) { + message.ipRtuStusInCentralCtrl = data.ipRtuStusInCentralCtrl; + } + if (data.ipRtuStusInEmergencyCtrl != null) { + message.ipRtuStusInEmergencyCtrl = data.ipRtuStusInEmergencyCtrl; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + ipRtuStusDown?: boolean; + ipRtuStusInLocalCtrl?: boolean; + ipRtuStusInCentralCtrl?: boolean; + ipRtuStusInEmergencyCtrl?: boolean; + id?: string; + } = {}; + if (this.ipRtuStusDown != null) { + data.ipRtuStusDown = this.ipRtuStusDown; + } + if (this.ipRtuStusInLocalCtrl != null) { + data.ipRtuStusInLocalCtrl = this.ipRtuStusInLocalCtrl; + } + if (this.ipRtuStusInCentralCtrl != null) { + data.ipRtuStusInCentralCtrl = this.ipRtuStusInCentralCtrl; + } + if (this.ipRtuStusInEmergencyCtrl != null) { + data.ipRtuStusInEmergencyCtrl = this.ipRtuStusInEmergencyCtrl; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ipRtuStusDown != false) + writer.writeBool(1, this.ipRtuStusDown); + if (this.ipRtuStusInLocalCtrl != false) + writer.writeBool(2, this.ipRtuStusInLocalCtrl); + if (this.ipRtuStusInCentralCtrl != false) + writer.writeBool(3, this.ipRtuStusInCentralCtrl); + if (this.ipRtuStusInEmergencyCtrl != false) + writer.writeBool(4, this.ipRtuStusInEmergencyCtrl); + if (this.id.length) + writer.writeString(5, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Rtu { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Rtu(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ipRtuStusDown = reader.readBool(); + break; + case 2: + message.ipRtuStusInLocalCtrl = reader.readBool(); + break; + case 3: + message.ipRtuStusInCentralCtrl = reader.readBool(); + break; + case 4: + message.ipRtuStusInEmergencyCtrl = reader.readBool(); + break; + case 5: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Rtu { + return Rtu.deserialize(bytes); + } + } + export class Station extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ipStaStusTermMode1?: boolean; + ipStaStusTermMode2?: boolean; + ipStaStusTermMode3?: boolean; + ipStaStusTermMode4?: boolean; + ipStaStusTermMode5?: boolean; + ipStaStusTermMode6?: boolean; + ipStaStusExpectTermMode1?: boolean; + ipStaStusExpectTermMode2?: boolean; + ipStaStusExpectTermMode3?: boolean; + ipStaStusExpectTermMode4?: boolean; + ipStaStusExpectTermMode5?: boolean; + ipStaStusExpectTermMode6?: boolean; + ipStaStusInCycle1?: boolean; + ipStaStusInCycle2?: boolean; + ipStaStusInCycle3?: boolean; + ipStaStusInCycle4?: boolean; + ipStaStusInCycle5?: boolean; + ipStaStusInCycle6?: boolean; + ipStaStusExpectCycle1?: boolean; + ipStaStusExpectCycle2?: boolean; + ipStaStusExpectCycle3?: boolean; + ipStaStusExpectCycle4?: boolean; + ipStaStusExpectCycle5?: boolean; + ipStaStusExpectCycle6?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ipStaStusTermMode1" in data && data.ipStaStusTermMode1 != undefined) { + this.ipStaStusTermMode1 = data.ipStaStusTermMode1; + } + if ("ipStaStusTermMode2" in data && data.ipStaStusTermMode2 != undefined) { + this.ipStaStusTermMode2 = data.ipStaStusTermMode2; + } + if ("ipStaStusTermMode3" in data && data.ipStaStusTermMode3 != undefined) { + this.ipStaStusTermMode3 = data.ipStaStusTermMode3; + } + if ("ipStaStusTermMode4" in data && data.ipStaStusTermMode4 != undefined) { + this.ipStaStusTermMode4 = data.ipStaStusTermMode4; + } + if ("ipStaStusTermMode5" in data && data.ipStaStusTermMode5 != undefined) { + this.ipStaStusTermMode5 = data.ipStaStusTermMode5; + } + if ("ipStaStusTermMode6" in data && data.ipStaStusTermMode6 != undefined) { + this.ipStaStusTermMode6 = data.ipStaStusTermMode6; + } + if ("ipStaStusExpectTermMode1" in data && data.ipStaStusExpectTermMode1 != undefined) { + this.ipStaStusExpectTermMode1 = data.ipStaStusExpectTermMode1; + } + if ("ipStaStusExpectTermMode2" in data && data.ipStaStusExpectTermMode2 != undefined) { + this.ipStaStusExpectTermMode2 = data.ipStaStusExpectTermMode2; + } + if ("ipStaStusExpectTermMode3" in data && data.ipStaStusExpectTermMode3 != undefined) { + this.ipStaStusExpectTermMode3 = data.ipStaStusExpectTermMode3; + } + if ("ipStaStusExpectTermMode4" in data && data.ipStaStusExpectTermMode4 != undefined) { + this.ipStaStusExpectTermMode4 = data.ipStaStusExpectTermMode4; + } + if ("ipStaStusExpectTermMode5" in data && data.ipStaStusExpectTermMode5 != undefined) { + this.ipStaStusExpectTermMode5 = data.ipStaStusExpectTermMode5; + } + if ("ipStaStusExpectTermMode6" in data && data.ipStaStusExpectTermMode6 != undefined) { + this.ipStaStusExpectTermMode6 = data.ipStaStusExpectTermMode6; + } + if ("ipStaStusInCycle1" in data && data.ipStaStusInCycle1 != undefined) { + this.ipStaStusInCycle1 = data.ipStaStusInCycle1; + } + if ("ipStaStusInCycle2" in data && data.ipStaStusInCycle2 != undefined) { + this.ipStaStusInCycle2 = data.ipStaStusInCycle2; + } + if ("ipStaStusInCycle3" in data && data.ipStaStusInCycle3 != undefined) { + this.ipStaStusInCycle3 = data.ipStaStusInCycle3; + } + if ("ipStaStusInCycle4" in data && data.ipStaStusInCycle4 != undefined) { + this.ipStaStusInCycle4 = data.ipStaStusInCycle4; + } + if ("ipStaStusInCycle5" in data && data.ipStaStusInCycle5 != undefined) { + this.ipStaStusInCycle5 = data.ipStaStusInCycle5; + } + if ("ipStaStusInCycle6" in data && data.ipStaStusInCycle6 != undefined) { + this.ipStaStusInCycle6 = data.ipStaStusInCycle6; + } + if ("ipStaStusExpectCycle1" in data && data.ipStaStusExpectCycle1 != undefined) { + this.ipStaStusExpectCycle1 = data.ipStaStusExpectCycle1; + } + if ("ipStaStusExpectCycle2" in data && data.ipStaStusExpectCycle2 != undefined) { + this.ipStaStusExpectCycle2 = data.ipStaStusExpectCycle2; + } + if ("ipStaStusExpectCycle3" in data && data.ipStaStusExpectCycle3 != undefined) { + this.ipStaStusExpectCycle3 = data.ipStaStusExpectCycle3; + } + if ("ipStaStusExpectCycle4" in data && data.ipStaStusExpectCycle4 != undefined) { + this.ipStaStusExpectCycle4 = data.ipStaStusExpectCycle4; + } + if ("ipStaStusExpectCycle5" in data && data.ipStaStusExpectCycle5 != undefined) { + this.ipStaStusExpectCycle5 = data.ipStaStusExpectCycle5; + } + if ("ipStaStusExpectCycle6" in data && data.ipStaStusExpectCycle6 != undefined) { + this.ipStaStusExpectCycle6 = data.ipStaStusExpectCycle6; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get ipStaStusTermMode1() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ipStaStusTermMode1(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get ipStaStusTermMode2() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set ipStaStusTermMode2(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get ipStaStusTermMode3() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set ipStaStusTermMode3(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get ipStaStusTermMode4() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set ipStaStusTermMode4(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get ipStaStusTermMode5() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set ipStaStusTermMode5(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get ipStaStusTermMode6() { + return pb_1.Message.getFieldWithDefault(this, 6, false) as boolean; + } + set ipStaStusTermMode6(value: boolean) { + pb_1.Message.setField(this, 6, value); + } + get ipStaStusExpectTermMode1() { + return pb_1.Message.getFieldWithDefault(this, 7, false) as boolean; + } + set ipStaStusExpectTermMode1(value: boolean) { + pb_1.Message.setField(this, 7, value); + } + get ipStaStusExpectTermMode2() { + return pb_1.Message.getFieldWithDefault(this, 8, false) as boolean; + } + set ipStaStusExpectTermMode2(value: boolean) { + pb_1.Message.setField(this, 8, value); + } + get ipStaStusExpectTermMode3() { + return pb_1.Message.getFieldWithDefault(this, 9, false) as boolean; + } + set ipStaStusExpectTermMode3(value: boolean) { + pb_1.Message.setField(this, 9, value); + } + get ipStaStusExpectTermMode4() { + return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean; + } + set ipStaStusExpectTermMode4(value: boolean) { + pb_1.Message.setField(this, 10, value); + } + get ipStaStusExpectTermMode5() { + return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean; + } + set ipStaStusExpectTermMode5(value: boolean) { + pb_1.Message.setField(this, 11, value); + } + get ipStaStusExpectTermMode6() { + return pb_1.Message.getFieldWithDefault(this, 12, false) as boolean; + } + set ipStaStusExpectTermMode6(value: boolean) { + pb_1.Message.setField(this, 12, value); + } + get ipStaStusInCycle1() { + return pb_1.Message.getFieldWithDefault(this, 13, false) as boolean; + } + set ipStaStusInCycle1(value: boolean) { + pb_1.Message.setField(this, 13, value); + } + get ipStaStusInCycle2() { + return pb_1.Message.getFieldWithDefault(this, 14, false) as boolean; + } + set ipStaStusInCycle2(value: boolean) { + pb_1.Message.setField(this, 14, value); + } + get ipStaStusInCycle3() { + return pb_1.Message.getFieldWithDefault(this, 15, false) as boolean; + } + set ipStaStusInCycle3(value: boolean) { + pb_1.Message.setField(this, 15, value); + } + get ipStaStusInCycle4() { + return pb_1.Message.getFieldWithDefault(this, 16, false) as boolean; + } + set ipStaStusInCycle4(value: boolean) { + pb_1.Message.setField(this, 16, value); + } + get ipStaStusInCycle5() { + return pb_1.Message.getFieldWithDefault(this, 17, false) as boolean; + } + set ipStaStusInCycle5(value: boolean) { + pb_1.Message.setField(this, 17, value); + } + get ipStaStusInCycle6() { + return pb_1.Message.getFieldWithDefault(this, 18, false) as boolean; + } + set ipStaStusInCycle6(value: boolean) { + pb_1.Message.setField(this, 18, value); + } + get ipStaStusExpectCycle1() { + return pb_1.Message.getFieldWithDefault(this, 19, false) as boolean; + } + set ipStaStusExpectCycle1(value: boolean) { + pb_1.Message.setField(this, 19, value); + } + get ipStaStusExpectCycle2() { + return pb_1.Message.getFieldWithDefault(this, 20, false) as boolean; + } + set ipStaStusExpectCycle2(value: boolean) { + pb_1.Message.setField(this, 20, value); + } + get ipStaStusExpectCycle3() { + return pb_1.Message.getFieldWithDefault(this, 21, false) as boolean; + } + set ipStaStusExpectCycle3(value: boolean) { + pb_1.Message.setField(this, 21, value); + } + get ipStaStusExpectCycle4() { + return pb_1.Message.getFieldWithDefault(this, 22, false) as boolean; + } + set ipStaStusExpectCycle4(value: boolean) { + pb_1.Message.setField(this, 22, value); + } + get ipStaStusExpectCycle5() { + return pb_1.Message.getFieldWithDefault(this, 23, false) as boolean; + } + set ipStaStusExpectCycle5(value: boolean) { + pb_1.Message.setField(this, 23, value); + } + get ipStaStusExpectCycle6() { + return pb_1.Message.getFieldWithDefault(this, 24, false) as boolean; + } + set ipStaStusExpectCycle6(value: boolean) { + pb_1.Message.setField(this, 24, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 25, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 25, value); + } + static fromObject(data: { + ipStaStusTermMode1?: boolean; + ipStaStusTermMode2?: boolean; + ipStaStusTermMode3?: boolean; + ipStaStusTermMode4?: boolean; + ipStaStusTermMode5?: boolean; + ipStaStusTermMode6?: boolean; + ipStaStusExpectTermMode1?: boolean; + ipStaStusExpectTermMode2?: boolean; + ipStaStusExpectTermMode3?: boolean; + ipStaStusExpectTermMode4?: boolean; + ipStaStusExpectTermMode5?: boolean; + ipStaStusExpectTermMode6?: boolean; + ipStaStusInCycle1?: boolean; + ipStaStusInCycle2?: boolean; + ipStaStusInCycle3?: boolean; + ipStaStusInCycle4?: boolean; + ipStaStusInCycle5?: boolean; + ipStaStusInCycle6?: boolean; + ipStaStusExpectCycle1?: boolean; + ipStaStusExpectCycle2?: boolean; + ipStaStusExpectCycle3?: boolean; + ipStaStusExpectCycle4?: boolean; + ipStaStusExpectCycle5?: boolean; + ipStaStusExpectCycle6?: boolean; + id?: string; + }): Station { + const message = new Station({}); + if (data.ipStaStusTermMode1 != null) { + message.ipStaStusTermMode1 = data.ipStaStusTermMode1; + } + if (data.ipStaStusTermMode2 != null) { + message.ipStaStusTermMode2 = data.ipStaStusTermMode2; + } + if (data.ipStaStusTermMode3 != null) { + message.ipStaStusTermMode3 = data.ipStaStusTermMode3; + } + if (data.ipStaStusTermMode4 != null) { + message.ipStaStusTermMode4 = data.ipStaStusTermMode4; + } + if (data.ipStaStusTermMode5 != null) { + message.ipStaStusTermMode5 = data.ipStaStusTermMode5; + } + if (data.ipStaStusTermMode6 != null) { + message.ipStaStusTermMode6 = data.ipStaStusTermMode6; + } + if (data.ipStaStusExpectTermMode1 != null) { + message.ipStaStusExpectTermMode1 = data.ipStaStusExpectTermMode1; + } + if (data.ipStaStusExpectTermMode2 != null) { + message.ipStaStusExpectTermMode2 = data.ipStaStusExpectTermMode2; + } + if (data.ipStaStusExpectTermMode3 != null) { + message.ipStaStusExpectTermMode3 = data.ipStaStusExpectTermMode3; + } + if (data.ipStaStusExpectTermMode4 != null) { + message.ipStaStusExpectTermMode4 = data.ipStaStusExpectTermMode4; + } + if (data.ipStaStusExpectTermMode5 != null) { + message.ipStaStusExpectTermMode5 = data.ipStaStusExpectTermMode5; + } + if (data.ipStaStusExpectTermMode6 != null) { + message.ipStaStusExpectTermMode6 = data.ipStaStusExpectTermMode6; + } + if (data.ipStaStusInCycle1 != null) { + message.ipStaStusInCycle1 = data.ipStaStusInCycle1; + } + if (data.ipStaStusInCycle2 != null) { + message.ipStaStusInCycle2 = data.ipStaStusInCycle2; + } + if (data.ipStaStusInCycle3 != null) { + message.ipStaStusInCycle3 = data.ipStaStusInCycle3; + } + if (data.ipStaStusInCycle4 != null) { + message.ipStaStusInCycle4 = data.ipStaStusInCycle4; + } + if (data.ipStaStusInCycle5 != null) { + message.ipStaStusInCycle5 = data.ipStaStusInCycle5; + } + if (data.ipStaStusInCycle6 != null) { + message.ipStaStusInCycle6 = data.ipStaStusInCycle6; + } + if (data.ipStaStusExpectCycle1 != null) { + message.ipStaStusExpectCycle1 = data.ipStaStusExpectCycle1; + } + if (data.ipStaStusExpectCycle2 != null) { + message.ipStaStusExpectCycle2 = data.ipStaStusExpectCycle2; + } + if (data.ipStaStusExpectCycle3 != null) { + message.ipStaStusExpectCycle3 = data.ipStaStusExpectCycle3; + } + if (data.ipStaStusExpectCycle4 != null) { + message.ipStaStusExpectCycle4 = data.ipStaStusExpectCycle4; + } + if (data.ipStaStusExpectCycle5 != null) { + message.ipStaStusExpectCycle5 = data.ipStaStusExpectCycle5; + } + if (data.ipStaStusExpectCycle6 != null) { + message.ipStaStusExpectCycle6 = data.ipStaStusExpectCycle6; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + ipStaStusTermMode1?: boolean; + ipStaStusTermMode2?: boolean; + ipStaStusTermMode3?: boolean; + ipStaStusTermMode4?: boolean; + ipStaStusTermMode5?: boolean; + ipStaStusTermMode6?: boolean; + ipStaStusExpectTermMode1?: boolean; + ipStaStusExpectTermMode2?: boolean; + ipStaStusExpectTermMode3?: boolean; + ipStaStusExpectTermMode4?: boolean; + ipStaStusExpectTermMode5?: boolean; + ipStaStusExpectTermMode6?: boolean; + ipStaStusInCycle1?: boolean; + ipStaStusInCycle2?: boolean; + ipStaStusInCycle3?: boolean; + ipStaStusInCycle4?: boolean; + ipStaStusInCycle5?: boolean; + ipStaStusInCycle6?: boolean; + ipStaStusExpectCycle1?: boolean; + ipStaStusExpectCycle2?: boolean; + ipStaStusExpectCycle3?: boolean; + ipStaStusExpectCycle4?: boolean; + ipStaStusExpectCycle5?: boolean; + ipStaStusExpectCycle6?: boolean; + id?: string; + } = {}; + if (this.ipStaStusTermMode1 != null) { + data.ipStaStusTermMode1 = this.ipStaStusTermMode1; + } + if (this.ipStaStusTermMode2 != null) { + data.ipStaStusTermMode2 = this.ipStaStusTermMode2; + } + if (this.ipStaStusTermMode3 != null) { + data.ipStaStusTermMode3 = this.ipStaStusTermMode3; + } + if (this.ipStaStusTermMode4 != null) { + data.ipStaStusTermMode4 = this.ipStaStusTermMode4; + } + if (this.ipStaStusTermMode5 != null) { + data.ipStaStusTermMode5 = this.ipStaStusTermMode5; + } + if (this.ipStaStusTermMode6 != null) { + data.ipStaStusTermMode6 = this.ipStaStusTermMode6; + } + if (this.ipStaStusExpectTermMode1 != null) { + data.ipStaStusExpectTermMode1 = this.ipStaStusExpectTermMode1; + } + if (this.ipStaStusExpectTermMode2 != null) { + data.ipStaStusExpectTermMode2 = this.ipStaStusExpectTermMode2; + } + if (this.ipStaStusExpectTermMode3 != null) { + data.ipStaStusExpectTermMode3 = this.ipStaStusExpectTermMode3; + } + if (this.ipStaStusExpectTermMode4 != null) { + data.ipStaStusExpectTermMode4 = this.ipStaStusExpectTermMode4; + } + if (this.ipStaStusExpectTermMode5 != null) { + data.ipStaStusExpectTermMode5 = this.ipStaStusExpectTermMode5; + } + if (this.ipStaStusExpectTermMode6 != null) { + data.ipStaStusExpectTermMode6 = this.ipStaStusExpectTermMode6; + } + if (this.ipStaStusInCycle1 != null) { + data.ipStaStusInCycle1 = this.ipStaStusInCycle1; + } + if (this.ipStaStusInCycle2 != null) { + data.ipStaStusInCycle2 = this.ipStaStusInCycle2; + } + if (this.ipStaStusInCycle3 != null) { + data.ipStaStusInCycle3 = this.ipStaStusInCycle3; + } + if (this.ipStaStusInCycle4 != null) { + data.ipStaStusInCycle4 = this.ipStaStusInCycle4; + } + if (this.ipStaStusInCycle5 != null) { + data.ipStaStusInCycle5 = this.ipStaStusInCycle5; + } + if (this.ipStaStusInCycle6 != null) { + data.ipStaStusInCycle6 = this.ipStaStusInCycle6; + } + if (this.ipStaStusExpectCycle1 != null) { + data.ipStaStusExpectCycle1 = this.ipStaStusExpectCycle1; + } + if (this.ipStaStusExpectCycle2 != null) { + data.ipStaStusExpectCycle2 = this.ipStaStusExpectCycle2; + } + if (this.ipStaStusExpectCycle3 != null) { + data.ipStaStusExpectCycle3 = this.ipStaStusExpectCycle3; + } + if (this.ipStaStusExpectCycle4 != null) { + data.ipStaStusExpectCycle4 = this.ipStaStusExpectCycle4; + } + if (this.ipStaStusExpectCycle5 != null) { + data.ipStaStusExpectCycle5 = this.ipStaStusExpectCycle5; + } + if (this.ipStaStusExpectCycle6 != null) { + data.ipStaStusExpectCycle6 = this.ipStaStusExpectCycle6; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ipStaStusTermMode1 != false) + writer.writeBool(1, this.ipStaStusTermMode1); + if (this.ipStaStusTermMode2 != false) + writer.writeBool(2, this.ipStaStusTermMode2); + if (this.ipStaStusTermMode3 != false) + writer.writeBool(3, this.ipStaStusTermMode3); + if (this.ipStaStusTermMode4 != false) + writer.writeBool(4, this.ipStaStusTermMode4); + if (this.ipStaStusTermMode5 != false) + writer.writeBool(5, this.ipStaStusTermMode5); + if (this.ipStaStusTermMode6 != false) + writer.writeBool(6, this.ipStaStusTermMode6); + if (this.ipStaStusExpectTermMode1 != false) + writer.writeBool(7, this.ipStaStusExpectTermMode1); + if (this.ipStaStusExpectTermMode2 != false) + writer.writeBool(8, this.ipStaStusExpectTermMode2); + if (this.ipStaStusExpectTermMode3 != false) + writer.writeBool(9, this.ipStaStusExpectTermMode3); + if (this.ipStaStusExpectTermMode4 != false) + writer.writeBool(10, this.ipStaStusExpectTermMode4); + if (this.ipStaStusExpectTermMode5 != false) + writer.writeBool(11, this.ipStaStusExpectTermMode5); + if (this.ipStaStusExpectTermMode6 != false) + writer.writeBool(12, this.ipStaStusExpectTermMode6); + if (this.ipStaStusInCycle1 != false) + writer.writeBool(13, this.ipStaStusInCycle1); + if (this.ipStaStusInCycle2 != false) + writer.writeBool(14, this.ipStaStusInCycle2); + if (this.ipStaStusInCycle3 != false) + writer.writeBool(15, this.ipStaStusInCycle3); + if (this.ipStaStusInCycle4 != false) + writer.writeBool(16, this.ipStaStusInCycle4); + if (this.ipStaStusInCycle5 != false) + writer.writeBool(17, this.ipStaStusInCycle5); + if (this.ipStaStusInCycle6 != false) + writer.writeBool(18, this.ipStaStusInCycle6); + if (this.ipStaStusExpectCycle1 != false) + writer.writeBool(19, this.ipStaStusExpectCycle1); + if (this.ipStaStusExpectCycle2 != false) + writer.writeBool(20, this.ipStaStusExpectCycle2); + if (this.ipStaStusExpectCycle3 != false) + writer.writeBool(21, this.ipStaStusExpectCycle3); + if (this.ipStaStusExpectCycle4 != false) + writer.writeBool(22, this.ipStaStusExpectCycle4); + if (this.ipStaStusExpectCycle5 != false) + writer.writeBool(23, this.ipStaStusExpectCycle5); + if (this.ipStaStusExpectCycle6 != false) + writer.writeBool(24, this.ipStaStusExpectCycle6); + if (this.id.length) + writer.writeString(25, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Station { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Station(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ipStaStusTermMode1 = reader.readBool(); + break; + case 2: + message.ipStaStusTermMode2 = reader.readBool(); + break; + case 3: + message.ipStaStusTermMode3 = reader.readBool(); + break; + case 4: + message.ipStaStusTermMode4 = reader.readBool(); + break; + case 5: + message.ipStaStusTermMode5 = reader.readBool(); + break; + case 6: + message.ipStaStusTermMode6 = reader.readBool(); + break; + case 7: + message.ipStaStusExpectTermMode1 = reader.readBool(); + break; + case 8: + message.ipStaStusExpectTermMode2 = reader.readBool(); + break; + case 9: + message.ipStaStusExpectTermMode3 = reader.readBool(); + break; + case 10: + message.ipStaStusExpectTermMode4 = reader.readBool(); + break; + case 11: + message.ipStaStusExpectTermMode5 = reader.readBool(); + break; + case 12: + message.ipStaStusExpectTermMode6 = reader.readBool(); + break; + case 13: + message.ipStaStusInCycle1 = reader.readBool(); + break; + case 14: + message.ipStaStusInCycle2 = reader.readBool(); + break; + case 15: + message.ipStaStusInCycle3 = reader.readBool(); + break; + case 16: + message.ipStaStusInCycle4 = reader.readBool(); + break; + case 17: + message.ipStaStusInCycle5 = reader.readBool(); + break; + case 18: + message.ipStaStusInCycle6 = reader.readBool(); + break; + case 19: + message.ipStaStusExpectCycle1 = reader.readBool(); + break; + case 20: + message.ipStaStusExpectCycle2 = reader.readBool(); + break; + case 21: + message.ipStaStusExpectCycle3 = reader.readBool(); + break; + case 22: + message.ipStaStusExpectCycle4 = reader.readBool(); + break; + case 23: + message.ipStaStusExpectCycle5 = reader.readBool(); + break; + case 24: + message.ipStaStusExpectCycle6 = reader.readBool(); + break; + case 25: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Station { + return Station.deserialize(bytes); + } + } + export class Signal extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + redOpen?: boolean; + redFlash?: boolean; + greenOpen?: boolean; + greenFlash?: boolean; + yellowOpen?: boolean; + yellowFlash?: boolean; + whiteOpen?: boolean; + whiteFlash?: boolean; + blueOpen?: boolean; + blueFlash?: boolean; + fleetMode?: boolean; + ctrlFleetMode?: boolean; + autoMode?: boolean; + ctrlAutoMode?: boolean; + extinguish?: boolean; + approachLock?: boolean; + protectRoute?: boolean; + autoRouteDisable?: boolean; + callon?: boolean; + yellowYellow?: boolean; + yellowGreen?: boolean; + blocked?: boolean; + lampFailure?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("redOpen" in data && data.redOpen != undefined) { + this.redOpen = data.redOpen; + } + if ("redFlash" in data && data.redFlash != undefined) { + this.redFlash = data.redFlash; + } + if ("greenOpen" in data && data.greenOpen != undefined) { + this.greenOpen = data.greenOpen; + } + if ("greenFlash" in data && data.greenFlash != undefined) { + this.greenFlash = data.greenFlash; + } + if ("yellowOpen" in data && data.yellowOpen != undefined) { + this.yellowOpen = data.yellowOpen; + } + if ("yellowFlash" in data && data.yellowFlash != undefined) { + this.yellowFlash = data.yellowFlash; + } + if ("whiteOpen" in data && data.whiteOpen != undefined) { + this.whiteOpen = data.whiteOpen; + } + if ("whiteFlash" in data && data.whiteFlash != undefined) { + this.whiteFlash = data.whiteFlash; + } + if ("blueOpen" in data && data.blueOpen != undefined) { + this.blueOpen = data.blueOpen; + } + if ("blueFlash" in data && data.blueFlash != undefined) { + this.blueFlash = data.blueFlash; + } + if ("fleetMode" in data && data.fleetMode != undefined) { + this.fleetMode = data.fleetMode; + } + if ("ctrlFleetMode" in data && data.ctrlFleetMode != undefined) { + this.ctrlFleetMode = data.ctrlFleetMode; + } + if ("autoMode" in data && data.autoMode != undefined) { + this.autoMode = data.autoMode; + } + if ("ctrlAutoMode" in data && data.ctrlAutoMode != undefined) { + this.ctrlAutoMode = data.ctrlAutoMode; + } + if ("extinguish" in data && data.extinguish != undefined) { + this.extinguish = data.extinguish; + } + if ("approachLock" in data && data.approachLock != undefined) { + this.approachLock = data.approachLock; + } + if ("protectRoute" in data && data.protectRoute != undefined) { + this.protectRoute = data.protectRoute; + } + if ("autoRouteDisable" in data && data.autoRouteDisable != undefined) { + this.autoRouteDisable = data.autoRouteDisable; + } + if ("callon" in data && data.callon != undefined) { + this.callon = data.callon; + } + if ("yellowYellow" in data && data.yellowYellow != undefined) { + this.yellowYellow = data.yellowYellow; + } + if ("yellowGreen" in data && data.yellowGreen != undefined) { + this.yellowGreen = data.yellowGreen; + } + if ("blocked" in data && data.blocked != undefined) { + this.blocked = data.blocked; + } + if ("lampFailure" in data && data.lampFailure != undefined) { + this.lampFailure = data.lampFailure; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get redOpen() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set redOpen(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get redFlash() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set redFlash(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get greenOpen() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set greenOpen(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get greenFlash() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set greenFlash(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get yellowOpen() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set yellowOpen(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get yellowFlash() { + return pb_1.Message.getFieldWithDefault(this, 6, false) as boolean; + } + set yellowFlash(value: boolean) { + pb_1.Message.setField(this, 6, value); + } + get whiteOpen() { + return pb_1.Message.getFieldWithDefault(this, 7, false) as boolean; + } + set whiteOpen(value: boolean) { + pb_1.Message.setField(this, 7, value); + } + get whiteFlash() { + return pb_1.Message.getFieldWithDefault(this, 8, false) as boolean; + } + set whiteFlash(value: boolean) { + pb_1.Message.setField(this, 8, value); + } + get blueOpen() { + return pb_1.Message.getFieldWithDefault(this, 9, false) as boolean; + } + set blueOpen(value: boolean) { + pb_1.Message.setField(this, 9, value); + } + get blueFlash() { + return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean; + } + set blueFlash(value: boolean) { + pb_1.Message.setField(this, 10, value); + } + get fleetMode() { + return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean; + } + set fleetMode(value: boolean) { + pb_1.Message.setField(this, 11, value); + } + get ctrlFleetMode() { + return pb_1.Message.getFieldWithDefault(this, 12, false) as boolean; + } + set ctrlFleetMode(value: boolean) { + pb_1.Message.setField(this, 12, value); + } + get autoMode() { + return pb_1.Message.getFieldWithDefault(this, 13, false) as boolean; + } + set autoMode(value: boolean) { + pb_1.Message.setField(this, 13, value); + } + get ctrlAutoMode() { + return pb_1.Message.getFieldWithDefault(this, 14, false) as boolean; + } + set ctrlAutoMode(value: boolean) { + pb_1.Message.setField(this, 14, value); + } + get extinguish() { + return pb_1.Message.getFieldWithDefault(this, 15, false) as boolean; + } + set extinguish(value: boolean) { + pb_1.Message.setField(this, 15, value); + } + get approachLock() { + return pb_1.Message.getFieldWithDefault(this, 16, false) as boolean; + } + set approachLock(value: boolean) { + pb_1.Message.setField(this, 16, value); + } + get protectRoute() { + return pb_1.Message.getFieldWithDefault(this, 17, false) as boolean; + } + set protectRoute(value: boolean) { + pb_1.Message.setField(this, 17, value); + } + get autoRouteDisable() { + return pb_1.Message.getFieldWithDefault(this, 18, false) as boolean; + } + set autoRouteDisable(value: boolean) { + pb_1.Message.setField(this, 18, value); + } + get callon() { + return pb_1.Message.getFieldWithDefault(this, 19, false) as boolean; + } + set callon(value: boolean) { + pb_1.Message.setField(this, 19, value); + } + get yellowYellow() { + return pb_1.Message.getFieldWithDefault(this, 20, false) as boolean; + } + set yellowYellow(value: boolean) { + pb_1.Message.setField(this, 20, value); + } + get yellowGreen() { + return pb_1.Message.getFieldWithDefault(this, 21, false) as boolean; + } + set yellowGreen(value: boolean) { + pb_1.Message.setField(this, 21, value); + } + get blocked() { + return pb_1.Message.getFieldWithDefault(this, 22, false) as boolean; + } + set blocked(value: boolean) { + pb_1.Message.setField(this, 22, value); + } + get lampFailure() { + return pb_1.Message.getFieldWithDefault(this, 23, false) as boolean; + } + set lampFailure(value: boolean) { + pb_1.Message.setField(this, 23, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 24, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 24, value); + } + static fromObject(data: { + redOpen?: boolean; + redFlash?: boolean; + greenOpen?: boolean; + greenFlash?: boolean; + yellowOpen?: boolean; + yellowFlash?: boolean; + whiteOpen?: boolean; + whiteFlash?: boolean; + blueOpen?: boolean; + blueFlash?: boolean; + fleetMode?: boolean; + ctrlFleetMode?: boolean; + autoMode?: boolean; + ctrlAutoMode?: boolean; + extinguish?: boolean; + approachLock?: boolean; + protectRoute?: boolean; + autoRouteDisable?: boolean; + callon?: boolean; + yellowYellow?: boolean; + yellowGreen?: boolean; + blocked?: boolean; + lampFailure?: boolean; + id?: string; + }): Signal { + const message = new Signal({}); + if (data.redOpen != null) { + message.redOpen = data.redOpen; + } + if (data.redFlash != null) { + message.redFlash = data.redFlash; + } + if (data.greenOpen != null) { + message.greenOpen = data.greenOpen; + } + if (data.greenFlash != null) { + message.greenFlash = data.greenFlash; + } + if (data.yellowOpen != null) { + message.yellowOpen = data.yellowOpen; + } + if (data.yellowFlash != null) { + message.yellowFlash = data.yellowFlash; + } + if (data.whiteOpen != null) { + message.whiteOpen = data.whiteOpen; + } + if (data.whiteFlash != null) { + message.whiteFlash = data.whiteFlash; + } + if (data.blueOpen != null) { + message.blueOpen = data.blueOpen; + } + if (data.blueFlash != null) { + message.blueFlash = data.blueFlash; + } + if (data.fleetMode != null) { + message.fleetMode = data.fleetMode; + } + if (data.ctrlFleetMode != null) { + message.ctrlFleetMode = data.ctrlFleetMode; + } + if (data.autoMode != null) { + message.autoMode = data.autoMode; + } + if (data.ctrlAutoMode != null) { + message.ctrlAutoMode = data.ctrlAutoMode; + } + if (data.extinguish != null) { + message.extinguish = data.extinguish; + } + if (data.approachLock != null) { + message.approachLock = data.approachLock; + } + if (data.protectRoute != null) { + message.protectRoute = data.protectRoute; + } + if (data.autoRouteDisable != null) { + message.autoRouteDisable = data.autoRouteDisable; + } + if (data.callon != null) { + message.callon = data.callon; + } + if (data.yellowYellow != null) { + message.yellowYellow = data.yellowYellow; + } + if (data.yellowGreen != null) { + message.yellowGreen = data.yellowGreen; + } + if (data.blocked != null) { + message.blocked = data.blocked; + } + if (data.lampFailure != null) { + message.lampFailure = data.lampFailure; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + redOpen?: boolean; + redFlash?: boolean; + greenOpen?: boolean; + greenFlash?: boolean; + yellowOpen?: boolean; + yellowFlash?: boolean; + whiteOpen?: boolean; + whiteFlash?: boolean; + blueOpen?: boolean; + blueFlash?: boolean; + fleetMode?: boolean; + ctrlFleetMode?: boolean; + autoMode?: boolean; + ctrlAutoMode?: boolean; + extinguish?: boolean; + approachLock?: boolean; + protectRoute?: boolean; + autoRouteDisable?: boolean; + callon?: boolean; + yellowYellow?: boolean; + yellowGreen?: boolean; + blocked?: boolean; + lampFailure?: boolean; + id?: string; + } = {}; + if (this.redOpen != null) { + data.redOpen = this.redOpen; + } + if (this.redFlash != null) { + data.redFlash = this.redFlash; + } + if (this.greenOpen != null) { + data.greenOpen = this.greenOpen; + } + if (this.greenFlash != null) { + data.greenFlash = this.greenFlash; + } + if (this.yellowOpen != null) { + data.yellowOpen = this.yellowOpen; + } + if (this.yellowFlash != null) { + data.yellowFlash = this.yellowFlash; + } + if (this.whiteOpen != null) { + data.whiteOpen = this.whiteOpen; + } + if (this.whiteFlash != null) { + data.whiteFlash = this.whiteFlash; + } + if (this.blueOpen != null) { + data.blueOpen = this.blueOpen; + } + if (this.blueFlash != null) { + data.blueFlash = this.blueFlash; + } + if (this.fleetMode != null) { + data.fleetMode = this.fleetMode; + } + if (this.ctrlFleetMode != null) { + data.ctrlFleetMode = this.ctrlFleetMode; + } + if (this.autoMode != null) { + data.autoMode = this.autoMode; + } + if (this.ctrlAutoMode != null) { + data.ctrlAutoMode = this.ctrlAutoMode; + } + if (this.extinguish != null) { + data.extinguish = this.extinguish; + } + if (this.approachLock != null) { + data.approachLock = this.approachLock; + } + if (this.protectRoute != null) { + data.protectRoute = this.protectRoute; + } + if (this.autoRouteDisable != null) { + data.autoRouteDisable = this.autoRouteDisable; + } + if (this.callon != null) { + data.callon = this.callon; + } + if (this.yellowYellow != null) { + data.yellowYellow = this.yellowYellow; + } + if (this.yellowGreen != null) { + data.yellowGreen = this.yellowGreen; + } + if (this.blocked != null) { + data.blocked = this.blocked; + } + if (this.lampFailure != null) { + data.lampFailure = this.lampFailure; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.redOpen != false) + writer.writeBool(1, this.redOpen); + if (this.redFlash != false) + writer.writeBool(2, this.redFlash); + if (this.greenOpen != false) + writer.writeBool(3, this.greenOpen); + if (this.greenFlash != false) + writer.writeBool(4, this.greenFlash); + if (this.yellowOpen != false) + writer.writeBool(5, this.yellowOpen); + if (this.yellowFlash != false) + writer.writeBool(6, this.yellowFlash); + if (this.whiteOpen != false) + writer.writeBool(7, this.whiteOpen); + if (this.whiteFlash != false) + writer.writeBool(8, this.whiteFlash); + if (this.blueOpen != false) + writer.writeBool(9, this.blueOpen); + if (this.blueFlash != false) + writer.writeBool(10, this.blueFlash); + if (this.fleetMode != false) + writer.writeBool(11, this.fleetMode); + if (this.ctrlFleetMode != false) + writer.writeBool(12, this.ctrlFleetMode); + if (this.autoMode != false) + writer.writeBool(13, this.autoMode); + if (this.ctrlAutoMode != false) + writer.writeBool(14, this.ctrlAutoMode); + if (this.extinguish != false) + writer.writeBool(15, this.extinguish); + if (this.approachLock != false) + writer.writeBool(16, this.approachLock); + if (this.protectRoute != false) + writer.writeBool(17, this.protectRoute); + if (this.autoRouteDisable != false) + writer.writeBool(18, this.autoRouteDisable); + if (this.callon != false) + writer.writeBool(19, this.callon); + if (this.yellowYellow != false) + writer.writeBool(20, this.yellowYellow); + if (this.yellowGreen != false) + writer.writeBool(21, this.yellowGreen); + if (this.blocked != false) + writer.writeBool(22, this.blocked); + if (this.lampFailure != false) + writer.writeBool(23, this.lampFailure); + if (this.id.length) + writer.writeString(24, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Signal { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Signal(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.redOpen = reader.readBool(); + break; + case 2: + message.redFlash = reader.readBool(); + break; + case 3: + message.greenOpen = reader.readBool(); + break; + case 4: + message.greenFlash = reader.readBool(); + break; + case 5: + message.yellowOpen = reader.readBool(); + break; + case 6: + message.yellowFlash = reader.readBool(); + break; + case 7: + message.whiteOpen = reader.readBool(); + break; + case 8: + message.whiteFlash = reader.readBool(); + break; + case 9: + message.blueOpen = reader.readBool(); + break; + case 10: + message.blueFlash = reader.readBool(); + break; + case 11: + message.fleetMode = reader.readBool(); + break; + case 12: + message.ctrlFleetMode = reader.readBool(); + break; + case 13: + message.autoMode = reader.readBool(); + break; + case 14: + message.ctrlAutoMode = reader.readBool(); + break; + case 15: + message.extinguish = reader.readBool(); + break; + case 16: + message.approachLock = reader.readBool(); + break; + case 17: + message.protectRoute = reader.readBool(); + break; + case 18: + message.autoRouteDisable = reader.readBool(); + break; + case 19: + message.callon = reader.readBool(); + break; + case 20: + message.yellowYellow = reader.readBool(); + break; + case 21: + message.yellowGreen = reader.readBool(); + break; + case 22: + message.blocked = reader.readBool(); + break; + case 23: + message.lampFailure = reader.readBool(); + break; + case 24: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Signal { + return Signal.deserialize(bytes); + } + } + export class Entry extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + dirLeft?: boolean; + dirRight?: boolean; + dirLocked?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("dirLeft" in data && data.dirLeft != undefined) { + this.dirLeft = data.dirLeft; + } + if ("dirRight" in data && data.dirRight != undefined) { + this.dirRight = data.dirRight; + } + if ("dirLocked" in data && data.dirLocked != undefined) { + this.dirLocked = data.dirLocked; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get dirLeft() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set dirLeft(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get dirRight() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set dirRight(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get dirLocked() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set dirLocked(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 4, value); + } + static fromObject(data: { + dirLeft?: boolean; + dirRight?: boolean; + dirLocked?: boolean; + id?: string; + }): Entry { + const message = new Entry({}); + if (data.dirLeft != null) { + message.dirLeft = data.dirLeft; + } + if (data.dirRight != null) { + message.dirRight = data.dirRight; + } + if (data.dirLocked != null) { + message.dirLocked = data.dirLocked; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + dirLeft?: boolean; + dirRight?: boolean; + dirLocked?: boolean; + id?: string; + } = {}; + if (this.dirLeft != null) { + data.dirLeft = this.dirLeft; + } + if (this.dirRight != null) { + data.dirRight = this.dirRight; + } + if (this.dirLocked != null) { + data.dirLocked = this.dirLocked; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.dirLeft != false) + writer.writeBool(1, this.dirLeft); + if (this.dirRight != false) + writer.writeBool(2, this.dirRight); + if (this.dirLocked != false) + writer.writeBool(3, this.dirLocked); + if (this.id.length) + writer.writeString(4, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Entry { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Entry(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.dirLeft = reader.readBool(); + break; + case 2: + message.dirRight = reader.readBool(); + break; + case 3: + message.dirLocked = reader.readBool(); + break; + case 4: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Entry { + return Entry.deserialize(bytes); + } + } + export class Switch extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ipSingleSwitchStusCiOccupied?: boolean; + ipSingleSwitchStusCbtcOccupied?: boolean; + ipSingleSwitchStusLocked?: boolean; + ipSingleSwitchStusFailLocked?: boolean; + ipSingleSwitchStusNormal?: boolean; + ipSingleSwitchStusReverse?: boolean; + ipSingleSwitchStusBlocked1?: boolean; + ipSingleSwitchStusJammed?: boolean; + ipSingleSwitchStusExpectLock?: boolean; + ipSingleSwitchStusExpectUnlock?: boolean; + ipSingleSwitchStusExpectNormal?: boolean; + ipSingleSwitchStusExpectReverse?: boolean; + ipSingleSwitchStusExpectBlock?: boolean; + ipSingleSwitchStusExpectUnblock?: boolean; + ipSingleSwitchStusInRoute?: boolean; + ipSingleSwitchStusManualMode?: boolean; + ipSingleSwitchStusCut?: boolean; + ipSingleSwitchStusAtcInvalid?: boolean; + ipSingleSwitchStusOverlap?: boolean; + ipSingleSwitchStusTsrCbtcMain?: boolean; + ipSingleSwitchStusTsrCbtcNormal?: boolean; + ipSingleSwitchStusTsrCbtcReverse?: boolean; + ipSingleSwitchStusTsrBmMain?: boolean; + ipSingleSwitchStusTsrBmNormal?: boolean; + ipSingleSwitchStusTsrBmReverse?: boolean; + ipSingleSwitchStusBlocked2?: boolean; + ipSingleSwitchStusLostIndication?: boolean; + id?: string; + speedLimit?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ipSingleSwitchStusCiOccupied" in data && data.ipSingleSwitchStusCiOccupied != undefined) { + this.ipSingleSwitchStusCiOccupied = data.ipSingleSwitchStusCiOccupied; + } + if ("ipSingleSwitchStusCbtcOccupied" in data && data.ipSingleSwitchStusCbtcOccupied != undefined) { + this.ipSingleSwitchStusCbtcOccupied = data.ipSingleSwitchStusCbtcOccupied; + } + if ("ipSingleSwitchStusLocked" in data && data.ipSingleSwitchStusLocked != undefined) { + this.ipSingleSwitchStusLocked = data.ipSingleSwitchStusLocked; + } + if ("ipSingleSwitchStusFailLocked" in data && data.ipSingleSwitchStusFailLocked != undefined) { + this.ipSingleSwitchStusFailLocked = data.ipSingleSwitchStusFailLocked; + } + if ("ipSingleSwitchStusNormal" in data && data.ipSingleSwitchStusNormal != undefined) { + this.ipSingleSwitchStusNormal = data.ipSingleSwitchStusNormal; + } + if ("ipSingleSwitchStusReverse" in data && data.ipSingleSwitchStusReverse != undefined) { + this.ipSingleSwitchStusReverse = data.ipSingleSwitchStusReverse; + } + if ("ipSingleSwitchStusBlocked1" in data && data.ipSingleSwitchStusBlocked1 != undefined) { + this.ipSingleSwitchStusBlocked1 = data.ipSingleSwitchStusBlocked1; + } + if ("ipSingleSwitchStusJammed" in data && data.ipSingleSwitchStusJammed != undefined) { + this.ipSingleSwitchStusJammed = data.ipSingleSwitchStusJammed; + } + if ("ipSingleSwitchStusExpectLock" in data && data.ipSingleSwitchStusExpectLock != undefined) { + this.ipSingleSwitchStusExpectLock = data.ipSingleSwitchStusExpectLock; + } + if ("ipSingleSwitchStusExpectUnlock" in data && data.ipSingleSwitchStusExpectUnlock != undefined) { + this.ipSingleSwitchStusExpectUnlock = data.ipSingleSwitchStusExpectUnlock; + } + if ("ipSingleSwitchStusExpectNormal" in data && data.ipSingleSwitchStusExpectNormal != undefined) { + this.ipSingleSwitchStusExpectNormal = data.ipSingleSwitchStusExpectNormal; + } + if ("ipSingleSwitchStusExpectReverse" in data && data.ipSingleSwitchStusExpectReverse != undefined) { + this.ipSingleSwitchStusExpectReverse = data.ipSingleSwitchStusExpectReverse; + } + if ("ipSingleSwitchStusExpectBlock" in data && data.ipSingleSwitchStusExpectBlock != undefined) { + this.ipSingleSwitchStusExpectBlock = data.ipSingleSwitchStusExpectBlock; + } + if ("ipSingleSwitchStusExpectUnblock" in data && data.ipSingleSwitchStusExpectUnblock != undefined) { + this.ipSingleSwitchStusExpectUnblock = data.ipSingleSwitchStusExpectUnblock; + } + if ("ipSingleSwitchStusInRoute" in data && data.ipSingleSwitchStusInRoute != undefined) { + this.ipSingleSwitchStusInRoute = data.ipSingleSwitchStusInRoute; + } + if ("ipSingleSwitchStusManualMode" in data && data.ipSingleSwitchStusManualMode != undefined) { + this.ipSingleSwitchStusManualMode = data.ipSingleSwitchStusManualMode; + } + if ("ipSingleSwitchStusCut" in data && data.ipSingleSwitchStusCut != undefined) { + this.ipSingleSwitchStusCut = data.ipSingleSwitchStusCut; + } + if ("ipSingleSwitchStusAtcInvalid" in data && data.ipSingleSwitchStusAtcInvalid != undefined) { + this.ipSingleSwitchStusAtcInvalid = data.ipSingleSwitchStusAtcInvalid; + } + if ("ipSingleSwitchStusOverlap" in data && data.ipSingleSwitchStusOverlap != undefined) { + this.ipSingleSwitchStusOverlap = data.ipSingleSwitchStusOverlap; + } + if ("ipSingleSwitchStusTsrCbtcMain" in data && data.ipSingleSwitchStusTsrCbtcMain != undefined) { + this.ipSingleSwitchStusTsrCbtcMain = data.ipSingleSwitchStusTsrCbtcMain; + } + if ("ipSingleSwitchStusTsrCbtcNormal" in data && data.ipSingleSwitchStusTsrCbtcNormal != undefined) { + this.ipSingleSwitchStusTsrCbtcNormal = data.ipSingleSwitchStusTsrCbtcNormal; + } + if ("ipSingleSwitchStusTsrCbtcReverse" in data && data.ipSingleSwitchStusTsrCbtcReverse != undefined) { + this.ipSingleSwitchStusTsrCbtcReverse = data.ipSingleSwitchStusTsrCbtcReverse; + } + if ("ipSingleSwitchStusTsrBmMain" in data && data.ipSingleSwitchStusTsrBmMain != undefined) { + this.ipSingleSwitchStusTsrBmMain = data.ipSingleSwitchStusTsrBmMain; + } + if ("ipSingleSwitchStusTsrBmNormal" in data && data.ipSingleSwitchStusTsrBmNormal != undefined) { + this.ipSingleSwitchStusTsrBmNormal = data.ipSingleSwitchStusTsrBmNormal; + } + if ("ipSingleSwitchStusTsrBmReverse" in data && data.ipSingleSwitchStusTsrBmReverse != undefined) { + this.ipSingleSwitchStusTsrBmReverse = data.ipSingleSwitchStusTsrBmReverse; + } + if ("ipSingleSwitchStusBlocked2" in data && data.ipSingleSwitchStusBlocked2 != undefined) { + this.ipSingleSwitchStusBlocked2 = data.ipSingleSwitchStusBlocked2; + } + if ("ipSingleSwitchStusLostIndication" in data && data.ipSingleSwitchStusLostIndication != undefined) { + this.ipSingleSwitchStusLostIndication = data.ipSingleSwitchStusLostIndication; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("speedLimit" in data && data.speedLimit != undefined) { + this.speedLimit = data.speedLimit; + } + } + } + get ipSingleSwitchStusCiOccupied() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ipSingleSwitchStusCiOccupied(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get ipSingleSwitchStusCbtcOccupied() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set ipSingleSwitchStusCbtcOccupied(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get ipSingleSwitchStusLocked() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set ipSingleSwitchStusLocked(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get ipSingleSwitchStusFailLocked() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set ipSingleSwitchStusFailLocked(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get ipSingleSwitchStusNormal() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set ipSingleSwitchStusNormal(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get ipSingleSwitchStusReverse() { + return pb_1.Message.getFieldWithDefault(this, 6, false) as boolean; + } + set ipSingleSwitchStusReverse(value: boolean) { + pb_1.Message.setField(this, 6, value); + } + get ipSingleSwitchStusBlocked1() { + return pb_1.Message.getFieldWithDefault(this, 7, false) as boolean; + } + set ipSingleSwitchStusBlocked1(value: boolean) { + pb_1.Message.setField(this, 7, value); + } + get ipSingleSwitchStusJammed() { + return pb_1.Message.getFieldWithDefault(this, 8, false) as boolean; + } + set ipSingleSwitchStusJammed(value: boolean) { + pb_1.Message.setField(this, 8, value); + } + get ipSingleSwitchStusExpectLock() { + return pb_1.Message.getFieldWithDefault(this, 9, false) as boolean; + } + set ipSingleSwitchStusExpectLock(value: boolean) { + pb_1.Message.setField(this, 9, value); + } + get ipSingleSwitchStusExpectUnlock() { + return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean; + } + set ipSingleSwitchStusExpectUnlock(value: boolean) { + pb_1.Message.setField(this, 10, value); + } + get ipSingleSwitchStusExpectNormal() { + return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean; + } + set ipSingleSwitchStusExpectNormal(value: boolean) { + pb_1.Message.setField(this, 11, value); + } + get ipSingleSwitchStusExpectReverse() { + return pb_1.Message.getFieldWithDefault(this, 12, false) as boolean; + } + set ipSingleSwitchStusExpectReverse(value: boolean) { + pb_1.Message.setField(this, 12, value); + } + get ipSingleSwitchStusExpectBlock() { + return pb_1.Message.getFieldWithDefault(this, 13, false) as boolean; + } + set ipSingleSwitchStusExpectBlock(value: boolean) { + pb_1.Message.setField(this, 13, value); + } + get ipSingleSwitchStusExpectUnblock() { + return pb_1.Message.getFieldWithDefault(this, 14, false) as boolean; + } + set ipSingleSwitchStusExpectUnblock(value: boolean) { + pb_1.Message.setField(this, 14, value); + } + get ipSingleSwitchStusInRoute() { + return pb_1.Message.getFieldWithDefault(this, 15, false) as boolean; + } + set ipSingleSwitchStusInRoute(value: boolean) { + pb_1.Message.setField(this, 15, value); + } + get ipSingleSwitchStusManualMode() { + return pb_1.Message.getFieldWithDefault(this, 16, false) as boolean; + } + set ipSingleSwitchStusManualMode(value: boolean) { + pb_1.Message.setField(this, 16, value); + } + get ipSingleSwitchStusCut() { + return pb_1.Message.getFieldWithDefault(this, 17, false) as boolean; + } + set ipSingleSwitchStusCut(value: boolean) { + pb_1.Message.setField(this, 17, value); + } + get ipSingleSwitchStusAtcInvalid() { + return pb_1.Message.getFieldWithDefault(this, 18, false) as boolean; + } + set ipSingleSwitchStusAtcInvalid(value: boolean) { + pb_1.Message.setField(this, 18, value); + } + get ipSingleSwitchStusOverlap() { + return pb_1.Message.getFieldWithDefault(this, 19, false) as boolean; + } + set ipSingleSwitchStusOverlap(value: boolean) { + pb_1.Message.setField(this, 19, value); + } + get ipSingleSwitchStusTsrCbtcMain() { + return pb_1.Message.getFieldWithDefault(this, 20, false) as boolean; + } + set ipSingleSwitchStusTsrCbtcMain(value: boolean) { + pb_1.Message.setField(this, 20, value); + } + get ipSingleSwitchStusTsrCbtcNormal() { + return pb_1.Message.getFieldWithDefault(this, 21, false) as boolean; + } + set ipSingleSwitchStusTsrCbtcNormal(value: boolean) { + pb_1.Message.setField(this, 21, value); + } + get ipSingleSwitchStusTsrCbtcReverse() { + return pb_1.Message.getFieldWithDefault(this, 22, false) as boolean; + } + set ipSingleSwitchStusTsrCbtcReverse(value: boolean) { + pb_1.Message.setField(this, 22, value); + } + get ipSingleSwitchStusTsrBmMain() { + return pb_1.Message.getFieldWithDefault(this, 23, false) as boolean; + } + set ipSingleSwitchStusTsrBmMain(value: boolean) { + pb_1.Message.setField(this, 23, value); + } + get ipSingleSwitchStusTsrBmNormal() { + return pb_1.Message.getFieldWithDefault(this, 24, false) as boolean; + } + set ipSingleSwitchStusTsrBmNormal(value: boolean) { + pb_1.Message.setField(this, 24, value); + } + get ipSingleSwitchStusTsrBmReverse() { + return pb_1.Message.getFieldWithDefault(this, 25, false) as boolean; + } + set ipSingleSwitchStusTsrBmReverse(value: boolean) { + pb_1.Message.setField(this, 25, value); + } + get ipSingleSwitchStusBlocked2() { + return pb_1.Message.getFieldWithDefault(this, 26, false) as boolean; + } + set ipSingleSwitchStusBlocked2(value: boolean) { + pb_1.Message.setField(this, 26, value); + } + get ipSingleSwitchStusLostIndication() { + return pb_1.Message.getFieldWithDefault(this, 27, false) as boolean; + } + set ipSingleSwitchStusLostIndication(value: boolean) { + pb_1.Message.setField(this, 27, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 28, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 28, value); + } + get speedLimit() { + return pb_1.Message.getFieldWithDefault(this, 29, 0) as number; + } + set speedLimit(value: number) { + pb_1.Message.setField(this, 29, value); + } + static fromObject(data: { + ipSingleSwitchStusCiOccupied?: boolean; + ipSingleSwitchStusCbtcOccupied?: boolean; + ipSingleSwitchStusLocked?: boolean; + ipSingleSwitchStusFailLocked?: boolean; + ipSingleSwitchStusNormal?: boolean; + ipSingleSwitchStusReverse?: boolean; + ipSingleSwitchStusBlocked1?: boolean; + ipSingleSwitchStusJammed?: boolean; + ipSingleSwitchStusExpectLock?: boolean; + ipSingleSwitchStusExpectUnlock?: boolean; + ipSingleSwitchStusExpectNormal?: boolean; + ipSingleSwitchStusExpectReverse?: boolean; + ipSingleSwitchStusExpectBlock?: boolean; + ipSingleSwitchStusExpectUnblock?: boolean; + ipSingleSwitchStusInRoute?: boolean; + ipSingleSwitchStusManualMode?: boolean; + ipSingleSwitchStusCut?: boolean; + ipSingleSwitchStusAtcInvalid?: boolean; + ipSingleSwitchStusOverlap?: boolean; + ipSingleSwitchStusTsrCbtcMain?: boolean; + ipSingleSwitchStusTsrCbtcNormal?: boolean; + ipSingleSwitchStusTsrCbtcReverse?: boolean; + ipSingleSwitchStusTsrBmMain?: boolean; + ipSingleSwitchStusTsrBmNormal?: boolean; + ipSingleSwitchStusTsrBmReverse?: boolean; + ipSingleSwitchStusBlocked2?: boolean; + ipSingleSwitchStusLostIndication?: boolean; + id?: string; + speedLimit?: number; + }): Switch { + const message = new Switch({}); + if (data.ipSingleSwitchStusCiOccupied != null) { + message.ipSingleSwitchStusCiOccupied = data.ipSingleSwitchStusCiOccupied; + } + if (data.ipSingleSwitchStusCbtcOccupied != null) { + message.ipSingleSwitchStusCbtcOccupied = data.ipSingleSwitchStusCbtcOccupied; + } + if (data.ipSingleSwitchStusLocked != null) { + message.ipSingleSwitchStusLocked = data.ipSingleSwitchStusLocked; + } + if (data.ipSingleSwitchStusFailLocked != null) { + message.ipSingleSwitchStusFailLocked = data.ipSingleSwitchStusFailLocked; + } + if (data.ipSingleSwitchStusNormal != null) { + message.ipSingleSwitchStusNormal = data.ipSingleSwitchStusNormal; + } + if (data.ipSingleSwitchStusReverse != null) { + message.ipSingleSwitchStusReverse = data.ipSingleSwitchStusReverse; + } + if (data.ipSingleSwitchStusBlocked1 != null) { + message.ipSingleSwitchStusBlocked1 = data.ipSingleSwitchStusBlocked1; + } + if (data.ipSingleSwitchStusJammed != null) { + message.ipSingleSwitchStusJammed = data.ipSingleSwitchStusJammed; + } + if (data.ipSingleSwitchStusExpectLock != null) { + message.ipSingleSwitchStusExpectLock = data.ipSingleSwitchStusExpectLock; + } + if (data.ipSingleSwitchStusExpectUnlock != null) { + message.ipSingleSwitchStusExpectUnlock = data.ipSingleSwitchStusExpectUnlock; + } + if (data.ipSingleSwitchStusExpectNormal != null) { + message.ipSingleSwitchStusExpectNormal = data.ipSingleSwitchStusExpectNormal; + } + if (data.ipSingleSwitchStusExpectReverse != null) { + message.ipSingleSwitchStusExpectReverse = data.ipSingleSwitchStusExpectReverse; + } + if (data.ipSingleSwitchStusExpectBlock != null) { + message.ipSingleSwitchStusExpectBlock = data.ipSingleSwitchStusExpectBlock; + } + if (data.ipSingleSwitchStusExpectUnblock != null) { + message.ipSingleSwitchStusExpectUnblock = data.ipSingleSwitchStusExpectUnblock; + } + if (data.ipSingleSwitchStusInRoute != null) { + message.ipSingleSwitchStusInRoute = data.ipSingleSwitchStusInRoute; + } + if (data.ipSingleSwitchStusManualMode != null) { + message.ipSingleSwitchStusManualMode = data.ipSingleSwitchStusManualMode; + } + if (data.ipSingleSwitchStusCut != null) { + message.ipSingleSwitchStusCut = data.ipSingleSwitchStusCut; + } + if (data.ipSingleSwitchStusAtcInvalid != null) { + message.ipSingleSwitchStusAtcInvalid = data.ipSingleSwitchStusAtcInvalid; + } + if (data.ipSingleSwitchStusOverlap != null) { + message.ipSingleSwitchStusOverlap = data.ipSingleSwitchStusOverlap; + } + if (data.ipSingleSwitchStusTsrCbtcMain != null) { + message.ipSingleSwitchStusTsrCbtcMain = data.ipSingleSwitchStusTsrCbtcMain; + } + if (data.ipSingleSwitchStusTsrCbtcNormal != null) { + message.ipSingleSwitchStusTsrCbtcNormal = data.ipSingleSwitchStusTsrCbtcNormal; + } + if (data.ipSingleSwitchStusTsrCbtcReverse != null) { + message.ipSingleSwitchStusTsrCbtcReverse = data.ipSingleSwitchStusTsrCbtcReverse; + } + if (data.ipSingleSwitchStusTsrBmMain != null) { + message.ipSingleSwitchStusTsrBmMain = data.ipSingleSwitchStusTsrBmMain; + } + if (data.ipSingleSwitchStusTsrBmNormal != null) { + message.ipSingleSwitchStusTsrBmNormal = data.ipSingleSwitchStusTsrBmNormal; + } + if (data.ipSingleSwitchStusTsrBmReverse != null) { + message.ipSingleSwitchStusTsrBmReverse = data.ipSingleSwitchStusTsrBmReverse; + } + if (data.ipSingleSwitchStusBlocked2 != null) { + message.ipSingleSwitchStusBlocked2 = data.ipSingleSwitchStusBlocked2; + } + if (data.ipSingleSwitchStusLostIndication != null) { + message.ipSingleSwitchStusLostIndication = data.ipSingleSwitchStusLostIndication; + } + if (data.id != null) { + message.id = data.id; + } + if (data.speedLimit != null) { + message.speedLimit = data.speedLimit; + } + return message; + } + toObject() { + const data: { + ipSingleSwitchStusCiOccupied?: boolean; + ipSingleSwitchStusCbtcOccupied?: boolean; + ipSingleSwitchStusLocked?: boolean; + ipSingleSwitchStusFailLocked?: boolean; + ipSingleSwitchStusNormal?: boolean; + ipSingleSwitchStusReverse?: boolean; + ipSingleSwitchStusBlocked1?: boolean; + ipSingleSwitchStusJammed?: boolean; + ipSingleSwitchStusExpectLock?: boolean; + ipSingleSwitchStusExpectUnlock?: boolean; + ipSingleSwitchStusExpectNormal?: boolean; + ipSingleSwitchStusExpectReverse?: boolean; + ipSingleSwitchStusExpectBlock?: boolean; + ipSingleSwitchStusExpectUnblock?: boolean; + ipSingleSwitchStusInRoute?: boolean; + ipSingleSwitchStusManualMode?: boolean; + ipSingleSwitchStusCut?: boolean; + ipSingleSwitchStusAtcInvalid?: boolean; + ipSingleSwitchStusOverlap?: boolean; + ipSingleSwitchStusTsrCbtcMain?: boolean; + ipSingleSwitchStusTsrCbtcNormal?: boolean; + ipSingleSwitchStusTsrCbtcReverse?: boolean; + ipSingleSwitchStusTsrBmMain?: boolean; + ipSingleSwitchStusTsrBmNormal?: boolean; + ipSingleSwitchStusTsrBmReverse?: boolean; + ipSingleSwitchStusBlocked2?: boolean; + ipSingleSwitchStusLostIndication?: boolean; + id?: string; + speedLimit?: number; + } = {}; + if (this.ipSingleSwitchStusCiOccupied != null) { + data.ipSingleSwitchStusCiOccupied = this.ipSingleSwitchStusCiOccupied; + } + if (this.ipSingleSwitchStusCbtcOccupied != null) { + data.ipSingleSwitchStusCbtcOccupied = this.ipSingleSwitchStusCbtcOccupied; + } + if (this.ipSingleSwitchStusLocked != null) { + data.ipSingleSwitchStusLocked = this.ipSingleSwitchStusLocked; + } + if (this.ipSingleSwitchStusFailLocked != null) { + data.ipSingleSwitchStusFailLocked = this.ipSingleSwitchStusFailLocked; + } + if (this.ipSingleSwitchStusNormal != null) { + data.ipSingleSwitchStusNormal = this.ipSingleSwitchStusNormal; + } + if (this.ipSingleSwitchStusReverse != null) { + data.ipSingleSwitchStusReverse = this.ipSingleSwitchStusReverse; + } + if (this.ipSingleSwitchStusBlocked1 != null) { + data.ipSingleSwitchStusBlocked1 = this.ipSingleSwitchStusBlocked1; + } + if (this.ipSingleSwitchStusJammed != null) { + data.ipSingleSwitchStusJammed = this.ipSingleSwitchStusJammed; + } + if (this.ipSingleSwitchStusExpectLock != null) { + data.ipSingleSwitchStusExpectLock = this.ipSingleSwitchStusExpectLock; + } + if (this.ipSingleSwitchStusExpectUnlock != null) { + data.ipSingleSwitchStusExpectUnlock = this.ipSingleSwitchStusExpectUnlock; + } + if (this.ipSingleSwitchStusExpectNormal != null) { + data.ipSingleSwitchStusExpectNormal = this.ipSingleSwitchStusExpectNormal; + } + if (this.ipSingleSwitchStusExpectReverse != null) { + data.ipSingleSwitchStusExpectReverse = this.ipSingleSwitchStusExpectReverse; + } + if (this.ipSingleSwitchStusExpectBlock != null) { + data.ipSingleSwitchStusExpectBlock = this.ipSingleSwitchStusExpectBlock; + } + if (this.ipSingleSwitchStusExpectUnblock != null) { + data.ipSingleSwitchStusExpectUnblock = this.ipSingleSwitchStusExpectUnblock; + } + if (this.ipSingleSwitchStusInRoute != null) { + data.ipSingleSwitchStusInRoute = this.ipSingleSwitchStusInRoute; + } + if (this.ipSingleSwitchStusManualMode != null) { + data.ipSingleSwitchStusManualMode = this.ipSingleSwitchStusManualMode; + } + if (this.ipSingleSwitchStusCut != null) { + data.ipSingleSwitchStusCut = this.ipSingleSwitchStusCut; + } + if (this.ipSingleSwitchStusAtcInvalid != null) { + data.ipSingleSwitchStusAtcInvalid = this.ipSingleSwitchStusAtcInvalid; + } + if (this.ipSingleSwitchStusOverlap != null) { + data.ipSingleSwitchStusOverlap = this.ipSingleSwitchStusOverlap; + } + if (this.ipSingleSwitchStusTsrCbtcMain != null) { + data.ipSingleSwitchStusTsrCbtcMain = this.ipSingleSwitchStusTsrCbtcMain; + } + if (this.ipSingleSwitchStusTsrCbtcNormal != null) { + data.ipSingleSwitchStusTsrCbtcNormal = this.ipSingleSwitchStusTsrCbtcNormal; + } + if (this.ipSingleSwitchStusTsrCbtcReverse != null) { + data.ipSingleSwitchStusTsrCbtcReverse = this.ipSingleSwitchStusTsrCbtcReverse; + } + if (this.ipSingleSwitchStusTsrBmMain != null) { + data.ipSingleSwitchStusTsrBmMain = this.ipSingleSwitchStusTsrBmMain; + } + if (this.ipSingleSwitchStusTsrBmNormal != null) { + data.ipSingleSwitchStusTsrBmNormal = this.ipSingleSwitchStusTsrBmNormal; + } + if (this.ipSingleSwitchStusTsrBmReverse != null) { + data.ipSingleSwitchStusTsrBmReverse = this.ipSingleSwitchStusTsrBmReverse; + } + if (this.ipSingleSwitchStusBlocked2 != null) { + data.ipSingleSwitchStusBlocked2 = this.ipSingleSwitchStusBlocked2; + } + if (this.ipSingleSwitchStusLostIndication != null) { + data.ipSingleSwitchStusLostIndication = this.ipSingleSwitchStusLostIndication; + } + if (this.id != null) { + data.id = this.id; + } + if (this.speedLimit != null) { + data.speedLimit = this.speedLimit; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ipSingleSwitchStusCiOccupied != false) + writer.writeBool(1, this.ipSingleSwitchStusCiOccupied); + if (this.ipSingleSwitchStusCbtcOccupied != false) + writer.writeBool(2, this.ipSingleSwitchStusCbtcOccupied); + if (this.ipSingleSwitchStusLocked != false) + writer.writeBool(3, this.ipSingleSwitchStusLocked); + if (this.ipSingleSwitchStusFailLocked != false) + writer.writeBool(4, this.ipSingleSwitchStusFailLocked); + if (this.ipSingleSwitchStusNormal != false) + writer.writeBool(5, this.ipSingleSwitchStusNormal); + if (this.ipSingleSwitchStusReverse != false) + writer.writeBool(6, this.ipSingleSwitchStusReverse); + if (this.ipSingleSwitchStusBlocked1 != false) + writer.writeBool(7, this.ipSingleSwitchStusBlocked1); + if (this.ipSingleSwitchStusJammed != false) + writer.writeBool(8, this.ipSingleSwitchStusJammed); + if (this.ipSingleSwitchStusExpectLock != false) + writer.writeBool(9, this.ipSingleSwitchStusExpectLock); + if (this.ipSingleSwitchStusExpectUnlock != false) + writer.writeBool(10, this.ipSingleSwitchStusExpectUnlock); + if (this.ipSingleSwitchStusExpectNormal != false) + writer.writeBool(11, this.ipSingleSwitchStusExpectNormal); + if (this.ipSingleSwitchStusExpectReverse != false) + writer.writeBool(12, this.ipSingleSwitchStusExpectReverse); + if (this.ipSingleSwitchStusExpectBlock != false) + writer.writeBool(13, this.ipSingleSwitchStusExpectBlock); + if (this.ipSingleSwitchStusExpectUnblock != false) + writer.writeBool(14, this.ipSingleSwitchStusExpectUnblock); + if (this.ipSingleSwitchStusInRoute != false) + writer.writeBool(15, this.ipSingleSwitchStusInRoute); + if (this.ipSingleSwitchStusManualMode != false) + writer.writeBool(16, this.ipSingleSwitchStusManualMode); + if (this.ipSingleSwitchStusCut != false) + writer.writeBool(17, this.ipSingleSwitchStusCut); + if (this.ipSingleSwitchStusAtcInvalid != false) + writer.writeBool(18, this.ipSingleSwitchStusAtcInvalid); + if (this.ipSingleSwitchStusOverlap != false) + writer.writeBool(19, this.ipSingleSwitchStusOverlap); + if (this.ipSingleSwitchStusTsrCbtcMain != false) + writer.writeBool(20, this.ipSingleSwitchStusTsrCbtcMain); + if (this.ipSingleSwitchStusTsrCbtcNormal != false) + writer.writeBool(21, this.ipSingleSwitchStusTsrCbtcNormal); + if (this.ipSingleSwitchStusTsrCbtcReverse != false) + writer.writeBool(22, this.ipSingleSwitchStusTsrCbtcReverse); + if (this.ipSingleSwitchStusTsrBmMain != false) + writer.writeBool(23, this.ipSingleSwitchStusTsrBmMain); + if (this.ipSingleSwitchStusTsrBmNormal != false) + writer.writeBool(24, this.ipSingleSwitchStusTsrBmNormal); + if (this.ipSingleSwitchStusTsrBmReverse != false) + writer.writeBool(25, this.ipSingleSwitchStusTsrBmReverse); + if (this.ipSingleSwitchStusBlocked2 != false) + writer.writeBool(26, this.ipSingleSwitchStusBlocked2); + if (this.ipSingleSwitchStusLostIndication != false) + writer.writeBool(27, this.ipSingleSwitchStusLostIndication); + if (this.id.length) + writer.writeString(28, this.id); + if (this.speedLimit != 0) + writer.writeInt32(29, this.speedLimit); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Switch { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Switch(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ipSingleSwitchStusCiOccupied = reader.readBool(); + break; + case 2: + message.ipSingleSwitchStusCbtcOccupied = reader.readBool(); + break; + case 3: + message.ipSingleSwitchStusLocked = reader.readBool(); + break; + case 4: + message.ipSingleSwitchStusFailLocked = reader.readBool(); + break; + case 5: + message.ipSingleSwitchStusNormal = reader.readBool(); + break; + case 6: + message.ipSingleSwitchStusReverse = reader.readBool(); + break; + case 7: + message.ipSingleSwitchStusBlocked1 = reader.readBool(); + break; + case 8: + message.ipSingleSwitchStusJammed = reader.readBool(); + break; + case 9: + message.ipSingleSwitchStusExpectLock = reader.readBool(); + break; + case 10: + message.ipSingleSwitchStusExpectUnlock = reader.readBool(); + break; + case 11: + message.ipSingleSwitchStusExpectNormal = reader.readBool(); + break; + case 12: + message.ipSingleSwitchStusExpectReverse = reader.readBool(); + break; + case 13: + message.ipSingleSwitchStusExpectBlock = reader.readBool(); + break; + case 14: + message.ipSingleSwitchStusExpectUnblock = reader.readBool(); + break; + case 15: + message.ipSingleSwitchStusInRoute = reader.readBool(); + break; + case 16: + message.ipSingleSwitchStusManualMode = reader.readBool(); + break; + case 17: + message.ipSingleSwitchStusCut = reader.readBool(); + break; + case 18: + message.ipSingleSwitchStusAtcInvalid = reader.readBool(); + break; + case 19: + message.ipSingleSwitchStusOverlap = reader.readBool(); + break; + case 20: + message.ipSingleSwitchStusTsrCbtcMain = reader.readBool(); + break; + case 21: + message.ipSingleSwitchStusTsrCbtcNormal = reader.readBool(); + break; + case 22: + message.ipSingleSwitchStusTsrCbtcReverse = reader.readBool(); + break; + case 23: + message.ipSingleSwitchStusTsrBmMain = reader.readBool(); + break; + case 24: + message.ipSingleSwitchStusTsrBmNormal = reader.readBool(); + break; + case 25: + message.ipSingleSwitchStusTsrBmReverse = reader.readBool(); + break; + case 26: + message.ipSingleSwitchStusBlocked2 = reader.readBool(); + break; + case 27: + message.ipSingleSwitchStusLostIndication = reader.readBool(); + break; + case 28: + message.id = reader.readString(); + break; + case 29: + message.speedLimit = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Switch { + return Switch.deserialize(bytes); + } + } + export class Track extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ciOccupied?: boolean; + cbtcOccupied?: boolean; + locked?: boolean; + failLocked?: boolean; + expectLock?: boolean; + expectUnlock?: boolean; + inRoute?: boolean; + cut?: boolean; + atcInvalid?: boolean; + overlap?: boolean; + blocked?: boolean; + id?: string; + speedLimit?: number; + limitType?: Track.LimitType; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ciOccupied" in data && data.ciOccupied != undefined) { + this.ciOccupied = data.ciOccupied; + } + if ("cbtcOccupied" in data && data.cbtcOccupied != undefined) { + this.cbtcOccupied = data.cbtcOccupied; + } + if ("locked" in data && data.locked != undefined) { + this.locked = data.locked; + } + if ("failLocked" in data && data.failLocked != undefined) { + this.failLocked = data.failLocked; + } + if ("expectLock" in data && data.expectLock != undefined) { + this.expectLock = data.expectLock; + } + if ("expectUnlock" in data && data.expectUnlock != undefined) { + this.expectUnlock = data.expectUnlock; + } + if ("inRoute" in data && data.inRoute != undefined) { + this.inRoute = data.inRoute; + } + if ("cut" in data && data.cut != undefined) { + this.cut = data.cut; + } + if ("atcInvalid" in data && data.atcInvalid != undefined) { + this.atcInvalid = data.atcInvalid; + } + if ("overlap" in data && data.overlap != undefined) { + this.overlap = data.overlap; + } + if ("blocked" in data && data.blocked != undefined) { + this.blocked = data.blocked; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("speedLimit" in data && data.speedLimit != undefined) { + this.speedLimit = data.speedLimit; + } + if ("limitType" in data && data.limitType != undefined) { + this.limitType = data.limitType; + } + } + } + get ciOccupied() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ciOccupied(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get cbtcOccupied() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set cbtcOccupied(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get locked() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set locked(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get failLocked() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set failLocked(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get expectLock() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set expectLock(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get expectUnlock() { + return pb_1.Message.getFieldWithDefault(this, 6, false) as boolean; + } + set expectUnlock(value: boolean) { + pb_1.Message.setField(this, 6, value); + } + get inRoute() { + return pb_1.Message.getFieldWithDefault(this, 7, false) as boolean; + } + set inRoute(value: boolean) { + pb_1.Message.setField(this, 7, value); + } + get cut() { + return pb_1.Message.getFieldWithDefault(this, 8, false) as boolean; + } + set cut(value: boolean) { + pb_1.Message.setField(this, 8, value); + } + get atcInvalid() { + return pb_1.Message.getFieldWithDefault(this, 9, false) as boolean; + } + set atcInvalid(value: boolean) { + pb_1.Message.setField(this, 9, value); + } + get overlap() { + return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean; + } + set overlap(value: boolean) { + pb_1.Message.setField(this, 10, value); + } + get blocked() { + return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean; + } + set blocked(value: boolean) { + pb_1.Message.setField(this, 11, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 12, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 12, value); + } + get speedLimit() { + return pb_1.Message.getFieldWithDefault(this, 13, 0) as number; + } + set speedLimit(value: number) { + pb_1.Message.setField(this, 13, value); + } + get limitType() { + return pb_1.Message.getFieldWithDefault(this, 14, Track.LimitType.Unknown) as Track.LimitType; + } + set limitType(value: Track.LimitType) { + pb_1.Message.setField(this, 14, value); + } + static fromObject(data: { + ciOccupied?: boolean; + cbtcOccupied?: boolean; + locked?: boolean; + failLocked?: boolean; + expectLock?: boolean; + expectUnlock?: boolean; + inRoute?: boolean; + cut?: boolean; + atcInvalid?: boolean; + overlap?: boolean; + blocked?: boolean; + id?: string; + speedLimit?: number; + limitType?: Track.LimitType; + }): Track { + const message = new Track({}); + if (data.ciOccupied != null) { + message.ciOccupied = data.ciOccupied; + } + if (data.cbtcOccupied != null) { + message.cbtcOccupied = data.cbtcOccupied; + } + if (data.locked != null) { + message.locked = data.locked; + } + if (data.failLocked != null) { + message.failLocked = data.failLocked; + } + if (data.expectLock != null) { + message.expectLock = data.expectLock; + } + if (data.expectUnlock != null) { + message.expectUnlock = data.expectUnlock; + } + if (data.inRoute != null) { + message.inRoute = data.inRoute; + } + if (data.cut != null) { + message.cut = data.cut; + } + if (data.atcInvalid != null) { + message.atcInvalid = data.atcInvalid; + } + if (data.overlap != null) { + message.overlap = data.overlap; + } + if (data.blocked != null) { + message.blocked = data.blocked; + } + if (data.id != null) { + message.id = data.id; + } + if (data.speedLimit != null) { + message.speedLimit = data.speedLimit; + } + if (data.limitType != null) { + message.limitType = data.limitType; + } + return message; + } + toObject() { + const data: { + ciOccupied?: boolean; + cbtcOccupied?: boolean; + locked?: boolean; + failLocked?: boolean; + expectLock?: boolean; + expectUnlock?: boolean; + inRoute?: boolean; + cut?: boolean; + atcInvalid?: boolean; + overlap?: boolean; + blocked?: boolean; + id?: string; + speedLimit?: number; + limitType?: Track.LimitType; + } = {}; + if (this.ciOccupied != null) { + data.ciOccupied = this.ciOccupied; + } + if (this.cbtcOccupied != null) { + data.cbtcOccupied = this.cbtcOccupied; + } + if (this.locked != null) { + data.locked = this.locked; + } + if (this.failLocked != null) { + data.failLocked = this.failLocked; + } + if (this.expectLock != null) { + data.expectLock = this.expectLock; + } + if (this.expectUnlock != null) { + data.expectUnlock = this.expectUnlock; + } + if (this.inRoute != null) { + data.inRoute = this.inRoute; + } + if (this.cut != null) { + data.cut = this.cut; + } + if (this.atcInvalid != null) { + data.atcInvalid = this.atcInvalid; + } + if (this.overlap != null) { + data.overlap = this.overlap; + } + if (this.blocked != null) { + data.blocked = this.blocked; + } + if (this.id != null) { + data.id = this.id; + } + if (this.speedLimit != null) { + data.speedLimit = this.speedLimit; + } + if (this.limitType != null) { + data.limitType = this.limitType; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ciOccupied != false) + writer.writeBool(1, this.ciOccupied); + if (this.cbtcOccupied != false) + writer.writeBool(2, this.cbtcOccupied); + if (this.locked != false) + writer.writeBool(3, this.locked); + if (this.failLocked != false) + writer.writeBool(4, this.failLocked); + if (this.expectLock != false) + writer.writeBool(5, this.expectLock); + if (this.expectUnlock != false) + writer.writeBool(6, this.expectUnlock); + if (this.inRoute != false) + writer.writeBool(7, this.inRoute); + if (this.cut != false) + writer.writeBool(8, this.cut); + if (this.atcInvalid != false) + writer.writeBool(9, this.atcInvalid); + if (this.overlap != false) + writer.writeBool(10, this.overlap); + if (this.blocked != false) + writer.writeBool(11, this.blocked); + if (this.id.length) + writer.writeString(12, this.id); + if (this.speedLimit != 0) + writer.writeInt32(13, this.speedLimit); + if (this.limitType != Track.LimitType.Unknown) + writer.writeEnum(14, this.limitType); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Track { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Track(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ciOccupied = reader.readBool(); + break; + case 2: + message.cbtcOccupied = reader.readBool(); + break; + case 3: + message.locked = reader.readBool(); + break; + case 4: + message.failLocked = reader.readBool(); + break; + case 5: + message.expectLock = reader.readBool(); + break; + case 6: + message.expectUnlock = reader.readBool(); + break; + case 7: + message.inRoute = reader.readBool(); + break; + case 8: + message.cut = reader.readBool(); + break; + case 9: + message.atcInvalid = reader.readBool(); + break; + case 10: + message.overlap = reader.readBool(); + break; + case 11: + message.blocked = reader.readBool(); + break; + case 12: + message.id = reader.readString(); + break; + case 13: + message.speedLimit = reader.readInt32(); + break; + case 14: + message.limitType = reader.readEnum(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Track { + return Track.deserialize(bytes); + } + } + export namespace Track { + export enum LimitType { + Unknown = 0, + Cbtc = 1, + Interlock = 2, + CbtcInterlock = 4 + } + } + export class Platform extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + emergstop?: boolean; + trainberth?: boolean; + close?: boolean; + upHold?: boolean; + downHold?: boolean; + upOccHold?: boolean; + downOccHold?: boolean; + psdOpen?: boolean; + psdCut?: boolean; + upSkipstop?: boolean; + downSkipstop?: boolean; + upTrainSkipstop?: boolean; + downTrainSkipstop?: boolean; + id?: string; + nextSectionRunTime?: number; + nextSectionRunLevel?: number; + stopTime?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("emergstop" in data && data.emergstop != undefined) { + this.emergstop = data.emergstop; + } + if ("trainberth" in data && data.trainberth != undefined) { + this.trainberth = data.trainberth; + } + if ("close" in data && data.close != undefined) { + this.close = data.close; + } + if ("upHold" in data && data.upHold != undefined) { + this.upHold = data.upHold; + } + if ("downHold" in data && data.downHold != undefined) { + this.downHold = data.downHold; + } + if ("upOccHold" in data && data.upOccHold != undefined) { + this.upOccHold = data.upOccHold; + } + if ("downOccHold" in data && data.downOccHold != undefined) { + this.downOccHold = data.downOccHold; + } + if ("psdOpen" in data && data.psdOpen != undefined) { + this.psdOpen = data.psdOpen; + } + if ("psdCut" in data && data.psdCut != undefined) { + this.psdCut = data.psdCut; + } + if ("upSkipstop" in data && data.upSkipstop != undefined) { + this.upSkipstop = data.upSkipstop; + } + if ("downSkipstop" in data && data.downSkipstop != undefined) { + this.downSkipstop = data.downSkipstop; + } + if ("upTrainSkipstop" in data && data.upTrainSkipstop != undefined) { + this.upTrainSkipstop = data.upTrainSkipstop; + } + if ("downTrainSkipstop" in data && data.downTrainSkipstop != undefined) { + this.downTrainSkipstop = data.downTrainSkipstop; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("nextSectionRunTime" in data && data.nextSectionRunTime != undefined) { + this.nextSectionRunTime = data.nextSectionRunTime; + } + if ("nextSectionRunLevel" in data && data.nextSectionRunLevel != undefined) { + this.nextSectionRunLevel = data.nextSectionRunLevel; + } + if ("stopTime" in data && data.stopTime != undefined) { + this.stopTime = data.stopTime; + } + } + } + get emergstop() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set emergstop(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get trainberth() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set trainberth(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get close() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set close(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get upHold() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set upHold(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get downHold() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set downHold(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get upOccHold() { + return pb_1.Message.getFieldWithDefault(this, 6, false) as boolean; + } + set upOccHold(value: boolean) { + pb_1.Message.setField(this, 6, value); + } + get downOccHold() { + return pb_1.Message.getFieldWithDefault(this, 7, false) as boolean; + } + set downOccHold(value: boolean) { + pb_1.Message.setField(this, 7, value); + } + get psdOpen() { + return pb_1.Message.getFieldWithDefault(this, 8, false) as boolean; + } + set psdOpen(value: boolean) { + pb_1.Message.setField(this, 8, value); + } + get psdCut() { + return pb_1.Message.getFieldWithDefault(this, 9, false) as boolean; + } + set psdCut(value: boolean) { + pb_1.Message.setField(this, 9, value); + } + get upSkipstop() { + return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean; + } + set upSkipstop(value: boolean) { + pb_1.Message.setField(this, 10, value); + } + get downSkipstop() { + return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean; + } + set downSkipstop(value: boolean) { + pb_1.Message.setField(this, 11, value); + } + get upTrainSkipstop() { + return pb_1.Message.getFieldWithDefault(this, 12, false) as boolean; + } + set upTrainSkipstop(value: boolean) { + pb_1.Message.setField(this, 12, value); + } + get downTrainSkipstop() { + return pb_1.Message.getFieldWithDefault(this, 13, false) as boolean; + } + set downTrainSkipstop(value: boolean) { + pb_1.Message.setField(this, 13, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 14, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 14, value); + } + get nextSectionRunTime() { + return pb_1.Message.getFieldWithDefault(this, 15, 0) as number; + } + set nextSectionRunTime(value: number) { + pb_1.Message.setField(this, 15, value); + } + get nextSectionRunLevel() { + return pb_1.Message.getFieldWithDefault(this, 16, 0) as number; + } + set nextSectionRunLevel(value: number) { + pb_1.Message.setField(this, 16, value); + } + get stopTime() { + return pb_1.Message.getFieldWithDefault(this, 17, 0) as number; + } + set stopTime(value: number) { + pb_1.Message.setField(this, 17, value); + } + static fromObject(data: { + emergstop?: boolean; + trainberth?: boolean; + close?: boolean; + upHold?: boolean; + downHold?: boolean; + upOccHold?: boolean; + downOccHold?: boolean; + psdOpen?: boolean; + psdCut?: boolean; + upSkipstop?: boolean; + downSkipstop?: boolean; + upTrainSkipstop?: boolean; + downTrainSkipstop?: boolean; + id?: string; + nextSectionRunTime?: number; + nextSectionRunLevel?: number; + stopTime?: number; + }): Platform { + const message = new Platform({}); + if (data.emergstop != null) { + message.emergstop = data.emergstop; + } + if (data.trainberth != null) { + message.trainberth = data.trainberth; + } + if (data.close != null) { + message.close = data.close; + } + if (data.upHold != null) { + message.upHold = data.upHold; + } + if (data.downHold != null) { + message.downHold = data.downHold; + } + if (data.upOccHold != null) { + message.upOccHold = data.upOccHold; + } + if (data.downOccHold != null) { + message.downOccHold = data.downOccHold; + } + if (data.psdOpen != null) { + message.psdOpen = data.psdOpen; + } + if (data.psdCut != null) { + message.psdCut = data.psdCut; + } + if (data.upSkipstop != null) { + message.upSkipstop = data.upSkipstop; + } + if (data.downSkipstop != null) { + message.downSkipstop = data.downSkipstop; + } + if (data.upTrainSkipstop != null) { + message.upTrainSkipstop = data.upTrainSkipstop; + } + if (data.downTrainSkipstop != null) { + message.downTrainSkipstop = data.downTrainSkipstop; + } + if (data.id != null) { + message.id = data.id; + } + if (data.nextSectionRunTime != null) { + message.nextSectionRunTime = data.nextSectionRunTime; + } + if (data.nextSectionRunLevel != null) { + message.nextSectionRunLevel = data.nextSectionRunLevel; + } + if (data.stopTime != null) { + message.stopTime = data.stopTime; + } + return message; + } + toObject() { + const data: { + emergstop?: boolean; + trainberth?: boolean; + close?: boolean; + upHold?: boolean; + downHold?: boolean; + upOccHold?: boolean; + downOccHold?: boolean; + psdOpen?: boolean; + psdCut?: boolean; + upSkipstop?: boolean; + downSkipstop?: boolean; + upTrainSkipstop?: boolean; + downTrainSkipstop?: boolean; + id?: string; + nextSectionRunTime?: number; + nextSectionRunLevel?: number; + stopTime?: number; + } = {}; + if (this.emergstop != null) { + data.emergstop = this.emergstop; + } + if (this.trainberth != null) { + data.trainberth = this.trainberth; + } + if (this.close != null) { + data.close = this.close; + } + if (this.upHold != null) { + data.upHold = this.upHold; + } + if (this.downHold != null) { + data.downHold = this.downHold; + } + if (this.upOccHold != null) { + data.upOccHold = this.upOccHold; + } + if (this.downOccHold != null) { + data.downOccHold = this.downOccHold; + } + if (this.psdOpen != null) { + data.psdOpen = this.psdOpen; + } + if (this.psdCut != null) { + data.psdCut = this.psdCut; + } + if (this.upSkipstop != null) { + data.upSkipstop = this.upSkipstop; + } + if (this.downSkipstop != null) { + data.downSkipstop = this.downSkipstop; + } + if (this.upTrainSkipstop != null) { + data.upTrainSkipstop = this.upTrainSkipstop; + } + if (this.downTrainSkipstop != null) { + data.downTrainSkipstop = this.downTrainSkipstop; + } + if (this.id != null) { + data.id = this.id; + } + if (this.nextSectionRunTime != null) { + data.nextSectionRunTime = this.nextSectionRunTime; + } + if (this.nextSectionRunLevel != null) { + data.nextSectionRunLevel = this.nextSectionRunLevel; + } + if (this.stopTime != null) { + data.stopTime = this.stopTime; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.emergstop != false) + writer.writeBool(1, this.emergstop); + if (this.trainberth != false) + writer.writeBool(2, this.trainberth); + if (this.close != false) + writer.writeBool(3, this.close); + if (this.upHold != false) + writer.writeBool(4, this.upHold); + if (this.downHold != false) + writer.writeBool(5, this.downHold); + if (this.upOccHold != false) + writer.writeBool(6, this.upOccHold); + if (this.downOccHold != false) + writer.writeBool(7, this.downOccHold); + if (this.psdOpen != false) + writer.writeBool(8, this.psdOpen); + if (this.psdCut != false) + writer.writeBool(9, this.psdCut); + if (this.upSkipstop != false) + writer.writeBool(10, this.upSkipstop); + if (this.downSkipstop != false) + writer.writeBool(11, this.downSkipstop); + if (this.upTrainSkipstop != false) + writer.writeBool(12, this.upTrainSkipstop); + if (this.downTrainSkipstop != false) + writer.writeBool(13, this.downTrainSkipstop); + if (this.id.length) + writer.writeString(14, this.id); + if (this.nextSectionRunTime != 0) + writer.writeInt32(15, this.nextSectionRunTime); + if (this.nextSectionRunLevel != 0) + writer.writeInt32(16, this.nextSectionRunLevel); + if (this.stopTime != 0) + writer.writeInt32(17, this.stopTime); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Platform { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Platform(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.emergstop = reader.readBool(); + break; + case 2: + message.trainberth = reader.readBool(); + break; + case 3: + message.close = reader.readBool(); + break; + case 4: + message.upHold = reader.readBool(); + break; + case 5: + message.downHold = reader.readBool(); + break; + case 6: + message.upOccHold = reader.readBool(); + break; + case 7: + message.downOccHold = reader.readBool(); + break; + case 8: + message.psdOpen = reader.readBool(); + break; + case 9: + message.psdCut = reader.readBool(); + break; + case 10: + message.upSkipstop = reader.readBool(); + break; + case 11: + message.downSkipstop = reader.readBool(); + break; + case 12: + message.upTrainSkipstop = reader.readBool(); + break; + case 13: + message.downTrainSkipstop = reader.readBool(); + break; + case 14: + message.id = reader.readString(); + break; + case 15: + message.nextSectionRunTime = reader.readInt32(); + break; + case 16: + message.nextSectionRunLevel = reader.readInt32(); + break; + case 17: + message.stopTime = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Platform { + return Platform.deserialize(bytes); + } + } + export class Scada extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + scadaOn?: boolean; + scadaSinglePower?: boolean; + scadaUnkown?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("scadaOn" in data && data.scadaOn != undefined) { + this.scadaOn = data.scadaOn; + } + if ("scadaSinglePower" in data && data.scadaSinglePower != undefined) { + this.scadaSinglePower = data.scadaSinglePower; + } + if ("scadaUnkown" in data && data.scadaUnkown != undefined) { + this.scadaUnkown = data.scadaUnkown; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get scadaOn() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set scadaOn(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get scadaSinglePower() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set scadaSinglePower(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get scadaUnkown() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set scadaUnkown(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 4, value); + } + static fromObject(data: { + scadaOn?: boolean; + scadaSinglePower?: boolean; + scadaUnkown?: boolean; + id?: string; + }): Scada { + const message = new Scada({}); + if (data.scadaOn != null) { + message.scadaOn = data.scadaOn; + } + if (data.scadaSinglePower != null) { + message.scadaSinglePower = data.scadaSinglePower; + } + if (data.scadaUnkown != null) { + message.scadaUnkown = data.scadaUnkown; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + scadaOn?: boolean; + scadaSinglePower?: boolean; + scadaUnkown?: boolean; + id?: string; + } = {}; + if (this.scadaOn != null) { + data.scadaOn = this.scadaOn; + } + if (this.scadaSinglePower != null) { + data.scadaSinglePower = this.scadaSinglePower; + } + if (this.scadaUnkown != null) { + data.scadaUnkown = this.scadaUnkown; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.scadaOn != false) + writer.writeBool(1, this.scadaOn); + if (this.scadaSinglePower != false) + writer.writeBool(2, this.scadaSinglePower); + if (this.scadaUnkown != false) + writer.writeBool(3, this.scadaUnkown); + if (this.id.length) + writer.writeString(4, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Scada { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Scada(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.scadaOn = reader.readBool(); + break; + case 2: + message.scadaSinglePower = reader.readBool(); + break; + case 3: + message.scadaUnkown = reader.readBool(); + break; + case 4: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Scada { + return Scada.deserialize(bytes); + } + } + export class WaterProofDoor extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + doorClosed?: boolean; + doorExpectClose?: boolean; + doorAgreeClosed?: boolean; + doorClosing?: boolean; + doorOpenLock?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("doorClosed" in data && data.doorClosed != undefined) { + this.doorClosed = data.doorClosed; + } + if ("doorExpectClose" in data && data.doorExpectClose != undefined) { + this.doorExpectClose = data.doorExpectClose; + } + if ("doorAgreeClosed" in data && data.doorAgreeClosed != undefined) { + this.doorAgreeClosed = data.doorAgreeClosed; + } + if ("doorClosing" in data && data.doorClosing != undefined) { + this.doorClosing = data.doorClosing; + } + if ("doorOpenLock" in data && data.doorOpenLock != undefined) { + this.doorOpenLock = data.doorOpenLock; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get doorClosed() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set doorClosed(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get doorExpectClose() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set doorExpectClose(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get doorAgreeClosed() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set doorAgreeClosed(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get doorClosing() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set doorClosing(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get doorOpenLock() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set doorOpenLock(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 6, value); + } + static fromObject(data: { + doorClosed?: boolean; + doorExpectClose?: boolean; + doorAgreeClosed?: boolean; + doorClosing?: boolean; + doorOpenLock?: boolean; + id?: string; + }): WaterProofDoor { + const message = new WaterProofDoor({}); + if (data.doorClosed != null) { + message.doorClosed = data.doorClosed; + } + if (data.doorExpectClose != null) { + message.doorExpectClose = data.doorExpectClose; + } + if (data.doorAgreeClosed != null) { + message.doorAgreeClosed = data.doorAgreeClosed; + } + if (data.doorClosing != null) { + message.doorClosing = data.doorClosing; + } + if (data.doorOpenLock != null) { + message.doorOpenLock = data.doorOpenLock; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + doorClosed?: boolean; + doorExpectClose?: boolean; + doorAgreeClosed?: boolean; + doorClosing?: boolean; + doorOpenLock?: boolean; + id?: string; + } = {}; + if (this.doorClosed != null) { + data.doorClosed = this.doorClosed; + } + if (this.doorExpectClose != null) { + data.doorExpectClose = this.doorExpectClose; + } + if (this.doorAgreeClosed != null) { + data.doorAgreeClosed = this.doorAgreeClosed; + } + if (this.doorClosing != null) { + data.doorClosing = this.doorClosing; + } + if (this.doorOpenLock != null) { + data.doorOpenLock = this.doorOpenLock; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.doorClosed != false) + writer.writeBool(1, this.doorClosed); + if (this.doorExpectClose != false) + writer.writeBool(2, this.doorExpectClose); + if (this.doorAgreeClosed != false) + writer.writeBool(3, this.doorAgreeClosed); + if (this.doorClosing != false) + writer.writeBool(4, this.doorClosing); + if (this.doorOpenLock != false) + writer.writeBool(5, this.doorOpenLock); + if (this.id.length) + writer.writeString(6, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): WaterProofDoor { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new WaterProofDoor(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.doorClosed = reader.readBool(); + break; + case 2: + message.doorExpectClose = reader.readBool(); + break; + case 3: + message.doorAgreeClosed = reader.readBool(); + break; + case 4: + message.doorClosing = reader.readBool(); + break; + case 5: + message.doorOpenLock = reader.readBool(); + break; + case 6: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): WaterProofDoor { + return WaterProofDoor.deserialize(bytes); + } + } + export class WorkArea extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ipStusWorkAreaEnable?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ipStusWorkAreaEnable" in data && data.ipStusWorkAreaEnable != undefined) { + this.ipStusWorkAreaEnable = data.ipStusWorkAreaEnable; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get ipStusWorkAreaEnable() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ipStusWorkAreaEnable(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + ipStusWorkAreaEnable?: boolean; + id?: string; + }): WorkArea { + const message = new WorkArea({}); + if (data.ipStusWorkAreaEnable != null) { + message.ipStusWorkAreaEnable = data.ipStusWorkAreaEnable; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + ipStusWorkAreaEnable?: boolean; + id?: string; + } = {}; + if (this.ipStusWorkAreaEnable != null) { + data.ipStusWorkAreaEnable = this.ipStusWorkAreaEnable; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ipStusWorkAreaEnable != false) + writer.writeBool(1, this.ipStusWorkAreaEnable); + if (this.id.length) + writer.writeString(2, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): WorkArea { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new WorkArea(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ipStusWorkAreaEnable = reader.readBool(); + break; + case 2: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): WorkArea { + return WorkArea.deserialize(bytes); + } + } + export class Gama extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ipStusGamaDisable?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ipStusGamaDisable" in data && data.ipStusGamaDisable != undefined) { + this.ipStusGamaDisable = data.ipStusGamaDisable; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get ipStusGamaDisable() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ipStusGamaDisable(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + ipStusGamaDisable?: boolean; + id?: string; + }): Gama { + const message = new Gama({}); + if (data.ipStusGamaDisable != null) { + message.ipStusGamaDisable = data.ipStusGamaDisable; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + ipStusGamaDisable?: boolean; + id?: string; + } = {}; + if (this.ipStusGamaDisable != null) { + data.ipStusGamaDisable = this.ipStusGamaDisable; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ipStusGamaDisable != false) + writer.writeBool(1, this.ipStusGamaDisable); + if (this.id.length) + writer.writeString(2, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Gama { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Gama(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ipStusGamaDisable = reader.readBool(); + break; + case 2: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Gama { + return Gama.deserialize(bytes); + } + } + export class TrainMode extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + ipModeTrainTypeManual?: boolean; + ipModeTrainTypeHead?: boolean; + ipModeTrainTypeSpecial?: boolean; + ipModeTrainTypeSchedule?: boolean; + ipModeTrainTypeRoute?: boolean; + ipModeTrainTypeShuttle?: boolean; + ipModeTrainTypeLineup?: boolean; + ipModeTrainSchdEarly?: boolean; + ipModeTrainSchdLate?: boolean; + ipModeTrainSkipstop?: boolean; + ipModeTrainCbtcMode?: boolean; + ipModeTrainAtpCut?: boolean; + ipModeTrainBerthed?: boolean; + ipModeTrainStoped?: boolean; + ipModeTrainHolded?: boolean; + ipModeTrainItama?: boolean; + ipModeTrainDirUp?: boolean; + ipModeTrainDirDown?: boolean; + ipModeTrainDirHeadUp?: boolean; + ipModeTrainDirHeadDown?: boolean; + ipModeTrainDoorOpen?: boolean; + ipModeTrainRsAlarm?: boolean; + ipModeTrainDoorAlarm?: boolean; + ipModeTrainEbAlarm?: boolean; + ipModeTrainIntegrityAlarm?: boolean; + ipModeTrainDriveModeAm?: boolean; + ipModeTrainDriveModeCm?: boolean; + ipModeTrainDriveModeRmf?: boolean; + ipModeTrainDriveModeDto?: boolean; + ipModeTrainDriveModeAtb?: boolean; + ipModeTrainDriveBlockAm?: boolean; + ipModeTrainDriveBlockCm?: boolean; + ipModeTrainDriveModeRmr?: boolean; + ipModeTrainDriveModeWash?: boolean; + id?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("ipModeTrainTypeManual" in data && data.ipModeTrainTypeManual != undefined) { + this.ipModeTrainTypeManual = data.ipModeTrainTypeManual; + } + if ("ipModeTrainTypeHead" in data && data.ipModeTrainTypeHead != undefined) { + this.ipModeTrainTypeHead = data.ipModeTrainTypeHead; + } + if ("ipModeTrainTypeSpecial" in data && data.ipModeTrainTypeSpecial != undefined) { + this.ipModeTrainTypeSpecial = data.ipModeTrainTypeSpecial; + } + if ("ipModeTrainTypeSchedule" in data && data.ipModeTrainTypeSchedule != undefined) { + this.ipModeTrainTypeSchedule = data.ipModeTrainTypeSchedule; + } + if ("ipModeTrainTypeRoute" in data && data.ipModeTrainTypeRoute != undefined) { + this.ipModeTrainTypeRoute = data.ipModeTrainTypeRoute; + } + if ("ipModeTrainTypeShuttle" in data && data.ipModeTrainTypeShuttle != undefined) { + this.ipModeTrainTypeShuttle = data.ipModeTrainTypeShuttle; + } + if ("ipModeTrainTypeLineup" in data && data.ipModeTrainTypeLineup != undefined) { + this.ipModeTrainTypeLineup = data.ipModeTrainTypeLineup; + } + if ("ipModeTrainSchdEarly" in data && data.ipModeTrainSchdEarly != undefined) { + this.ipModeTrainSchdEarly = data.ipModeTrainSchdEarly; + } + if ("ipModeTrainSchdLate" in data && data.ipModeTrainSchdLate != undefined) { + this.ipModeTrainSchdLate = data.ipModeTrainSchdLate; + } + if ("ipModeTrainSkipstop" in data && data.ipModeTrainSkipstop != undefined) { + this.ipModeTrainSkipstop = data.ipModeTrainSkipstop; + } + if ("ipModeTrainCbtcMode" in data && data.ipModeTrainCbtcMode != undefined) { + this.ipModeTrainCbtcMode = data.ipModeTrainCbtcMode; + } + if ("ipModeTrainAtpCut" in data && data.ipModeTrainAtpCut != undefined) { + this.ipModeTrainAtpCut = data.ipModeTrainAtpCut; + } + if ("ipModeTrainBerthed" in data && data.ipModeTrainBerthed != undefined) { + this.ipModeTrainBerthed = data.ipModeTrainBerthed; + } + if ("ipModeTrainStoped" in data && data.ipModeTrainStoped != undefined) { + this.ipModeTrainStoped = data.ipModeTrainStoped; + } + if ("ipModeTrainHolded" in data && data.ipModeTrainHolded != undefined) { + this.ipModeTrainHolded = data.ipModeTrainHolded; + } + if ("ipModeTrainItama" in data && data.ipModeTrainItama != undefined) { + this.ipModeTrainItama = data.ipModeTrainItama; + } + if ("ipModeTrainDirUp" in data && data.ipModeTrainDirUp != undefined) { + this.ipModeTrainDirUp = data.ipModeTrainDirUp; + } + if ("ipModeTrainDirDown" in data && data.ipModeTrainDirDown != undefined) { + this.ipModeTrainDirDown = data.ipModeTrainDirDown; + } + if ("ipModeTrainDirHeadUp" in data && data.ipModeTrainDirHeadUp != undefined) { + this.ipModeTrainDirHeadUp = data.ipModeTrainDirHeadUp; + } + if ("ipModeTrainDirHeadDown" in data && data.ipModeTrainDirHeadDown != undefined) { + this.ipModeTrainDirHeadDown = data.ipModeTrainDirHeadDown; + } + if ("ipModeTrainDoorOpen" in data && data.ipModeTrainDoorOpen != undefined) { + this.ipModeTrainDoorOpen = data.ipModeTrainDoorOpen; + } + if ("ipModeTrainRsAlarm" in data && data.ipModeTrainRsAlarm != undefined) { + this.ipModeTrainRsAlarm = data.ipModeTrainRsAlarm; + } + if ("ipModeTrainDoorAlarm" in data && data.ipModeTrainDoorAlarm != undefined) { + this.ipModeTrainDoorAlarm = data.ipModeTrainDoorAlarm; + } + if ("ipModeTrainEbAlarm" in data && data.ipModeTrainEbAlarm != undefined) { + this.ipModeTrainEbAlarm = data.ipModeTrainEbAlarm; + } + if ("ipModeTrainIntegrityAlarm" in data && data.ipModeTrainIntegrityAlarm != undefined) { + this.ipModeTrainIntegrityAlarm = data.ipModeTrainIntegrityAlarm; + } + if ("ipModeTrainDriveModeAm" in data && data.ipModeTrainDriveModeAm != undefined) { + this.ipModeTrainDriveModeAm = data.ipModeTrainDriveModeAm; + } + if ("ipModeTrainDriveModeCm" in data && data.ipModeTrainDriveModeCm != undefined) { + this.ipModeTrainDriveModeCm = data.ipModeTrainDriveModeCm; + } + if ("ipModeTrainDriveModeRmf" in data && data.ipModeTrainDriveModeRmf != undefined) { + this.ipModeTrainDriveModeRmf = data.ipModeTrainDriveModeRmf; + } + if ("ipModeTrainDriveModeDto" in data && data.ipModeTrainDriveModeDto != undefined) { + this.ipModeTrainDriveModeDto = data.ipModeTrainDriveModeDto; + } + if ("ipModeTrainDriveModeAtb" in data && data.ipModeTrainDriveModeAtb != undefined) { + this.ipModeTrainDriveModeAtb = data.ipModeTrainDriveModeAtb; + } + if ("ipModeTrainDriveBlockAm" in data && data.ipModeTrainDriveBlockAm != undefined) { + this.ipModeTrainDriveBlockAm = data.ipModeTrainDriveBlockAm; + } + if ("ipModeTrainDriveBlockCm" in data && data.ipModeTrainDriveBlockCm != undefined) { + this.ipModeTrainDriveBlockCm = data.ipModeTrainDriveBlockCm; + } + if ("ipModeTrainDriveModeRmr" in data && data.ipModeTrainDriveModeRmr != undefined) { + this.ipModeTrainDriveModeRmr = data.ipModeTrainDriveModeRmr; + } + if ("ipModeTrainDriveModeWash" in data && data.ipModeTrainDriveModeWash != undefined) { + this.ipModeTrainDriveModeWash = data.ipModeTrainDriveModeWash; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + } + } + get ipModeTrainTypeManual() { + return pb_1.Message.getFieldWithDefault(this, 1, false) as boolean; + } + set ipModeTrainTypeManual(value: boolean) { + pb_1.Message.setField(this, 1, value); + } + get ipModeTrainTypeHead() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set ipModeTrainTypeHead(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + get ipModeTrainTypeSpecial() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set ipModeTrainTypeSpecial(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get ipModeTrainTypeSchedule() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set ipModeTrainTypeSchedule(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get ipModeTrainTypeRoute() { + return pb_1.Message.getFieldWithDefault(this, 5, false) as boolean; + } + set ipModeTrainTypeRoute(value: boolean) { + pb_1.Message.setField(this, 5, value); + } + get ipModeTrainTypeShuttle() { + return pb_1.Message.getFieldWithDefault(this, 6, false) as boolean; + } + set ipModeTrainTypeShuttle(value: boolean) { + pb_1.Message.setField(this, 6, value); + } + get ipModeTrainTypeLineup() { + return pb_1.Message.getFieldWithDefault(this, 7, false) as boolean; + } + set ipModeTrainTypeLineup(value: boolean) { + pb_1.Message.setField(this, 7, value); + } + get ipModeTrainSchdEarly() { + return pb_1.Message.getFieldWithDefault(this, 8, false) as boolean; + } + set ipModeTrainSchdEarly(value: boolean) { + pb_1.Message.setField(this, 8, value); + } + get ipModeTrainSchdLate() { + return pb_1.Message.getFieldWithDefault(this, 9, false) as boolean; + } + set ipModeTrainSchdLate(value: boolean) { + pb_1.Message.setField(this, 9, value); + } + get ipModeTrainSkipstop() { + return pb_1.Message.getFieldWithDefault(this, 10, false) as boolean; + } + set ipModeTrainSkipstop(value: boolean) { + pb_1.Message.setField(this, 10, value); + } + get ipModeTrainCbtcMode() { + return pb_1.Message.getFieldWithDefault(this, 11, false) as boolean; + } + set ipModeTrainCbtcMode(value: boolean) { + pb_1.Message.setField(this, 11, value); + } + get ipModeTrainAtpCut() { + return pb_1.Message.getFieldWithDefault(this, 12, false) as boolean; + } + set ipModeTrainAtpCut(value: boolean) { + pb_1.Message.setField(this, 12, value); + } + get ipModeTrainBerthed() { + return pb_1.Message.getFieldWithDefault(this, 13, false) as boolean; + } + set ipModeTrainBerthed(value: boolean) { + pb_1.Message.setField(this, 13, value); + } + get ipModeTrainStoped() { + return pb_1.Message.getFieldWithDefault(this, 14, false) as boolean; + } + set ipModeTrainStoped(value: boolean) { + pb_1.Message.setField(this, 14, value); + } + get ipModeTrainHolded() { + return pb_1.Message.getFieldWithDefault(this, 15, false) as boolean; + } + set ipModeTrainHolded(value: boolean) { + pb_1.Message.setField(this, 15, value); + } + get ipModeTrainItama() { + return pb_1.Message.getFieldWithDefault(this, 16, false) as boolean; + } + set ipModeTrainItama(value: boolean) { + pb_1.Message.setField(this, 16, value); + } + get ipModeTrainDirUp() { + return pb_1.Message.getFieldWithDefault(this, 17, false) as boolean; + } + set ipModeTrainDirUp(value: boolean) { + pb_1.Message.setField(this, 17, value); + } + get ipModeTrainDirDown() { + return pb_1.Message.getFieldWithDefault(this, 18, false) as boolean; + } + set ipModeTrainDirDown(value: boolean) { + pb_1.Message.setField(this, 18, value); + } + get ipModeTrainDirHeadUp() { + return pb_1.Message.getFieldWithDefault(this, 19, false) as boolean; + } + set ipModeTrainDirHeadUp(value: boolean) { + pb_1.Message.setField(this, 19, value); + } + get ipModeTrainDirHeadDown() { + return pb_1.Message.getFieldWithDefault(this, 20, false) as boolean; + } + set ipModeTrainDirHeadDown(value: boolean) { + pb_1.Message.setField(this, 20, value); + } + get ipModeTrainDoorOpen() { + return pb_1.Message.getFieldWithDefault(this, 21, false) as boolean; + } + set ipModeTrainDoorOpen(value: boolean) { + pb_1.Message.setField(this, 21, value); + } + get ipModeTrainRsAlarm() { + return pb_1.Message.getFieldWithDefault(this, 22, false) as boolean; + } + set ipModeTrainRsAlarm(value: boolean) { + pb_1.Message.setField(this, 22, value); + } + get ipModeTrainDoorAlarm() { + return pb_1.Message.getFieldWithDefault(this, 23, false) as boolean; + } + set ipModeTrainDoorAlarm(value: boolean) { + pb_1.Message.setField(this, 23, value); + } + get ipModeTrainEbAlarm() { + return pb_1.Message.getFieldWithDefault(this, 24, false) as boolean; + } + set ipModeTrainEbAlarm(value: boolean) { + pb_1.Message.setField(this, 24, value); + } + get ipModeTrainIntegrityAlarm() { + return pb_1.Message.getFieldWithDefault(this, 25, false) as boolean; + } + set ipModeTrainIntegrityAlarm(value: boolean) { + pb_1.Message.setField(this, 25, value); + } + get ipModeTrainDriveModeAm() { + return pb_1.Message.getFieldWithDefault(this, 26, false) as boolean; + } + set ipModeTrainDriveModeAm(value: boolean) { + pb_1.Message.setField(this, 26, value); + } + get ipModeTrainDriveModeCm() { + return pb_1.Message.getFieldWithDefault(this, 27, false) as boolean; + } + set ipModeTrainDriveModeCm(value: boolean) { + pb_1.Message.setField(this, 27, value); + } + get ipModeTrainDriveModeRmf() { + return pb_1.Message.getFieldWithDefault(this, 28, false) as boolean; + } + set ipModeTrainDriveModeRmf(value: boolean) { + pb_1.Message.setField(this, 28, value); + } + get ipModeTrainDriveModeDto() { + return pb_1.Message.getFieldWithDefault(this, 29, false) as boolean; + } + set ipModeTrainDriveModeDto(value: boolean) { + pb_1.Message.setField(this, 29, value); + } + get ipModeTrainDriveModeAtb() { + return pb_1.Message.getFieldWithDefault(this, 30, false) as boolean; + } + set ipModeTrainDriveModeAtb(value: boolean) { + pb_1.Message.setField(this, 30, value); + } + get ipModeTrainDriveBlockAm() { + return pb_1.Message.getFieldWithDefault(this, 31, false) as boolean; + } + set ipModeTrainDriveBlockAm(value: boolean) { + pb_1.Message.setField(this, 31, value); + } + get ipModeTrainDriveBlockCm() { + return pb_1.Message.getFieldWithDefault(this, 32, false) as boolean; + } + set ipModeTrainDriveBlockCm(value: boolean) { + pb_1.Message.setField(this, 32, value); + } + get ipModeTrainDriveModeRmr() { + return pb_1.Message.getFieldWithDefault(this, 33, false) as boolean; + } + set ipModeTrainDriveModeRmr(value: boolean) { + pb_1.Message.setField(this, 33, value); + } + get ipModeTrainDriveModeWash() { + return pb_1.Message.getFieldWithDefault(this, 34, false) as boolean; + } + set ipModeTrainDriveModeWash(value: boolean) { + pb_1.Message.setField(this, 34, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 35, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 35, value); + } + static fromObject(data: { + ipModeTrainTypeManual?: boolean; + ipModeTrainTypeHead?: boolean; + ipModeTrainTypeSpecial?: boolean; + ipModeTrainTypeSchedule?: boolean; + ipModeTrainTypeRoute?: boolean; + ipModeTrainTypeShuttle?: boolean; + ipModeTrainTypeLineup?: boolean; + ipModeTrainSchdEarly?: boolean; + ipModeTrainSchdLate?: boolean; + ipModeTrainSkipstop?: boolean; + ipModeTrainCbtcMode?: boolean; + ipModeTrainAtpCut?: boolean; + ipModeTrainBerthed?: boolean; + ipModeTrainStoped?: boolean; + ipModeTrainHolded?: boolean; + ipModeTrainItama?: boolean; + ipModeTrainDirUp?: boolean; + ipModeTrainDirDown?: boolean; + ipModeTrainDirHeadUp?: boolean; + ipModeTrainDirHeadDown?: boolean; + ipModeTrainDoorOpen?: boolean; + ipModeTrainRsAlarm?: boolean; + ipModeTrainDoorAlarm?: boolean; + ipModeTrainEbAlarm?: boolean; + ipModeTrainIntegrityAlarm?: boolean; + ipModeTrainDriveModeAm?: boolean; + ipModeTrainDriveModeCm?: boolean; + ipModeTrainDriveModeRmf?: boolean; + ipModeTrainDriveModeDto?: boolean; + ipModeTrainDriveModeAtb?: boolean; + ipModeTrainDriveBlockAm?: boolean; + ipModeTrainDriveBlockCm?: boolean; + ipModeTrainDriveModeRmr?: boolean; + ipModeTrainDriveModeWash?: boolean; + id?: string; + }): TrainMode { + const message = new TrainMode({}); + if (data.ipModeTrainTypeManual != null) { + message.ipModeTrainTypeManual = data.ipModeTrainTypeManual; + } + if (data.ipModeTrainTypeHead != null) { + message.ipModeTrainTypeHead = data.ipModeTrainTypeHead; + } + if (data.ipModeTrainTypeSpecial != null) { + message.ipModeTrainTypeSpecial = data.ipModeTrainTypeSpecial; + } + if (data.ipModeTrainTypeSchedule != null) { + message.ipModeTrainTypeSchedule = data.ipModeTrainTypeSchedule; + } + if (data.ipModeTrainTypeRoute != null) { + message.ipModeTrainTypeRoute = data.ipModeTrainTypeRoute; + } + if (data.ipModeTrainTypeShuttle != null) { + message.ipModeTrainTypeShuttle = data.ipModeTrainTypeShuttle; + } + if (data.ipModeTrainTypeLineup != null) { + message.ipModeTrainTypeLineup = data.ipModeTrainTypeLineup; + } + if (data.ipModeTrainSchdEarly != null) { + message.ipModeTrainSchdEarly = data.ipModeTrainSchdEarly; + } + if (data.ipModeTrainSchdLate != null) { + message.ipModeTrainSchdLate = data.ipModeTrainSchdLate; + } + if (data.ipModeTrainSkipstop != null) { + message.ipModeTrainSkipstop = data.ipModeTrainSkipstop; + } + if (data.ipModeTrainCbtcMode != null) { + message.ipModeTrainCbtcMode = data.ipModeTrainCbtcMode; + } + if (data.ipModeTrainAtpCut != null) { + message.ipModeTrainAtpCut = data.ipModeTrainAtpCut; + } + if (data.ipModeTrainBerthed != null) { + message.ipModeTrainBerthed = data.ipModeTrainBerthed; + } + if (data.ipModeTrainStoped != null) { + message.ipModeTrainStoped = data.ipModeTrainStoped; + } + if (data.ipModeTrainHolded != null) { + message.ipModeTrainHolded = data.ipModeTrainHolded; + } + if (data.ipModeTrainItama != null) { + message.ipModeTrainItama = data.ipModeTrainItama; + } + if (data.ipModeTrainDirUp != null) { + message.ipModeTrainDirUp = data.ipModeTrainDirUp; + } + if (data.ipModeTrainDirDown != null) { + message.ipModeTrainDirDown = data.ipModeTrainDirDown; + } + if (data.ipModeTrainDirHeadUp != null) { + message.ipModeTrainDirHeadUp = data.ipModeTrainDirHeadUp; + } + if (data.ipModeTrainDirHeadDown != null) { + message.ipModeTrainDirHeadDown = data.ipModeTrainDirHeadDown; + } + if (data.ipModeTrainDoorOpen != null) { + message.ipModeTrainDoorOpen = data.ipModeTrainDoorOpen; + } + if (data.ipModeTrainRsAlarm != null) { + message.ipModeTrainRsAlarm = data.ipModeTrainRsAlarm; + } + if (data.ipModeTrainDoorAlarm != null) { + message.ipModeTrainDoorAlarm = data.ipModeTrainDoorAlarm; + } + if (data.ipModeTrainEbAlarm != null) { + message.ipModeTrainEbAlarm = data.ipModeTrainEbAlarm; + } + if (data.ipModeTrainIntegrityAlarm != null) { + message.ipModeTrainIntegrityAlarm = data.ipModeTrainIntegrityAlarm; + } + if (data.ipModeTrainDriveModeAm != null) { + message.ipModeTrainDriveModeAm = data.ipModeTrainDriveModeAm; + } + if (data.ipModeTrainDriveModeCm != null) { + message.ipModeTrainDriveModeCm = data.ipModeTrainDriveModeCm; + } + if (data.ipModeTrainDriveModeRmf != null) { + message.ipModeTrainDriveModeRmf = data.ipModeTrainDriveModeRmf; + } + if (data.ipModeTrainDriveModeDto != null) { + message.ipModeTrainDriveModeDto = data.ipModeTrainDriveModeDto; + } + if (data.ipModeTrainDriveModeAtb != null) { + message.ipModeTrainDriveModeAtb = data.ipModeTrainDriveModeAtb; + } + if (data.ipModeTrainDriveBlockAm != null) { + message.ipModeTrainDriveBlockAm = data.ipModeTrainDriveBlockAm; + } + if (data.ipModeTrainDriveBlockCm != null) { + message.ipModeTrainDriveBlockCm = data.ipModeTrainDriveBlockCm; + } + if (data.ipModeTrainDriveModeRmr != null) { + message.ipModeTrainDriveModeRmr = data.ipModeTrainDriveModeRmr; + } + if (data.ipModeTrainDriveModeWash != null) { + message.ipModeTrainDriveModeWash = data.ipModeTrainDriveModeWash; + } + if (data.id != null) { + message.id = data.id; + } + return message; + } + toObject() { + const data: { + ipModeTrainTypeManual?: boolean; + ipModeTrainTypeHead?: boolean; + ipModeTrainTypeSpecial?: boolean; + ipModeTrainTypeSchedule?: boolean; + ipModeTrainTypeRoute?: boolean; + ipModeTrainTypeShuttle?: boolean; + ipModeTrainTypeLineup?: boolean; + ipModeTrainSchdEarly?: boolean; + ipModeTrainSchdLate?: boolean; + ipModeTrainSkipstop?: boolean; + ipModeTrainCbtcMode?: boolean; + ipModeTrainAtpCut?: boolean; + ipModeTrainBerthed?: boolean; + ipModeTrainStoped?: boolean; + ipModeTrainHolded?: boolean; + ipModeTrainItama?: boolean; + ipModeTrainDirUp?: boolean; + ipModeTrainDirDown?: boolean; + ipModeTrainDirHeadUp?: boolean; + ipModeTrainDirHeadDown?: boolean; + ipModeTrainDoorOpen?: boolean; + ipModeTrainRsAlarm?: boolean; + ipModeTrainDoorAlarm?: boolean; + ipModeTrainEbAlarm?: boolean; + ipModeTrainIntegrityAlarm?: boolean; + ipModeTrainDriveModeAm?: boolean; + ipModeTrainDriveModeCm?: boolean; + ipModeTrainDriveModeRmf?: boolean; + ipModeTrainDriveModeDto?: boolean; + ipModeTrainDriveModeAtb?: boolean; + ipModeTrainDriveBlockAm?: boolean; + ipModeTrainDriveBlockCm?: boolean; + ipModeTrainDriveModeRmr?: boolean; + ipModeTrainDriveModeWash?: boolean; + id?: string; + } = {}; + if (this.ipModeTrainTypeManual != null) { + data.ipModeTrainTypeManual = this.ipModeTrainTypeManual; + } + if (this.ipModeTrainTypeHead != null) { + data.ipModeTrainTypeHead = this.ipModeTrainTypeHead; + } + if (this.ipModeTrainTypeSpecial != null) { + data.ipModeTrainTypeSpecial = this.ipModeTrainTypeSpecial; + } + if (this.ipModeTrainTypeSchedule != null) { + data.ipModeTrainTypeSchedule = this.ipModeTrainTypeSchedule; + } + if (this.ipModeTrainTypeRoute != null) { + data.ipModeTrainTypeRoute = this.ipModeTrainTypeRoute; + } + if (this.ipModeTrainTypeShuttle != null) { + data.ipModeTrainTypeShuttle = this.ipModeTrainTypeShuttle; + } + if (this.ipModeTrainTypeLineup != null) { + data.ipModeTrainTypeLineup = this.ipModeTrainTypeLineup; + } + if (this.ipModeTrainSchdEarly != null) { + data.ipModeTrainSchdEarly = this.ipModeTrainSchdEarly; + } + if (this.ipModeTrainSchdLate != null) { + data.ipModeTrainSchdLate = this.ipModeTrainSchdLate; + } + if (this.ipModeTrainSkipstop != null) { + data.ipModeTrainSkipstop = this.ipModeTrainSkipstop; + } + if (this.ipModeTrainCbtcMode != null) { + data.ipModeTrainCbtcMode = this.ipModeTrainCbtcMode; + } + if (this.ipModeTrainAtpCut != null) { + data.ipModeTrainAtpCut = this.ipModeTrainAtpCut; + } + if (this.ipModeTrainBerthed != null) { + data.ipModeTrainBerthed = this.ipModeTrainBerthed; + } + if (this.ipModeTrainStoped != null) { + data.ipModeTrainStoped = this.ipModeTrainStoped; + } + if (this.ipModeTrainHolded != null) { + data.ipModeTrainHolded = this.ipModeTrainHolded; + } + if (this.ipModeTrainItama != null) { + data.ipModeTrainItama = this.ipModeTrainItama; + } + if (this.ipModeTrainDirUp != null) { + data.ipModeTrainDirUp = this.ipModeTrainDirUp; + } + if (this.ipModeTrainDirDown != null) { + data.ipModeTrainDirDown = this.ipModeTrainDirDown; + } + if (this.ipModeTrainDirHeadUp != null) { + data.ipModeTrainDirHeadUp = this.ipModeTrainDirHeadUp; + } + if (this.ipModeTrainDirHeadDown != null) { + data.ipModeTrainDirHeadDown = this.ipModeTrainDirHeadDown; + } + if (this.ipModeTrainDoorOpen != null) { + data.ipModeTrainDoorOpen = this.ipModeTrainDoorOpen; + } + if (this.ipModeTrainRsAlarm != null) { + data.ipModeTrainRsAlarm = this.ipModeTrainRsAlarm; + } + if (this.ipModeTrainDoorAlarm != null) { + data.ipModeTrainDoorAlarm = this.ipModeTrainDoorAlarm; + } + if (this.ipModeTrainEbAlarm != null) { + data.ipModeTrainEbAlarm = this.ipModeTrainEbAlarm; + } + if (this.ipModeTrainIntegrityAlarm != null) { + data.ipModeTrainIntegrityAlarm = this.ipModeTrainIntegrityAlarm; + } + if (this.ipModeTrainDriveModeAm != null) { + data.ipModeTrainDriveModeAm = this.ipModeTrainDriveModeAm; + } + if (this.ipModeTrainDriveModeCm != null) { + data.ipModeTrainDriveModeCm = this.ipModeTrainDriveModeCm; + } + if (this.ipModeTrainDriveModeRmf != null) { + data.ipModeTrainDriveModeRmf = this.ipModeTrainDriveModeRmf; + } + if (this.ipModeTrainDriveModeDto != null) { + data.ipModeTrainDriveModeDto = this.ipModeTrainDriveModeDto; + } + if (this.ipModeTrainDriveModeAtb != null) { + data.ipModeTrainDriveModeAtb = this.ipModeTrainDriveModeAtb; + } + if (this.ipModeTrainDriveBlockAm != null) { + data.ipModeTrainDriveBlockAm = this.ipModeTrainDriveBlockAm; + } + if (this.ipModeTrainDriveBlockCm != null) { + data.ipModeTrainDriveBlockCm = this.ipModeTrainDriveBlockCm; + } + if (this.ipModeTrainDriveModeRmr != null) { + data.ipModeTrainDriveModeRmr = this.ipModeTrainDriveModeRmr; + } + if (this.ipModeTrainDriveModeWash != null) { + data.ipModeTrainDriveModeWash = this.ipModeTrainDriveModeWash; + } + if (this.id != null) { + data.id = this.id; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.ipModeTrainTypeManual != false) + writer.writeBool(1, this.ipModeTrainTypeManual); + if (this.ipModeTrainTypeHead != false) + writer.writeBool(2, this.ipModeTrainTypeHead); + if (this.ipModeTrainTypeSpecial != false) + writer.writeBool(3, this.ipModeTrainTypeSpecial); + if (this.ipModeTrainTypeSchedule != false) + writer.writeBool(4, this.ipModeTrainTypeSchedule); + if (this.ipModeTrainTypeRoute != false) + writer.writeBool(5, this.ipModeTrainTypeRoute); + if (this.ipModeTrainTypeShuttle != false) + writer.writeBool(6, this.ipModeTrainTypeShuttle); + if (this.ipModeTrainTypeLineup != false) + writer.writeBool(7, this.ipModeTrainTypeLineup); + if (this.ipModeTrainSchdEarly != false) + writer.writeBool(8, this.ipModeTrainSchdEarly); + if (this.ipModeTrainSchdLate != false) + writer.writeBool(9, this.ipModeTrainSchdLate); + if (this.ipModeTrainSkipstop != false) + writer.writeBool(10, this.ipModeTrainSkipstop); + if (this.ipModeTrainCbtcMode != false) + writer.writeBool(11, this.ipModeTrainCbtcMode); + if (this.ipModeTrainAtpCut != false) + writer.writeBool(12, this.ipModeTrainAtpCut); + if (this.ipModeTrainBerthed != false) + writer.writeBool(13, this.ipModeTrainBerthed); + if (this.ipModeTrainStoped != false) + writer.writeBool(14, this.ipModeTrainStoped); + if (this.ipModeTrainHolded != false) + writer.writeBool(15, this.ipModeTrainHolded); + if (this.ipModeTrainItama != false) + writer.writeBool(16, this.ipModeTrainItama); + if (this.ipModeTrainDirUp != false) + writer.writeBool(17, this.ipModeTrainDirUp); + if (this.ipModeTrainDirDown != false) + writer.writeBool(18, this.ipModeTrainDirDown); + if (this.ipModeTrainDirHeadUp != false) + writer.writeBool(19, this.ipModeTrainDirHeadUp); + if (this.ipModeTrainDirHeadDown != false) + writer.writeBool(20, this.ipModeTrainDirHeadDown); + if (this.ipModeTrainDoorOpen != false) + writer.writeBool(21, this.ipModeTrainDoorOpen); + if (this.ipModeTrainRsAlarm != false) + writer.writeBool(22, this.ipModeTrainRsAlarm); + if (this.ipModeTrainDoorAlarm != false) + writer.writeBool(23, this.ipModeTrainDoorAlarm); + if (this.ipModeTrainEbAlarm != false) + writer.writeBool(24, this.ipModeTrainEbAlarm); + if (this.ipModeTrainIntegrityAlarm != false) + writer.writeBool(25, this.ipModeTrainIntegrityAlarm); + if (this.ipModeTrainDriveModeAm != false) + writer.writeBool(26, this.ipModeTrainDriveModeAm); + if (this.ipModeTrainDriveModeCm != false) + writer.writeBool(27, this.ipModeTrainDriveModeCm); + if (this.ipModeTrainDriveModeRmf != false) + writer.writeBool(28, this.ipModeTrainDriveModeRmf); + if (this.ipModeTrainDriveModeDto != false) + writer.writeBool(29, this.ipModeTrainDriveModeDto); + if (this.ipModeTrainDriveModeAtb != false) + writer.writeBool(30, this.ipModeTrainDriveModeAtb); + if (this.ipModeTrainDriveBlockAm != false) + writer.writeBool(31, this.ipModeTrainDriveBlockAm); + if (this.ipModeTrainDriveBlockCm != false) + writer.writeBool(32, this.ipModeTrainDriveBlockCm); + if (this.ipModeTrainDriveModeRmr != false) + writer.writeBool(33, this.ipModeTrainDriveModeRmr); + if (this.ipModeTrainDriveModeWash != false) + writer.writeBool(34, this.ipModeTrainDriveModeWash); + if (this.id.length) + writer.writeString(35, this.id); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainMode { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainMode(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.ipModeTrainTypeManual = reader.readBool(); + break; + case 2: + message.ipModeTrainTypeHead = reader.readBool(); + break; + case 3: + message.ipModeTrainTypeSpecial = reader.readBool(); + break; + case 4: + message.ipModeTrainTypeSchedule = reader.readBool(); + break; + case 5: + message.ipModeTrainTypeRoute = reader.readBool(); + break; + case 6: + message.ipModeTrainTypeShuttle = reader.readBool(); + break; + case 7: + message.ipModeTrainTypeLineup = reader.readBool(); + break; + case 8: + message.ipModeTrainSchdEarly = reader.readBool(); + break; + case 9: + message.ipModeTrainSchdLate = reader.readBool(); + break; + case 10: + message.ipModeTrainSkipstop = reader.readBool(); + break; + case 11: + message.ipModeTrainCbtcMode = reader.readBool(); + break; + case 12: + message.ipModeTrainAtpCut = reader.readBool(); + break; + case 13: + message.ipModeTrainBerthed = reader.readBool(); + break; + case 14: + message.ipModeTrainStoped = reader.readBool(); + break; + case 15: + message.ipModeTrainHolded = reader.readBool(); + break; + case 16: + message.ipModeTrainItama = reader.readBool(); + break; + case 17: + message.ipModeTrainDirUp = reader.readBool(); + break; + case 18: + message.ipModeTrainDirDown = reader.readBool(); + break; + case 19: + message.ipModeTrainDirHeadUp = reader.readBool(); + break; + case 20: + message.ipModeTrainDirHeadDown = reader.readBool(); + break; + case 21: + message.ipModeTrainDoorOpen = reader.readBool(); + break; + case 22: + message.ipModeTrainRsAlarm = reader.readBool(); + break; + case 23: + message.ipModeTrainDoorAlarm = reader.readBool(); + break; + case 24: + message.ipModeTrainEbAlarm = reader.readBool(); + break; + case 25: + message.ipModeTrainIntegrityAlarm = reader.readBool(); + break; + case 26: + message.ipModeTrainDriveModeAm = reader.readBool(); + break; + case 27: + message.ipModeTrainDriveModeCm = reader.readBool(); + break; + case 28: + message.ipModeTrainDriveModeRmf = reader.readBool(); + break; + case 29: + message.ipModeTrainDriveModeDto = reader.readBool(); + break; + case 30: + message.ipModeTrainDriveModeAtb = reader.readBool(); + break; + case 31: + message.ipModeTrainDriveBlockAm = reader.readBool(); + break; + case 32: + message.ipModeTrainDriveBlockCm = reader.readBool(); + break; + case 33: + message.ipModeTrainDriveModeRmr = reader.readBool(); + break; + case 34: + message.ipModeTrainDriveModeWash = reader.readBool(); + break; + case 35: + message.id = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainMode { + return TrainMode.deserialize(bytes); + } + } + export class OccNccFepNetwork extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + id?: string; + active?: boolean; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("active" in data && data.active != undefined) { + this.active = data.active; + } + } + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 1, value); + } + get active() { + return pb_1.Message.getFieldWithDefault(this, 2, false) as boolean; + } + set active(value: boolean) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + id?: string; + active?: boolean; + }): OccNccFepNetwork { + const message = new OccNccFepNetwork({}); + if (data.id != null) { + message.id = data.id; + } + if (data.active != null) { + message.active = data.active; + } + return message; + } + toObject() { + const data: { + id?: string; + active?: boolean; + } = {}; + if (this.id != null) { + data.id = this.id; + } + if (this.active != null) { + data.active = this.active; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.id.length) + writer.writeString(1, this.id); + if (this.active != false) + writer.writeBool(2, this.active); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): OccNccFepNetwork { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new OccNccFepNetwork(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.id = reader.readString(); + break; + case 2: + message.active = reader.readBool(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): OccNccFepNetwork { + return OccNccFepNetwork.deserialize(bytes); + } + } +} diff --git a/src/protos/section_status.ts b/src/protos/section_status.ts new file mode 100644 index 0000000..8a6a587 --- /dev/null +++ b/src/protos/section_status.ts @@ -0,0 +1,219 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: section_status.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export namespace state { + export class Section extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + code?: string; + leftSection?: Section; + rightSection?: Section; + axleCounter?: boolean; + logicList?: Section[]; + leftKilometerCode?: string; + rightKilometerCode?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [5], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("leftSection" in data && data.leftSection != undefined) { + this.leftSection = data.leftSection; + } + if ("rightSection" in data && data.rightSection != undefined) { + this.rightSection = data.rightSection; + } + if ("axleCounter" in data && data.axleCounter != undefined) { + this.axleCounter = data.axleCounter; + } + if ("logicList" in data && data.logicList != undefined) { + this.logicList = data.logicList; + } + if ("leftKilometerCode" in data && data.leftKilometerCode != undefined) { + this.leftKilometerCode = data.leftKilometerCode; + } + if ("rightKilometerCode" in data && data.rightKilometerCode != undefined) { + this.rightKilometerCode = data.rightKilometerCode; + } + } + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 1, value); + } + get leftSection() { + return pb_1.Message.getWrapperField(this, Section, 2) as Section; + } + set leftSection(value: Section) { + pb_1.Message.setWrapperField(this, 2, value); + } + get has_leftSection() { + return pb_1.Message.getField(this, 2) != null; + } + get rightSection() { + return pb_1.Message.getWrapperField(this, Section, 3) as Section; + } + set rightSection(value: Section) { + pb_1.Message.setWrapperField(this, 3, value); + } + get has_rightSection() { + return pb_1.Message.getField(this, 3) != null; + } + get axleCounter() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set axleCounter(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get logicList() { + return pb_1.Message.getRepeatedWrapperField(this, Section, 5) as Section[]; + } + set logicList(value: Section[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } + get leftKilometerCode() { + return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + } + set leftKilometerCode(value: string) { + pb_1.Message.setField(this, 6, value); + } + get rightKilometerCode() { + return pb_1.Message.getFieldWithDefault(this, 7, "") as string; + } + set rightKilometerCode(value: string) { + pb_1.Message.setField(this, 7, value); + } + static fromObject(data: { + code?: string; + leftSection?: ReturnType; + rightSection?: ReturnType; + axleCounter?: boolean; + logicList?: ReturnType[]; + leftKilometerCode?: string; + rightKilometerCode?: string; + }): Section { + const message = new Section({}); + if (data.code != null) { + message.code = data.code; + } + if (data.leftSection != null) { + message.leftSection = Section.fromObject(data.leftSection); + } + if (data.rightSection != null) { + message.rightSection = Section.fromObject(data.rightSection); + } + if (data.axleCounter != null) { + message.axleCounter = data.axleCounter; + } + if (data.logicList != null) { + message.logicList = data.logicList.map(item => Section.fromObject(item)); + } + if (data.leftKilometerCode != null) { + message.leftKilometerCode = data.leftKilometerCode; + } + if (data.rightKilometerCode != null) { + message.rightKilometerCode = data.rightKilometerCode; + } + return message; + } + toObject() { + const data: { + code?: string; + leftSection?: ReturnType; + rightSection?: ReturnType; + axleCounter?: boolean; + logicList?: ReturnType[]; + leftKilometerCode?: string; + rightKilometerCode?: string; + } = {}; + if (this.code != null) { + data.code = this.code; + } + if (this.leftSection != null) { + data.leftSection = this.leftSection.toObject(); + } + if (this.rightSection != null) { + data.rightSection = this.rightSection.toObject(); + } + if (this.axleCounter != null) { + data.axleCounter = this.axleCounter; + } + if (this.logicList != null) { + data.logicList = this.logicList.map((item: Section) => item.toObject()); + } + if (this.leftKilometerCode != null) { + data.leftKilometerCode = this.leftKilometerCode; + } + if (this.rightKilometerCode != null) { + data.rightKilometerCode = this.rightKilometerCode; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.code.length) + writer.writeString(1, this.code); + if (this.has_leftSection) + writer.writeMessage(2, this.leftSection, () => this.leftSection.serialize(writer)); + if (this.has_rightSection) + writer.writeMessage(3, this.rightSection, () => this.rightSection.serialize(writer)); + if (this.axleCounter != false) + writer.writeBool(4, this.axleCounter); + if (this.logicList.length) + writer.writeRepeatedMessage(5, this.logicList, (item: Section) => item.serialize(writer)); + if (this.leftKilometerCode.length) + writer.writeString(6, this.leftKilometerCode); + if (this.rightKilometerCode.length) + writer.writeString(7, this.rightKilometerCode); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Section { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Section(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.code = reader.readString(); + break; + case 2: + reader.readMessage(message.leftSection, () => message.leftSection = Section.deserialize(reader)); + break; + case 3: + reader.readMessage(message.rightSection, () => message.rightSection = Section.deserialize(reader)); + break; + case 4: + message.axleCounter = reader.readBool(); + break; + case 5: + reader.readMessage(message.logicList, () => pb_1.Message.addToRepeatedWrapperField(message, 5, Section.deserialize(reader), Section)); + break; + case 6: + message.leftKilometerCode = reader.readString(); + break; + case 7: + message.rightKilometerCode = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Section { + return Section.deserialize(bytes); + } + } +} diff --git a/src/protos/stationLayoutGraphics.ts b/src/protos/stationLayoutGraphics.ts new file mode 100644 index 0000000..5beab30 --- /dev/null +++ b/src/protos/stationLayoutGraphics.ts @@ -0,0 +1,4126 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: stationLayoutGraphics.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as pb_1 from "google-protobuf"; +export namespace graphicData { + export class RtssGraphicStorage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + canvas?: Canvas; + links?: Link[]; + iscsFans?: IscsFan[]; + Platforms?: Platform[]; + stations?: Station[]; + rects?: Rect[]; + train?: Train[]; + signals?: Signal[]; + turnouts?: Turnout[]; + section?: Section[]; + stationLines?: StationLine[]; + runLines?: RunLine[]; + trainLines?: TrainLine[]; + pathLines?: PathLine[]; + polygons?: Polygon[]; + trainWindows?: TrainWindow[]; + axleCountings?: AxleCounting[]; + separators?: Separator[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("canvas" in data && data.canvas != undefined) { + this.canvas = data.canvas; + } + if ("links" in data && data.links != undefined) { + this.links = data.links; + } + if ("iscsFans" in data && data.iscsFans != undefined) { + this.iscsFans = data.iscsFans; + } + if ("Platforms" in data && data.Platforms != undefined) { + this.Platforms = data.Platforms; + } + if ("stations" in data && data.stations != undefined) { + this.stations = data.stations; + } + if ("rects" in data && data.rects != undefined) { + this.rects = data.rects; + } + if ("train" in data && data.train != undefined) { + this.train = data.train; + } + if ("signals" in data && data.signals != undefined) { + this.signals = data.signals; + } + if ("turnouts" in data && data.turnouts != undefined) { + this.turnouts = data.turnouts; + } + if ("section" in data && data.section != undefined) { + this.section = data.section; + } + if ("stationLines" in data && data.stationLines != undefined) { + this.stationLines = data.stationLines; + } + if ("runLines" in data && data.runLines != undefined) { + this.runLines = data.runLines; + } + if ("trainLines" in data && data.trainLines != undefined) { + this.trainLines = data.trainLines; + } + if ("pathLines" in data && data.pathLines != undefined) { + this.pathLines = data.pathLines; + } + if ("polygons" in data && data.polygons != undefined) { + this.polygons = data.polygons; + } + if ("trainWindows" in data && data.trainWindows != undefined) { + this.trainWindows = data.trainWindows; + } + if ("axleCountings" in data && data.axleCountings != undefined) { + this.axleCountings = data.axleCountings; + } + if ("separators" in data && data.separators != undefined) { + this.separators = data.separators; + } + } + } + get canvas() { + return pb_1.Message.getWrapperField(this, Canvas, 1) as Canvas; + } + set canvas(value: Canvas) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_canvas() { + return pb_1.Message.getField(this, 1) != null; + } + get links() { + return pb_1.Message.getRepeatedWrapperField(this, Link, 2) as Link[]; + } + set links(value: Link[]) { + pb_1.Message.setRepeatedWrapperField(this, 2, value); + } + get iscsFans() { + return pb_1.Message.getRepeatedWrapperField(this, IscsFan, 3) as IscsFan[]; + } + set iscsFans(value: IscsFan[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); + } + get Platforms() { + return pb_1.Message.getRepeatedWrapperField(this, Platform, 4) as Platform[]; + } + set Platforms(value: Platform[]) { + pb_1.Message.setRepeatedWrapperField(this, 4, value); + } + get stations() { + return pb_1.Message.getRepeatedWrapperField(this, Station, 5) as Station[]; + } + set stations(value: Station[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } + get rects() { + return pb_1.Message.getRepeatedWrapperField(this, Rect, 6) as Rect[]; + } + set rects(value: Rect[]) { + pb_1.Message.setRepeatedWrapperField(this, 6, value); + } + get train() { + return pb_1.Message.getRepeatedWrapperField(this, Train, 7) as Train[]; + } + set train(value: Train[]) { + pb_1.Message.setRepeatedWrapperField(this, 7, value); + } + get signals() { + return pb_1.Message.getRepeatedWrapperField(this, Signal, 8) as Signal[]; + } + set signals(value: Signal[]) { + pb_1.Message.setRepeatedWrapperField(this, 8, value); + } + get turnouts() { + return pb_1.Message.getRepeatedWrapperField(this, Turnout, 9) as Turnout[]; + } + set turnouts(value: Turnout[]) { + pb_1.Message.setRepeatedWrapperField(this, 9, value); + } + get section() { + return pb_1.Message.getRepeatedWrapperField(this, Section, 10) as Section[]; + } + set section(value: Section[]) { + pb_1.Message.setRepeatedWrapperField(this, 10, value); + } + get stationLines() { + return pb_1.Message.getRepeatedWrapperField(this, StationLine, 11) as StationLine[]; + } + set stationLines(value: StationLine[]) { + pb_1.Message.setRepeatedWrapperField(this, 11, value); + } + get runLines() { + return pb_1.Message.getRepeatedWrapperField(this, RunLine, 12) as RunLine[]; + } + set runLines(value: RunLine[]) { + pb_1.Message.setRepeatedWrapperField(this, 12, value); + } + get trainLines() { + return pb_1.Message.getRepeatedWrapperField(this, TrainLine, 13) as TrainLine[]; + } + set trainLines(value: TrainLine[]) { + pb_1.Message.setRepeatedWrapperField(this, 13, value); + } + get pathLines() { + return pb_1.Message.getRepeatedWrapperField(this, PathLine, 14) as PathLine[]; + } + set pathLines(value: PathLine[]) { + pb_1.Message.setRepeatedWrapperField(this, 14, value); + } + get polygons() { + return pb_1.Message.getRepeatedWrapperField(this, Polygon, 15) as Polygon[]; + } + set polygons(value: Polygon[]) { + pb_1.Message.setRepeatedWrapperField(this, 15, value); + } + get trainWindows() { + return pb_1.Message.getRepeatedWrapperField(this, TrainWindow, 16) as TrainWindow[]; + } + set trainWindows(value: TrainWindow[]) { + pb_1.Message.setRepeatedWrapperField(this, 16, value); + } + get axleCountings() { + return pb_1.Message.getRepeatedWrapperField(this, AxleCounting, 17) as AxleCounting[]; + } + set axleCountings(value: AxleCounting[]) { + pb_1.Message.setRepeatedWrapperField(this, 17, value); + } + get separators() { + return pb_1.Message.getRepeatedWrapperField(this, Separator, 18) as Separator[]; + } + set separators(value: Separator[]) { + pb_1.Message.setRepeatedWrapperField(this, 18, value); + } + static fromObject(data: { + canvas?: ReturnType; + links?: ReturnType[]; + iscsFans?: ReturnType[]; + Platforms?: ReturnType[]; + stations?: ReturnType[]; + rects?: ReturnType[]; + train?: ReturnType[]; + signals?: ReturnType[]; + turnouts?: ReturnType[]; + section?: ReturnType[]; + stationLines?: ReturnType[]; + runLines?: ReturnType[]; + trainLines?: ReturnType[]; + pathLines?: ReturnType[]; + polygons?: ReturnType[]; + trainWindows?: ReturnType[]; + axleCountings?: ReturnType[]; + separators?: ReturnType[]; + }): RtssGraphicStorage { + const message = new RtssGraphicStorage({}); + if (data.canvas != null) { + message.canvas = Canvas.fromObject(data.canvas); + } + if (data.links != null) { + message.links = data.links.map(item => Link.fromObject(item)); + } + if (data.iscsFans != null) { + message.iscsFans = data.iscsFans.map(item => IscsFan.fromObject(item)); + } + if (data.Platforms != null) { + message.Platforms = data.Platforms.map(item => Platform.fromObject(item)); + } + if (data.stations != null) { + message.stations = data.stations.map(item => Station.fromObject(item)); + } + if (data.rects != null) { + message.rects = data.rects.map(item => Rect.fromObject(item)); + } + if (data.train != null) { + message.train = data.train.map(item => Train.fromObject(item)); + } + if (data.signals != null) { + message.signals = data.signals.map(item => Signal.fromObject(item)); + } + if (data.turnouts != null) { + message.turnouts = data.turnouts.map(item => Turnout.fromObject(item)); + } + if (data.section != null) { + message.section = data.section.map(item => Section.fromObject(item)); + } + if (data.stationLines != null) { + message.stationLines = data.stationLines.map(item => StationLine.fromObject(item)); + } + if (data.runLines != null) { + message.runLines = data.runLines.map(item => RunLine.fromObject(item)); + } + if (data.trainLines != null) { + message.trainLines = data.trainLines.map(item => TrainLine.fromObject(item)); + } + if (data.pathLines != null) { + message.pathLines = data.pathLines.map(item => PathLine.fromObject(item)); + } + if (data.polygons != null) { + message.polygons = data.polygons.map(item => Polygon.fromObject(item)); + } + if (data.trainWindows != null) { + message.trainWindows = data.trainWindows.map(item => TrainWindow.fromObject(item)); + } + if (data.axleCountings != null) { + message.axleCountings = data.axleCountings.map(item => AxleCounting.fromObject(item)); + } + if (data.separators != null) { + message.separators = data.separators.map(item => Separator.fromObject(item)); + } + return message; + } + toObject() { + const data: { + canvas?: ReturnType; + links?: ReturnType[]; + iscsFans?: ReturnType[]; + Platforms?: ReturnType[]; + stations?: ReturnType[]; + rects?: ReturnType[]; + train?: ReturnType[]; + signals?: ReturnType[]; + turnouts?: ReturnType[]; + section?: ReturnType[]; + stationLines?: ReturnType[]; + runLines?: ReturnType[]; + trainLines?: ReturnType[]; + pathLines?: ReturnType[]; + polygons?: ReturnType[]; + trainWindows?: ReturnType[]; + axleCountings?: ReturnType[]; + separators?: ReturnType[]; + } = {}; + if (this.canvas != null) { + data.canvas = this.canvas.toObject(); + } + if (this.links != null) { + data.links = this.links.map((item: Link) => item.toObject()); + } + if (this.iscsFans != null) { + data.iscsFans = this.iscsFans.map((item: IscsFan) => item.toObject()); + } + if (this.Platforms != null) { + data.Platforms = this.Platforms.map((item: Platform) => item.toObject()); + } + if (this.stations != null) { + data.stations = this.stations.map((item: Station) => item.toObject()); + } + if (this.rects != null) { + data.rects = this.rects.map((item: Rect) => item.toObject()); + } + if (this.train != null) { + data.train = this.train.map((item: Train) => item.toObject()); + } + if (this.signals != null) { + data.signals = this.signals.map((item: Signal) => item.toObject()); + } + if (this.turnouts != null) { + data.turnouts = this.turnouts.map((item: Turnout) => item.toObject()); + } + if (this.section != null) { + data.section = this.section.map((item: Section) => item.toObject()); + } + if (this.stationLines != null) { + data.stationLines = this.stationLines.map((item: StationLine) => item.toObject()); + } + if (this.runLines != null) { + data.runLines = this.runLines.map((item: RunLine) => item.toObject()); + } + if (this.trainLines != null) { + data.trainLines = this.trainLines.map((item: TrainLine) => item.toObject()); + } + if (this.pathLines != null) { + data.pathLines = this.pathLines.map((item: PathLine) => item.toObject()); + } + if (this.polygons != null) { + data.polygons = this.polygons.map((item: Polygon) => item.toObject()); + } + if (this.trainWindows != null) { + data.trainWindows = this.trainWindows.map((item: TrainWindow) => item.toObject()); + } + if (this.axleCountings != null) { + data.axleCountings = this.axleCountings.map((item: AxleCounting) => item.toObject()); + } + if (this.separators != null) { + data.separators = this.separators.map((item: Separator) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_canvas) + writer.writeMessage(1, this.canvas, () => this.canvas.serialize(writer)); + if (this.links.length) + writer.writeRepeatedMessage(2, this.links, (item: Link) => item.serialize(writer)); + if (this.iscsFans.length) + writer.writeRepeatedMessage(3, this.iscsFans, (item: IscsFan) => item.serialize(writer)); + if (this.Platforms.length) + writer.writeRepeatedMessage(4, this.Platforms, (item: Platform) => item.serialize(writer)); + if (this.stations.length) + writer.writeRepeatedMessage(5, this.stations, (item: Station) => item.serialize(writer)); + if (this.rects.length) + writer.writeRepeatedMessage(6, this.rects, (item: Rect) => item.serialize(writer)); + if (this.train.length) + writer.writeRepeatedMessage(7, this.train, (item: Train) => item.serialize(writer)); + if (this.signals.length) + writer.writeRepeatedMessage(8, this.signals, (item: Signal) => item.serialize(writer)); + if (this.turnouts.length) + writer.writeRepeatedMessage(9, this.turnouts, (item: Turnout) => item.serialize(writer)); + if (this.section.length) + writer.writeRepeatedMessage(10, this.section, (item: Section) => item.serialize(writer)); + if (this.stationLines.length) + writer.writeRepeatedMessage(11, this.stationLines, (item: StationLine) => item.serialize(writer)); + if (this.runLines.length) + writer.writeRepeatedMessage(12, this.runLines, (item: RunLine) => item.serialize(writer)); + if (this.trainLines.length) + writer.writeRepeatedMessage(13, this.trainLines, (item: TrainLine) => item.serialize(writer)); + if (this.pathLines.length) + writer.writeRepeatedMessage(14, this.pathLines, (item: PathLine) => item.serialize(writer)); + if (this.polygons.length) + writer.writeRepeatedMessage(15, this.polygons, (item: Polygon) => item.serialize(writer)); + if (this.trainWindows.length) + writer.writeRepeatedMessage(16, this.trainWindows, (item: TrainWindow) => item.serialize(writer)); + if (this.axleCountings.length) + writer.writeRepeatedMessage(17, this.axleCountings, (item: AxleCounting) => item.serialize(writer)); + if (this.separators.length) + writer.writeRepeatedMessage(18, this.separators, (item: Separator) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): RtssGraphicStorage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new RtssGraphicStorage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.canvas, () => message.canvas = Canvas.deserialize(reader)); + break; + case 2: + reader.readMessage(message.links, () => pb_1.Message.addToRepeatedWrapperField(message, 2, Link.deserialize(reader), Link)); + break; + case 3: + reader.readMessage(message.iscsFans, () => pb_1.Message.addToRepeatedWrapperField(message, 3, IscsFan.deserialize(reader), IscsFan)); + break; + case 4: + reader.readMessage(message.Platforms, () => pb_1.Message.addToRepeatedWrapperField(message, 4, Platform.deserialize(reader), Platform)); + break; + case 5: + reader.readMessage(message.stations, () => pb_1.Message.addToRepeatedWrapperField(message, 5, Station.deserialize(reader), Station)); + break; + case 6: + reader.readMessage(message.rects, () => pb_1.Message.addToRepeatedWrapperField(message, 6, Rect.deserialize(reader), Rect)); + break; + case 7: + reader.readMessage(message.train, () => pb_1.Message.addToRepeatedWrapperField(message, 7, Train.deserialize(reader), Train)); + break; + case 8: + reader.readMessage(message.signals, () => pb_1.Message.addToRepeatedWrapperField(message, 8, Signal.deserialize(reader), Signal)); + break; + case 9: + reader.readMessage(message.turnouts, () => pb_1.Message.addToRepeatedWrapperField(message, 9, Turnout.deserialize(reader), Turnout)); + break; + case 10: + reader.readMessage(message.section, () => pb_1.Message.addToRepeatedWrapperField(message, 10, Section.deserialize(reader), Section)); + break; + case 11: + reader.readMessage(message.stationLines, () => pb_1.Message.addToRepeatedWrapperField(message, 11, StationLine.deserialize(reader), StationLine)); + break; + case 12: + reader.readMessage(message.runLines, () => pb_1.Message.addToRepeatedWrapperField(message, 12, RunLine.deserialize(reader), RunLine)); + break; + case 13: + reader.readMessage(message.trainLines, () => pb_1.Message.addToRepeatedWrapperField(message, 13, TrainLine.deserialize(reader), TrainLine)); + break; + case 14: + reader.readMessage(message.pathLines, () => pb_1.Message.addToRepeatedWrapperField(message, 14, PathLine.deserialize(reader), PathLine)); + break; + case 15: + reader.readMessage(message.polygons, () => pb_1.Message.addToRepeatedWrapperField(message, 15, Polygon.deserialize(reader), Polygon)); + break; + case 16: + reader.readMessage(message.trainWindows, () => pb_1.Message.addToRepeatedWrapperField(message, 16, TrainWindow.deserialize(reader), TrainWindow)); + break; + case 17: + reader.readMessage(message.axleCountings, () => pb_1.Message.addToRepeatedWrapperField(message, 17, AxleCounting.deserialize(reader), AxleCounting)); + break; + case 18: + reader.readMessage(message.separators, () => pb_1.Message.addToRepeatedWrapperField(message, 18, Separator.deserialize(reader), Separator)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): RtssGraphicStorage { + return RtssGraphicStorage.deserialize(bytes); + } + } + export class Canvas extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + width?: number; + height?: number; + backgroundColor?: string; + viewportTransform?: Transform; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("width" in data && data.width != undefined) { + this.width = data.width; + } + if ("height" in data && data.height != undefined) { + this.height = data.height; + } + if ("backgroundColor" in data && data.backgroundColor != undefined) { + this.backgroundColor = data.backgroundColor; + } + if ("viewportTransform" in data && data.viewportTransform != undefined) { + this.viewportTransform = data.viewportTransform; + } + } + } + get width() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set width(value: number) { + pb_1.Message.setField(this, 1, value); + } + get height() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set height(value: number) { + pb_1.Message.setField(this, 2, value); + } + get backgroundColor() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set backgroundColor(value: string) { + pb_1.Message.setField(this, 3, value); + } + get viewportTransform() { + return pb_1.Message.getWrapperField(this, Transform, 4) as Transform; + } + set viewportTransform(value: Transform) { + pb_1.Message.setWrapperField(this, 4, value); + } + get has_viewportTransform() { + return pb_1.Message.getField(this, 4) != null; + } + static fromObject(data: { + width?: number; + height?: number; + backgroundColor?: string; + viewportTransform?: ReturnType; + }): Canvas { + const message = new Canvas({}); + if (data.width != null) { + message.width = data.width; + } + if (data.height != null) { + message.height = data.height; + } + if (data.backgroundColor != null) { + message.backgroundColor = data.backgroundColor; + } + if (data.viewportTransform != null) { + message.viewportTransform = Transform.fromObject(data.viewportTransform); + } + return message; + } + toObject() { + const data: { + width?: number; + height?: number; + backgroundColor?: string; + viewportTransform?: ReturnType; + } = {}; + if (this.width != null) { + data.width = this.width; + } + if (this.height != null) { + data.height = this.height; + } + if (this.backgroundColor != null) { + data.backgroundColor = this.backgroundColor; + } + if (this.viewportTransform != null) { + data.viewportTransform = this.viewportTransform.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.width != 0) + writer.writeInt32(1, this.width); + if (this.height != 0) + writer.writeInt32(2, this.height); + if (this.backgroundColor.length) + writer.writeString(3, this.backgroundColor); + if (this.has_viewportTransform) + writer.writeMessage(4, this.viewportTransform, () => this.viewportTransform.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Canvas { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Canvas(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.width = reader.readInt32(); + break; + case 2: + message.height = reader.readInt32(); + break; + case 3: + message.backgroundColor = reader.readString(); + break; + case 4: + reader.readMessage(message.viewportTransform, () => message.viewportTransform = Transform.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Canvas { + return Canvas.deserialize(bytes); + } + } + export class Point extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + x?: number; + y?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("x" in data && data.x != undefined) { + this.x = data.x; + } + if ("y" in data && data.y != undefined) { + this.y = data.y; + } + } + } + get x() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set x(value: number) { + pb_1.Message.setField(this, 1, value); + } + get y() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set y(value: number) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + x?: number; + y?: number; + }): Point { + const message = new Point({}); + if (data.x != null) { + message.x = data.x; + } + if (data.y != null) { + message.y = data.y; + } + return message; + } + toObject() { + const data: { + x?: number; + y?: number; + } = {}; + if (this.x != null) { + data.x = this.x; + } + if (this.y != null) { + data.y = this.y; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.x != 0) + writer.writeFloat(1, this.x); + if (this.y != 0) + writer.writeFloat(2, this.y); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Point { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Point(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.x = reader.readFloat(); + break; + case 2: + message.y = reader.readFloat(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Point { + return Point.deserialize(bytes); + } + } + export class Transform extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + position?: Point; + scale?: Point; + rotation?: number; + skew?: Point; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("position" in data && data.position != undefined) { + this.position = data.position; + } + if ("scale" in data && data.scale != undefined) { + this.scale = data.scale; + } + if ("rotation" in data && data.rotation != undefined) { + this.rotation = data.rotation; + } + if ("skew" in data && data.skew != undefined) { + this.skew = data.skew; + } + } + } + get position() { + return pb_1.Message.getWrapperField(this, Point, 1) as Point; + } + set position(value: Point) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_position() { + return pb_1.Message.getField(this, 1) != null; + } + get scale() { + return pb_1.Message.getWrapperField(this, Point, 2) as Point; + } + set scale(value: Point) { + pb_1.Message.setWrapperField(this, 2, value); + } + get has_scale() { + return pb_1.Message.getField(this, 2) != null; + } + get rotation() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set rotation(value: number) { + pb_1.Message.setField(this, 3, value); + } + get skew() { + return pb_1.Message.getWrapperField(this, Point, 4) as Point; + } + set skew(value: Point) { + pb_1.Message.setWrapperField(this, 4, value); + } + get has_skew() { + return pb_1.Message.getField(this, 4) != null; + } + static fromObject(data: { + position?: ReturnType; + scale?: ReturnType; + rotation?: number; + skew?: ReturnType; + }): Transform { + const message = new Transform({}); + if (data.position != null) { + message.position = Point.fromObject(data.position); + } + if (data.scale != null) { + message.scale = Point.fromObject(data.scale); + } + if (data.rotation != null) { + message.rotation = data.rotation; + } + if (data.skew != null) { + message.skew = Point.fromObject(data.skew); + } + return message; + } + toObject() { + const data: { + position?: ReturnType; + scale?: ReturnType; + rotation?: number; + skew?: ReturnType; + } = {}; + if (this.position != null) { + data.position = this.position.toObject(); + } + if (this.scale != null) { + data.scale = this.scale.toObject(); + } + if (this.rotation != null) { + data.rotation = this.rotation; + } + if (this.skew != null) { + data.skew = this.skew.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_position) + writer.writeMessage(1, this.position, () => this.position.serialize(writer)); + if (this.has_scale) + writer.writeMessage(2, this.scale, () => this.scale.serialize(writer)); + if (this.rotation != 0) + writer.writeFloat(3, this.rotation); + if (this.has_skew) + writer.writeMessage(4, this.skew, () => this.skew.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Transform { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Transform(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.position, () => message.position = Point.deserialize(reader)); + break; + case 2: + reader.readMessage(message.scale, () => message.scale = Point.deserialize(reader)); + break; + case 3: + message.rotation = reader.readFloat(); + break; + case 4: + reader.readMessage(message.skew, () => message.skew = Point.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Transform { + return Transform.deserialize(bytes); + } + } + export class ChildTransform extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + name?: string; + transform?: Transform; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("name" in data && data.name != undefined) { + this.name = data.name; + } + if ("transform" in data && data.transform != undefined) { + this.transform = data.transform; + } + } + } + get name() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set name(value: string) { + pb_1.Message.setField(this, 1, value); + } + get transform() { + return pb_1.Message.getWrapperField(this, Transform, 2) as Transform; + } + set transform(value: Transform) { + pb_1.Message.setWrapperField(this, 2, value); + } + get has_transform() { + return pb_1.Message.getField(this, 2) != null; + } + static fromObject(data: { + name?: string; + transform?: ReturnType; + }): ChildTransform { + const message = new ChildTransform({}); + if (data.name != null) { + message.name = data.name; + } + if (data.transform != null) { + message.transform = Transform.fromObject(data.transform); + } + return message; + } + toObject() { + const data: { + name?: string; + transform?: ReturnType; + } = {}; + if (this.name != null) { + data.name = this.name; + } + if (this.transform != null) { + data.transform = this.transform.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.name.length) + writer.writeString(1, this.name); + if (this.has_transform) + writer.writeMessage(2, this.transform, () => this.transform.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): ChildTransform { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new ChildTransform(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.name = reader.readString(); + break; + case 2: + reader.readMessage(message.transform, () => message.transform = Transform.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): ChildTransform { + return ChildTransform.deserialize(bytes); + } + } + export class CommonInfo extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + id?: string; + graphicType?: string; + transform?: Transform; + childTransforms?: ChildTransform[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [4], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("graphicType" in data && data.graphicType != undefined) { + this.graphicType = data.graphicType; + } + if ("transform" in data && data.transform != undefined) { + this.transform = data.transform; + } + if ("childTransforms" in data && data.childTransforms != undefined) { + this.childTransforms = data.childTransforms; + } + } + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 1, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 1, value); + } + get graphicType() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set graphicType(value: string) { + pb_1.Message.setField(this, 2, value); + } + get transform() { + return pb_1.Message.getWrapperField(this, Transform, 3) as Transform; + } + set transform(value: Transform) { + pb_1.Message.setWrapperField(this, 3, value); + } + get has_transform() { + return pb_1.Message.getField(this, 3) != null; + } + get childTransforms() { + return pb_1.Message.getRepeatedWrapperField(this, ChildTransform, 4) as ChildTransform[]; + } + set childTransforms(value: ChildTransform[]) { + pb_1.Message.setRepeatedWrapperField(this, 4, value); + } + static fromObject(data: { + id?: string; + graphicType?: string; + transform?: ReturnType; + childTransforms?: ReturnType[]; + }): CommonInfo { + const message = new CommonInfo({}); + if (data.id != null) { + message.id = data.id; + } + if (data.graphicType != null) { + message.graphicType = data.graphicType; + } + if (data.transform != null) { + message.transform = Transform.fromObject(data.transform); + } + if (data.childTransforms != null) { + message.childTransforms = data.childTransforms.map(item => ChildTransform.fromObject(item)); + } + return message; + } + toObject() { + const data: { + id?: string; + graphicType?: string; + transform?: ReturnType; + childTransforms?: ReturnType[]; + } = {}; + if (this.id != null) { + data.id = this.id; + } + if (this.graphicType != null) { + data.graphicType = this.graphicType; + } + if (this.transform != null) { + data.transform = this.transform.toObject(); + } + if (this.childTransforms != null) { + data.childTransforms = this.childTransforms.map((item: ChildTransform) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.id.length) + writer.writeString(1, this.id); + if (this.graphicType.length) + writer.writeString(2, this.graphicType); + if (this.has_transform) + writer.writeMessage(3, this.transform, () => this.transform.serialize(writer)); + if (this.childTransforms.length) + writer.writeRepeatedMessage(4, this.childTransforms, (item: ChildTransform) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): CommonInfo { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new CommonInfo(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.id = reader.readString(); + break; + case 2: + message.graphicType = reader.readString(); + break; + case 3: + reader.readMessage(message.transform, () => message.transform = Transform.deserialize(reader)); + break; + case 4: + reader.readMessage(message.childTransforms, () => pb_1.Message.addToRepeatedWrapperField(message, 4, ChildTransform.deserialize(reader), ChildTransform)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): CommonInfo { + return CommonInfo.deserialize(bytes); + } + } + export class Link extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + curve?: boolean; + segmentsCount?: number; + lineWidth?: number; + lineColor?: string; + points?: Point[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [7], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("curve" in data && data.curve != undefined) { + this.curve = data.curve; + } + if ("segmentsCount" in data && data.segmentsCount != undefined) { + this.segmentsCount = data.segmentsCount; + } + if ("lineWidth" in data && data.lineWidth != undefined) { + this.lineWidth = data.lineWidth; + } + if ("lineColor" in data && data.lineColor != undefined) { + this.lineColor = data.lineColor; + } + if ("points" in data && data.points != undefined) { + this.points = data.points; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get curve() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set curve(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get segmentsCount() { + return pb_1.Message.getFieldWithDefault(this, 4, 0) as number; + } + set segmentsCount(value: number) { + pb_1.Message.setField(this, 4, value); + } + get lineWidth() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set lineWidth(value: number) { + pb_1.Message.setField(this, 5, value); + } + get lineColor() { + return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + } + set lineColor(value: string) { + pb_1.Message.setField(this, 6, value); + } + get points() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 7) as Point[]; + } + set points(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 7, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + curve?: boolean; + segmentsCount?: number; + lineWidth?: number; + lineColor?: string; + points?: ReturnType[]; + }): Link { + const message = new Link({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.curve != null) { + message.curve = data.curve; + } + if (data.segmentsCount != null) { + message.segmentsCount = data.segmentsCount; + } + if (data.lineWidth != null) { + message.lineWidth = data.lineWidth; + } + if (data.lineColor != null) { + message.lineColor = data.lineColor; + } + if (data.points != null) { + message.points = data.points.map(item => Point.fromObject(item)); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + curve?: boolean; + segmentsCount?: number; + lineWidth?: number; + lineColor?: string; + points?: ReturnType[]; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.curve != null) { + data.curve = this.curve; + } + if (this.segmentsCount != null) { + data.segmentsCount = this.segmentsCount; + } + if (this.lineWidth != null) { + data.lineWidth = this.lineWidth; + } + if (this.lineColor != null) { + data.lineColor = this.lineColor; + } + if (this.points != null) { + data.points = this.points.map((item: Point) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.curve != false) + writer.writeBool(3, this.curve); + if (this.segmentsCount != 0) + writer.writeInt32(4, this.segmentsCount); + if (this.lineWidth != 0) + writer.writeInt32(5, this.lineWidth); + if (this.lineColor.length) + writer.writeString(6, this.lineColor); + if (this.points.length) + writer.writeRepeatedMessage(7, this.points, (item: Point) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Link { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Link(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.curve = reader.readBool(); + break; + case 4: + message.segmentsCount = reader.readInt32(); + break; + case 5: + message.lineWidth = reader.readInt32(); + break; + case 6: + message.lineColor = reader.readString(); + break; + case 7: + reader.readMessage(message.points, () => pb_1.Message.addToRepeatedWrapperField(message, 7, Point.deserialize(reader), Point)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Link { + return Link.deserialize(bytes); + } + } + export class Rect extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + lineWidth?: number; + lineColor?: string; + width?: number; + height?: number; + radius?: number; + point?: Point; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("lineWidth" in data && data.lineWidth != undefined) { + this.lineWidth = data.lineWidth; + } + if ("lineColor" in data && data.lineColor != undefined) { + this.lineColor = data.lineColor; + } + if ("width" in data && data.width != undefined) { + this.width = data.width; + } + if ("height" in data && data.height != undefined) { + this.height = data.height; + } + if ("radius" in data && data.radius != undefined) { + this.radius = data.radius; + } + if ("point" in data && data.point != undefined) { + this.point = data.point; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get lineWidth() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set lineWidth(value: number) { + pb_1.Message.setField(this, 3, value); + } + get lineColor() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set lineColor(value: string) { + pb_1.Message.setField(this, 4, value); + } + get width() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set width(value: number) { + pb_1.Message.setField(this, 5, value); + } + get height() { + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; + } + set height(value: number) { + pb_1.Message.setField(this, 6, value); + } + get radius() { + return pb_1.Message.getFieldWithDefault(this, 7, 0) as number; + } + set radius(value: number) { + pb_1.Message.setField(this, 7, value); + } + get point() { + return pb_1.Message.getWrapperField(this, Point, 8) as Point; + } + set point(value: Point) { + pb_1.Message.setWrapperField(this, 8, value); + } + get has_point() { + return pb_1.Message.getField(this, 8) != null; + } + static fromObject(data: { + common?: ReturnType; + code?: string; + lineWidth?: number; + lineColor?: string; + width?: number; + height?: number; + radius?: number; + point?: ReturnType; + }): Rect { + const message = new Rect({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.lineWidth != null) { + message.lineWidth = data.lineWidth; + } + if (data.lineColor != null) { + message.lineColor = data.lineColor; + } + if (data.width != null) { + message.width = data.width; + } + if (data.height != null) { + message.height = data.height; + } + if (data.radius != null) { + message.radius = data.radius; + } + if (data.point != null) { + message.point = Point.fromObject(data.point); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + lineWidth?: number; + lineColor?: string; + width?: number; + height?: number; + radius?: number; + point?: ReturnType; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.lineWidth != null) { + data.lineWidth = this.lineWidth; + } + if (this.lineColor != null) { + data.lineColor = this.lineColor; + } + if (this.width != null) { + data.width = this.width; + } + if (this.height != null) { + data.height = this.height; + } + if (this.radius != null) { + data.radius = this.radius; + } + if (this.point != null) { + data.point = this.point.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.lineWidth != 0) + writer.writeInt32(3, this.lineWidth); + if (this.lineColor.length) + writer.writeString(4, this.lineColor); + if (this.width != 0) + writer.writeFloat(5, this.width); + if (this.height != 0) + writer.writeFloat(6, this.height); + if (this.radius != 0) + writer.writeInt32(7, this.radius); + if (this.has_point) + writer.writeMessage(8, this.point, () => this.point.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Rect { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Rect(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.lineWidth = reader.readInt32(); + break; + case 4: + message.lineColor = reader.readString(); + break; + case 5: + message.width = reader.readFloat(); + break; + case 6: + message.height = reader.readFloat(); + break; + case 7: + message.radius = reader.readInt32(); + break; + case 8: + reader.readMessage(message.point, () => message.point = Point.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Rect { + return Rect.deserialize(bytes); + } + } + export class Polygon extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + lineWidth?: number; + lineColor?: string; + points?: Point[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [5], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("lineWidth" in data && data.lineWidth != undefined) { + this.lineWidth = data.lineWidth; + } + if ("lineColor" in data && data.lineColor != undefined) { + this.lineColor = data.lineColor; + } + if ("points" in data && data.points != undefined) { + this.points = data.points; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get lineWidth() { + return pb_1.Message.getFieldWithDefault(this, 3, 0) as number; + } + set lineWidth(value: number) { + pb_1.Message.setField(this, 3, value); + } + get lineColor() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set lineColor(value: string) { + pb_1.Message.setField(this, 4, value); + } + get points() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 5) as Point[]; + } + set points(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + lineWidth?: number; + lineColor?: string; + points?: ReturnType[]; + }): Polygon { + const message = new Polygon({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.lineWidth != null) { + message.lineWidth = data.lineWidth; + } + if (data.lineColor != null) { + message.lineColor = data.lineColor; + } + if (data.points != null) { + message.points = data.points.map(item => Point.fromObject(item)); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + lineWidth?: number; + lineColor?: string; + points?: ReturnType[]; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.lineWidth != null) { + data.lineWidth = this.lineWidth; + } + if (this.lineColor != null) { + data.lineColor = this.lineColor; + } + if (this.points != null) { + data.points = this.points.map((item: Point) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.lineWidth != 0) + writer.writeInt32(3, this.lineWidth); + if (this.lineColor.length) + writer.writeString(4, this.lineColor); + if (this.points.length) + writer.writeRepeatedMessage(5, this.points, (item: Point) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Polygon { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Polygon(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.lineWidth = reader.readInt32(); + break; + case 4: + message.lineColor = reader.readString(); + break; + case 5: + reader.readMessage(message.points, () => pb_1.Message.addToRepeatedWrapperField(message, 5, Point.deserialize(reader), Point)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Polygon { + return Polygon.deserialize(bytes); + } + } + export class Platform extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + hasdoor?: boolean; + direction?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("hasdoor" in data && data.hasdoor != undefined) { + this.hasdoor = data.hasdoor; + } + if ("direction" in data && data.direction != undefined) { + this.direction = data.direction; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get hasdoor() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set hasdoor(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get direction() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set direction(value: string) { + pb_1.Message.setField(this, 4, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + hasdoor?: boolean; + direction?: string; + }): Platform { + const message = new Platform({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.hasdoor != null) { + message.hasdoor = data.hasdoor; + } + if (data.direction != null) { + message.direction = data.direction; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + hasdoor?: boolean; + direction?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.hasdoor != null) { + data.hasdoor = this.hasdoor; + } + if (this.direction != null) { + data.direction = this.direction; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.hasdoor != false) + writer.writeBool(3, this.hasdoor); + if (this.direction.length) + writer.writeString(4, this.direction); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Platform { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Platform(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.hasdoor = reader.readBool(); + break; + case 4: + message.direction = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Platform { + return Platform.deserialize(bytes); + } + } + export class Station extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + hasControl?: boolean; + concentrationStations?: boolean; + kilometerSystem?: KilometerSystem; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("hasControl" in data && data.hasControl != undefined) { + this.hasControl = data.hasControl; + } + if ("concentrationStations" in data && data.concentrationStations != undefined) { + this.concentrationStations = data.concentrationStations; + } + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get hasControl() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set hasControl(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get concentrationStations() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set concentrationStations(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get kilometerSystem() { + return pb_1.Message.getWrapperField(this, KilometerSystem, 6) as KilometerSystem; + } + set kilometerSystem(value: KilometerSystem) { + pb_1.Message.setWrapperField(this, 6, value); + } + get has_kilometerSystem() { + return pb_1.Message.getField(this, 6) != null; + } + static fromObject(data: { + common?: ReturnType; + code?: string; + hasControl?: boolean; + concentrationStations?: boolean; + kilometerSystem?: ReturnType; + }): Station { + const message = new Station({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.hasControl != null) { + message.hasControl = data.hasControl; + } + if (data.concentrationStations != null) { + message.concentrationStations = data.concentrationStations; + } + if (data.kilometerSystem != null) { + message.kilometerSystem = KilometerSystem.fromObject(data.kilometerSystem); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + hasControl?: boolean; + concentrationStations?: boolean; + kilometerSystem?: ReturnType; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.hasControl != null) { + data.hasControl = this.hasControl; + } + if (this.concentrationStations != null) { + data.concentrationStations = this.concentrationStations; + } + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.hasControl != false) + writer.writeBool(3, this.hasControl); + if (this.concentrationStations != false) + writer.writeBool(4, this.concentrationStations); + if (this.has_kilometerSystem) + writer.writeMessage(6, this.kilometerSystem, () => this.kilometerSystem.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Station { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Station(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.hasControl = reader.readBool(); + break; + case 4: + message.concentrationStations = reader.readBool(); + break; + case 6: + reader.readMessage(message.kilometerSystem, () => message.kilometerSystem = KilometerSystem.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Station { + return Station.deserialize(bytes); + } + } + export class StationLine extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + hasTransfer?: boolean; + hideName?: boolean; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("hasTransfer" in data && data.hasTransfer != undefined) { + this.hasTransfer = data.hasTransfer; + } + if ("hideName" in data && data.hideName != undefined) { + this.hideName = data.hideName; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get hasTransfer() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set hasTransfer(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get hideName() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set hideName(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + hasTransfer?: boolean; + hideName?: boolean; + }): StationLine { + const message = new StationLine({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.hasTransfer != null) { + message.hasTransfer = data.hasTransfer; + } + if (data.hideName != null) { + message.hideName = data.hideName; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + hasTransfer?: boolean; + hideName?: boolean; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.hasTransfer != null) { + data.hasTransfer = this.hasTransfer; + } + if (this.hideName != null) { + data.hideName = this.hideName; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.hasTransfer != false) + writer.writeBool(3, this.hasTransfer); + if (this.hideName != false) + writer.writeBool(4, this.hideName); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): StationLine { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new StationLine(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.hasTransfer = reader.readBool(); + break; + case 4: + message.hideName = reader.readBool(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): StationLine { + return StationLine.deserialize(bytes); + } + } + export class TrainWindow extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + sectionId?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("sectionId" in data && data.sectionId != undefined) { + this.sectionId = data.sectionId; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get sectionId() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set sectionId(value: string) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + sectionId?: string; + }): TrainWindow { + const message = new TrainWindow({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.sectionId != null) { + message.sectionId = data.sectionId; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + sectionId?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.sectionId != null) { + data.sectionId = this.sectionId; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.sectionId.length) + writer.writeString(3, this.sectionId); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainWindow { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainWindow(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.sectionId = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainWindow { + return TrainWindow.deserialize(bytes); + } + } + export class AxleCounting extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + kilometerSystem?: KilometerSystem; + axleCountingRef?: RelatedRef[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [4], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; + } + if ("axleCountingRef" in data && data.axleCountingRef != undefined) { + this.axleCountingRef = data.axleCountingRef; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get kilometerSystem() { + return pb_1.Message.getWrapperField(this, KilometerSystem, 3) as KilometerSystem; + } + set kilometerSystem(value: KilometerSystem) { + pb_1.Message.setWrapperField(this, 3, value); + } + get has_kilometerSystem() { + return pb_1.Message.getField(this, 3) != null; + } + get axleCountingRef() { + return pb_1.Message.getRepeatedWrapperField(this, RelatedRef, 4) as RelatedRef[]; + } + set axleCountingRef(value: RelatedRef[]) { + pb_1.Message.setRepeatedWrapperField(this, 4, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + kilometerSystem?: ReturnType; + axleCountingRef?: ReturnType[]; + }): AxleCounting { + const message = new AxleCounting({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.kilometerSystem != null) { + message.kilometerSystem = KilometerSystem.fromObject(data.kilometerSystem); + } + if (data.axleCountingRef != null) { + message.axleCountingRef = data.axleCountingRef.map(item => RelatedRef.fromObject(item)); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + kilometerSystem?: ReturnType; + axleCountingRef?: ReturnType[]; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.toObject(); + } + if (this.axleCountingRef != null) { + data.axleCountingRef = this.axleCountingRef.map((item: RelatedRef) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.has_kilometerSystem) + writer.writeMessage(3, this.kilometerSystem, () => this.kilometerSystem.serialize(writer)); + if (this.axleCountingRef.length) + writer.writeRepeatedMessage(4, this.axleCountingRef, (item: RelatedRef) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): AxleCounting { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new AxleCounting(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + reader.readMessage(message.kilometerSystem, () => message.kilometerSystem = KilometerSystem.deserialize(reader)); + break; + case 4: + reader.readMessage(message.axleCountingRef, () => pb_1.Message.addToRepeatedWrapperField(message, 4, RelatedRef.deserialize(reader), RelatedRef)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): AxleCounting { + return AxleCounting.deserialize(bytes); + } + } + export class Train extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + }): Train { + const message = new Train({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Train { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Train(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Train { + return Train.deserialize(bytes); + } + } + export class TrainLine extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + }): TrainLine { + const message = new TrainLine({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainLine { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainLine(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainLine { + return TrainLine.deserialize(bytes); + } + } + export class IscsFan extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + }): IscsFan { + const message = new IscsFan({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): IscsFan { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new IscsFan(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): IscsFan { + return IscsFan.deserialize(bytes); + } + } + export class Turnout extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + pointA?: Point[]; + pointB?: Point[]; + pointC?: Point[]; + paRef?: RelatedRef; + pbRef?: RelatedRef; + pcRef?: RelatedRef; + kilometerSystem?: KilometerSystem[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [6, 7, 8, 13], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("pointA" in data && data.pointA != undefined) { + this.pointA = data.pointA; + } + if ("pointB" in data && data.pointB != undefined) { + this.pointB = data.pointB; + } + if ("pointC" in data && data.pointC != undefined) { + this.pointC = data.pointC; + } + if ("paRef" in data && data.paRef != undefined) { + this.paRef = data.paRef; + } + if ("pbRef" in data && data.pbRef != undefined) { + this.pbRef = data.pbRef; + } + if ("pcRef" in data && data.pcRef != undefined) { + this.pcRef = data.pcRef; + } + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get pointA() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 6) as Point[]; + } + set pointA(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 6, value); + } + get pointB() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 7) as Point[]; + } + set pointB(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 7, value); + } + get pointC() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 8) as Point[]; + } + set pointC(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 8, value); + } + get paRef() { + return pb_1.Message.getWrapperField(this, RelatedRef, 9) as RelatedRef; + } + set paRef(value: RelatedRef) { + pb_1.Message.setWrapperField(this, 9, value); + } + get has_paRef() { + return pb_1.Message.getField(this, 9) != null; + } + get pbRef() { + return pb_1.Message.getWrapperField(this, RelatedRef, 10) as RelatedRef; + } + set pbRef(value: RelatedRef) { + pb_1.Message.setWrapperField(this, 10, value); + } + get has_pbRef() { + return pb_1.Message.getField(this, 10) != null; + } + get pcRef() { + return pb_1.Message.getWrapperField(this, RelatedRef, 11) as RelatedRef; + } + set pcRef(value: RelatedRef) { + pb_1.Message.setWrapperField(this, 11, value); + } + get has_pcRef() { + return pb_1.Message.getField(this, 11) != null; + } + get kilometerSystem() { + return pb_1.Message.getRepeatedWrapperField(this, KilometerSystem, 13) as KilometerSystem[]; + } + set kilometerSystem(value: KilometerSystem[]) { + pb_1.Message.setRepeatedWrapperField(this, 13, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + pointA?: ReturnType[]; + pointB?: ReturnType[]; + pointC?: ReturnType[]; + paRef?: ReturnType; + pbRef?: ReturnType; + pcRef?: ReturnType; + kilometerSystem?: ReturnType[]; + }): Turnout { + const message = new Turnout({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.pointA != null) { + message.pointA = data.pointA.map(item => Point.fromObject(item)); + } + if (data.pointB != null) { + message.pointB = data.pointB.map(item => Point.fromObject(item)); + } + if (data.pointC != null) { + message.pointC = data.pointC.map(item => Point.fromObject(item)); + } + if (data.paRef != null) { + message.paRef = RelatedRef.fromObject(data.paRef); + } + if (data.pbRef != null) { + message.pbRef = RelatedRef.fromObject(data.pbRef); + } + if (data.pcRef != null) { + message.pcRef = RelatedRef.fromObject(data.pcRef); + } + if (data.kilometerSystem != null) { + message.kilometerSystem = data.kilometerSystem.map(item => KilometerSystem.fromObject(item)); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + pointA?: ReturnType[]; + pointB?: ReturnType[]; + pointC?: ReturnType[]; + paRef?: ReturnType; + pbRef?: ReturnType; + pcRef?: ReturnType; + kilometerSystem?: ReturnType[]; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.pointA != null) { + data.pointA = this.pointA.map((item: Point) => item.toObject()); + } + if (this.pointB != null) { + data.pointB = this.pointB.map((item: Point) => item.toObject()); + } + if (this.pointC != null) { + data.pointC = this.pointC.map((item: Point) => item.toObject()); + } + if (this.paRef != null) { + data.paRef = this.paRef.toObject(); + } + if (this.pbRef != null) { + data.pbRef = this.pbRef.toObject(); + } + if (this.pcRef != null) { + data.pcRef = this.pcRef.toObject(); + } + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.map((item: KilometerSystem) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.pointA.length) + writer.writeRepeatedMessage(6, this.pointA, (item: Point) => item.serialize(writer)); + if (this.pointB.length) + writer.writeRepeatedMessage(7, this.pointB, (item: Point) => item.serialize(writer)); + if (this.pointC.length) + writer.writeRepeatedMessage(8, this.pointC, (item: Point) => item.serialize(writer)); + if (this.has_paRef) + writer.writeMessage(9, this.paRef, () => this.paRef.serialize(writer)); + if (this.has_pbRef) + writer.writeMessage(10, this.pbRef, () => this.pbRef.serialize(writer)); + if (this.has_pcRef) + writer.writeMessage(11, this.pcRef, () => this.pcRef.serialize(writer)); + if (this.kilometerSystem.length) + writer.writeRepeatedMessage(13, this.kilometerSystem, (item: KilometerSystem) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Turnout { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Turnout(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 6: + reader.readMessage(message.pointA, () => pb_1.Message.addToRepeatedWrapperField(message, 6, Point.deserialize(reader), Point)); + break; + case 7: + reader.readMessage(message.pointB, () => pb_1.Message.addToRepeatedWrapperField(message, 7, Point.deserialize(reader), Point)); + break; + case 8: + reader.readMessage(message.pointC, () => pb_1.Message.addToRepeatedWrapperField(message, 8, Point.deserialize(reader), Point)); + break; + case 9: + reader.readMessage(message.paRef, () => message.paRef = RelatedRef.deserialize(reader)); + break; + case 10: + reader.readMessage(message.pbRef, () => message.pbRef = RelatedRef.deserialize(reader)); + break; + case 11: + reader.readMessage(message.pcRef, () => message.pcRef = RelatedRef.deserialize(reader)); + break; + case 13: + reader.readMessage(message.kilometerSystem, () => pb_1.Message.addToRepeatedWrapperField(message, 13, KilometerSystem.deserialize(reader), KilometerSystem)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Turnout { + return Turnout.deserialize(bytes); + } + } + export class KilometerSystem extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + kilometer?: number; + coordinateSystem?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("kilometer" in data && data.kilometer != undefined) { + this.kilometer = data.kilometer; + } + if ("coordinateSystem" in data && data.coordinateSystem != undefined) { + this.coordinateSystem = data.coordinateSystem; + } + } + } + get kilometer() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set kilometer(value: number) { + pb_1.Message.setField(this, 1, value); + } + get coordinateSystem() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set coordinateSystem(value: string) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + kilometer?: number; + coordinateSystem?: string; + }): KilometerSystem { + const message = new KilometerSystem({}); + if (data.kilometer != null) { + message.kilometer = data.kilometer; + } + if (data.coordinateSystem != null) { + message.coordinateSystem = data.coordinateSystem; + } + return message; + } + toObject() { + const data: { + kilometer?: number; + coordinateSystem?: string; + } = {}; + if (this.kilometer != null) { + data.kilometer = this.kilometer; + } + if (this.coordinateSystem != null) { + data.coordinateSystem = this.coordinateSystem; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.kilometer != 0) + writer.writeInt64(1, this.kilometer); + if (this.coordinateSystem.length) + writer.writeString(2, this.coordinateSystem); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): KilometerSystem { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new KilometerSystem(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.kilometer = reader.readInt64(); + break; + case 2: + message.coordinateSystem = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): KilometerSystem { + return KilometerSystem.deserialize(bytes); + } + } + export class Signal extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + mirror?: boolean; + kilometerSystem?: KilometerSystem; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("mirror" in data && data.mirror != undefined) { + this.mirror = data.mirror; + } + if ("kilometerSystem" in data && data.kilometerSystem != undefined) { + this.kilometerSystem = data.kilometerSystem; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get mirror() { + return pb_1.Message.getFieldWithDefault(this, 3, false) as boolean; + } + set mirror(value: boolean) { + pb_1.Message.setField(this, 3, value); + } + get kilometerSystem() { + return pb_1.Message.getWrapperField(this, KilometerSystem, 6) as KilometerSystem; + } + set kilometerSystem(value: KilometerSystem) { + pb_1.Message.setWrapperField(this, 6, value); + } + get has_kilometerSystem() { + return pb_1.Message.getField(this, 6) != null; + } + static fromObject(data: { + common?: ReturnType; + code?: string; + mirror?: boolean; + kilometerSystem?: ReturnType; + }): Signal { + const message = new Signal({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.mirror != null) { + message.mirror = data.mirror; + } + if (data.kilometerSystem != null) { + message.kilometerSystem = KilometerSystem.fromObject(data.kilometerSystem); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + mirror?: boolean; + kilometerSystem?: ReturnType; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.mirror != null) { + data.mirror = this.mirror; + } + if (this.kilometerSystem != null) { + data.kilometerSystem = this.kilometerSystem.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.mirror != false) + writer.writeBool(3, this.mirror); + if (this.has_kilometerSystem) + writer.writeMessage(6, this.kilometerSystem, () => this.kilometerSystem.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Signal { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Signal(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.mirror = reader.readBool(); + break; + case 6: + reader.readMessage(message.kilometerSystem, () => message.kilometerSystem = KilometerSystem.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Signal { + return Signal.deserialize(bytes); + } + } + export class RunLine extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + points?: Point[]; + nameColor?: string; + nameBgColor?: string; + containSta?: string[]; + linkPathLines?: string[]; + lineId?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [3, 8, 9], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("points" in data && data.points != undefined) { + this.points = data.points; + } + if ("nameColor" in data && data.nameColor != undefined) { + this.nameColor = data.nameColor; + } + if ("nameBgColor" in data && data.nameBgColor != undefined) { + this.nameBgColor = data.nameBgColor; + } + if ("containSta" in data && data.containSta != undefined) { + this.containSta = data.containSta; + } + if ("linkPathLines" in data && data.linkPathLines != undefined) { + this.linkPathLines = data.linkPathLines; + } + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get points() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 3) as Point[]; + } + set points(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); + } + get nameColor() { + return pb_1.Message.getFieldWithDefault(this, 4, "") as string; + } + set nameColor(value: string) { + pb_1.Message.setField(this, 4, value); + } + get nameBgColor() { + return pb_1.Message.getFieldWithDefault(this, 5, "") as string; + } + set nameBgColor(value: string) { + pb_1.Message.setField(this, 5, value); + } + get containSta() { + return pb_1.Message.getFieldWithDefault(this, 8, []) as string[]; + } + set containSta(value: string[]) { + pb_1.Message.setField(this, 8, value); + } + get linkPathLines() { + return pb_1.Message.getFieldWithDefault(this, 9, []) as string[]; + } + set linkPathLines(value: string[]) { + pb_1.Message.setField(this, 9, value); + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 10, "") as string; + } + set lineId(value: string) { + pb_1.Message.setField(this, 10, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + points?: ReturnType[]; + nameColor?: string; + nameBgColor?: string; + containSta?: string[]; + linkPathLines?: string[]; + lineId?: string; + }): RunLine { + const message = new RunLine({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.points != null) { + message.points = data.points.map(item => Point.fromObject(item)); + } + if (data.nameColor != null) { + message.nameColor = data.nameColor; + } + if (data.nameBgColor != null) { + message.nameBgColor = data.nameBgColor; + } + if (data.containSta != null) { + message.containSta = data.containSta; + } + if (data.linkPathLines != null) { + message.linkPathLines = data.linkPathLines; + } + if (data.lineId != null) { + message.lineId = data.lineId; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + points?: ReturnType[]; + nameColor?: string; + nameBgColor?: string; + containSta?: string[]; + linkPathLines?: string[]; + lineId?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.points != null) { + data.points = this.points.map((item: Point) => item.toObject()); + } + if (this.nameColor != null) { + data.nameColor = this.nameColor; + } + if (this.nameBgColor != null) { + data.nameBgColor = this.nameBgColor; + } + if (this.containSta != null) { + data.containSta = this.containSta; + } + if (this.linkPathLines != null) { + data.linkPathLines = this.linkPathLines; + } + if (this.lineId != null) { + data.lineId = this.lineId; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.points.length) + writer.writeRepeatedMessage(3, this.points, (item: Point) => item.serialize(writer)); + if (this.nameColor.length) + writer.writeString(4, this.nameColor); + if (this.nameBgColor.length) + writer.writeString(5, this.nameBgColor); + if (this.containSta.length) + writer.writeRepeatedString(8, this.containSta); + if (this.linkPathLines.length) + writer.writeRepeatedString(9, this.linkPathLines); + if (this.lineId.length) + writer.writeString(10, this.lineId); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): RunLine { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new RunLine(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + reader.readMessage(message.points, () => pb_1.Message.addToRepeatedWrapperField(message, 3, Point.deserialize(reader), Point)); + break; + case 4: + message.nameColor = reader.readString(); + break; + case 5: + message.nameBgColor = reader.readString(); + break; + case 8: + pb_1.Message.addToRepeatedField(message, 8, reader.readString()); + break; + case 9: + pb_1.Message.addToRepeatedField(message, 9, reader.readString()); + break; + case 10: + message.lineId = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): RunLine { + return RunLine.deserialize(bytes); + } + } + export class Section extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + points?: Point[]; + paRef?: RelatedRef; + pbRef?: RelatedRef; + sectionType?: Section.SectionType; + children?: string[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [3, 7], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("points" in data && data.points != undefined) { + this.points = data.points; + } + if ("paRef" in data && data.paRef != undefined) { + this.paRef = data.paRef; + } + if ("pbRef" in data && data.pbRef != undefined) { + this.pbRef = data.pbRef; + } + if ("sectionType" in data && data.sectionType != undefined) { + this.sectionType = data.sectionType; + } + if ("children" in data && data.children != undefined) { + this.children = data.children; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get points() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 3) as Point[]; + } + set points(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); + } + get paRef() { + return pb_1.Message.getWrapperField(this, RelatedRef, 4) as RelatedRef; + } + set paRef(value: RelatedRef) { + pb_1.Message.setWrapperField(this, 4, value); + } + get has_paRef() { + return pb_1.Message.getField(this, 4) != null; + } + get pbRef() { + return pb_1.Message.getWrapperField(this, RelatedRef, 5) as RelatedRef; + } + set pbRef(value: RelatedRef) { + pb_1.Message.setWrapperField(this, 5, value); + } + get has_pbRef() { + return pb_1.Message.getField(this, 5) != null; + } + get sectionType() { + return pb_1.Message.getFieldWithDefault(this, 6, Section.SectionType.Physical) as Section.SectionType; + } + set sectionType(value: Section.SectionType) { + pb_1.Message.setField(this, 6, value); + } + get children() { + return pb_1.Message.getFieldWithDefault(this, 7, []) as string[]; + } + set children(value: string[]) { + pb_1.Message.setField(this, 7, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + points?: ReturnType[]; + paRef?: ReturnType; + pbRef?: ReturnType; + sectionType?: Section.SectionType; + children?: string[]; + }): Section { + const message = new Section({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.points != null) { + message.points = data.points.map(item => Point.fromObject(item)); + } + if (data.paRef != null) { + message.paRef = RelatedRef.fromObject(data.paRef); + } + if (data.pbRef != null) { + message.pbRef = RelatedRef.fromObject(data.pbRef); + } + if (data.sectionType != null) { + message.sectionType = data.sectionType; + } + if (data.children != null) { + message.children = data.children; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + points?: ReturnType[]; + paRef?: ReturnType; + pbRef?: ReturnType; + sectionType?: Section.SectionType; + children?: string[]; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.points != null) { + data.points = this.points.map((item: Point) => item.toObject()); + } + if (this.paRef != null) { + data.paRef = this.paRef.toObject(); + } + if (this.pbRef != null) { + data.pbRef = this.pbRef.toObject(); + } + if (this.sectionType != null) { + data.sectionType = this.sectionType; + } + if (this.children != null) { + data.children = this.children; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.points.length) + writer.writeRepeatedMessage(3, this.points, (item: Point) => item.serialize(writer)); + if (this.has_paRef) + writer.writeMessage(4, this.paRef, () => this.paRef.serialize(writer)); + if (this.has_pbRef) + writer.writeMessage(5, this.pbRef, () => this.pbRef.serialize(writer)); + if (this.sectionType != Section.SectionType.Physical) + writer.writeEnum(6, this.sectionType); + if (this.children.length) + writer.writeRepeatedString(7, this.children); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Section { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Section(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + reader.readMessage(message.points, () => pb_1.Message.addToRepeatedWrapperField(message, 3, Point.deserialize(reader), Point)); + break; + case 4: + reader.readMessage(message.paRef, () => message.paRef = RelatedRef.deserialize(reader)); + break; + case 5: + reader.readMessage(message.pbRef, () => message.pbRef = RelatedRef.deserialize(reader)); + break; + case 6: + message.sectionType = reader.readEnum(); + break; + case 7: + pb_1.Message.addToRepeatedField(message, 7, reader.readString()); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Section { + return Section.deserialize(bytes); + } + } + export namespace Section { + export enum SectionType { + Physical = 0, + Logic = 1, + TurnoutPhysical = 2 + } + } + export class KilometerPoint extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + point?: Point; + kilometer?: number; + stName?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("point" in data && data.point != undefined) { + this.point = data.point; + } + if ("kilometer" in data && data.kilometer != undefined) { + this.kilometer = data.kilometer; + } + if ("stName" in data && data.stName != undefined) { + this.stName = data.stName; + } + } + } + get point() { + return pb_1.Message.getWrapperField(this, Point, 1) as Point; + } + set point(value: Point) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_point() { + return pb_1.Message.getField(this, 1) != null; + } + get kilometer() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set kilometer(value: number) { + pb_1.Message.setField(this, 2, value); + } + get stName() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set stName(value: string) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + point?: ReturnType; + kilometer?: number; + stName?: string; + }): KilometerPoint { + const message = new KilometerPoint({}); + if (data.point != null) { + message.point = Point.fromObject(data.point); + } + if (data.kilometer != null) { + message.kilometer = data.kilometer; + } + if (data.stName != null) { + message.stName = data.stName; + } + return message; + } + toObject() { + const data: { + point?: ReturnType; + kilometer?: number; + stName?: string; + } = {}; + if (this.point != null) { + data.point = this.point.toObject(); + } + if (this.kilometer != null) { + data.kilometer = this.kilometer; + } + if (this.stName != null) { + data.stName = this.stName; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_point) + writer.writeMessage(1, this.point, () => this.point.serialize(writer)); + if (this.kilometer != 0) + writer.writeInt64(2, this.kilometer); + if (this.stName.length) + writer.writeString(3, this.stName); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): KilometerPoint { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new KilometerPoint(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.point, () => message.point = Point.deserialize(reader)); + break; + case 2: + message.kilometer = reader.readInt64(); + break; + case 3: + message.stName = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): KilometerPoint { + return KilometerPoint.deserialize(bytes); + } + } + export class PathLine extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + points?: Point[]; + isUp?: boolean; + kilometerPoints?: KilometerPoint[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [3, 5], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("points" in data && data.points != undefined) { + this.points = data.points; + } + if ("isUp" in data && data.isUp != undefined) { + this.isUp = data.isUp; + } + if ("kilometerPoints" in data && data.kilometerPoints != undefined) { + this.kilometerPoints = data.kilometerPoints; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get points() { + return pb_1.Message.getRepeatedWrapperField(this, Point, 3) as Point[]; + } + set points(value: Point[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); + } + get isUp() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set isUp(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get kilometerPoints() { + return pb_1.Message.getRepeatedWrapperField(this, KilometerPoint, 5) as KilometerPoint[]; + } + set kilometerPoints(value: KilometerPoint[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + points?: ReturnType[]; + isUp?: boolean; + kilometerPoints?: ReturnType[]; + }): PathLine { + const message = new PathLine({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.points != null) { + message.points = data.points.map(item => Point.fromObject(item)); + } + if (data.isUp != null) { + message.isUp = data.isUp; + } + if (data.kilometerPoints != null) { + message.kilometerPoints = data.kilometerPoints.map(item => KilometerPoint.fromObject(item)); + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + points?: ReturnType[]; + isUp?: boolean; + kilometerPoints?: ReturnType[]; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.points != null) { + data.points = this.points.map((item: Point) => item.toObject()); + } + if (this.isUp != null) { + data.isUp = this.isUp; + } + if (this.kilometerPoints != null) { + data.kilometerPoints = this.kilometerPoints.map((item: KilometerPoint) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.points.length) + writer.writeRepeatedMessage(3, this.points, (item: Point) => item.serialize(writer)); + if (this.isUp != false) + writer.writeBool(4, this.isUp); + if (this.kilometerPoints.length) + writer.writeRepeatedMessage(5, this.kilometerPoints, (item: KilometerPoint) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): PathLine { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new PathLine(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + reader.readMessage(message.points, () => pb_1.Message.addToRepeatedWrapperField(message, 3, Point.deserialize(reader), Point)); + break; + case 4: + message.isUp = reader.readBool(); + break; + case 5: + reader.readMessage(message.kilometerPoints, () => pb_1.Message.addToRepeatedWrapperField(message, 5, KilometerPoint.deserialize(reader), KilometerPoint)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): PathLine { + return PathLine.deserialize(bytes); + } + } + export class RelatedRef extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + deviceType?: RelatedRef.DeviceType; + id?: string; + devicePort?: RelatedRef.DevicePort; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("deviceType" in data && data.deviceType != undefined) { + this.deviceType = data.deviceType; + } + if ("id" in data && data.id != undefined) { + this.id = data.id; + } + if ("devicePort" in data && data.devicePort != undefined) { + this.devicePort = data.devicePort; + } + } + } + get deviceType() { + return pb_1.Message.getFieldWithDefault(this, 1, RelatedRef.DeviceType.Section) as RelatedRef.DeviceType; + } + set deviceType(value: RelatedRef.DeviceType) { + pb_1.Message.setField(this, 1, value); + } + get id() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set id(value: string) { + pb_1.Message.setField(this, 2, value); + } + get devicePort() { + return pb_1.Message.getFieldWithDefault(this, 3, RelatedRef.DevicePort.A) as RelatedRef.DevicePort; + } + set devicePort(value: RelatedRef.DevicePort) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + deviceType?: RelatedRef.DeviceType; + id?: string; + devicePort?: RelatedRef.DevicePort; + }): RelatedRef { + const message = new RelatedRef({}); + if (data.deviceType != null) { + message.deviceType = data.deviceType; + } + if (data.id != null) { + message.id = data.id; + } + if (data.devicePort != null) { + message.devicePort = data.devicePort; + } + return message; + } + toObject() { + const data: { + deviceType?: RelatedRef.DeviceType; + id?: string; + devicePort?: RelatedRef.DevicePort; + } = {}; + if (this.deviceType != null) { + data.deviceType = this.deviceType; + } + if (this.id != null) { + data.id = this.id; + } + if (this.devicePort != null) { + data.devicePort = this.devicePort; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.deviceType != RelatedRef.DeviceType.Section) + writer.writeEnum(1, this.deviceType); + if (this.id.length) + writer.writeString(2, this.id); + if (this.devicePort != RelatedRef.DevicePort.A) + writer.writeEnum(3, this.devicePort); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): RelatedRef { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new RelatedRef(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.deviceType = reader.readEnum(); + break; + case 2: + message.id = reader.readString(); + break; + case 3: + message.devicePort = reader.readEnum(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): RelatedRef { + return RelatedRef.deserialize(bytes); + } + } + export namespace RelatedRef { + export enum DeviceType { + Section = 0, + Turnout = 1, + TrainWindow = 2, + AxleCounting = 3 + } + export enum DevicePort { + A = 0, + B = 1, + C = 2 + } + } + export class Separator extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + common?: CommonInfo; + code?: string; + separatorType?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("common" in data && data.common != undefined) { + this.common = data.common; + } + if ("code" in data && data.code != undefined) { + this.code = data.code; + } + if ("separatorType" in data && data.separatorType != undefined) { + this.separatorType = data.separatorType; + } + } + } + get common() { + return pb_1.Message.getWrapperField(this, CommonInfo, 1) as CommonInfo; + } + set common(value: CommonInfo) { + pb_1.Message.setWrapperField(this, 1, value); + } + get has_common() { + return pb_1.Message.getField(this, 1) != null; + } + get code() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set code(value: string) { + pb_1.Message.setField(this, 2, value); + } + get separatorType() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set separatorType(value: string) { + pb_1.Message.setField(this, 3, value); + } + static fromObject(data: { + common?: ReturnType; + code?: string; + separatorType?: string; + }): Separator { + const message = new Separator({}); + if (data.common != null) { + message.common = CommonInfo.fromObject(data.common); + } + if (data.code != null) { + message.code = data.code; + } + if (data.separatorType != null) { + message.separatorType = data.separatorType; + } + return message; + } + toObject() { + const data: { + common?: ReturnType; + code?: string; + separatorType?: string; + } = {}; + if (this.common != null) { + data.common = this.common.toObject(); + } + if (this.code != null) { + data.code = this.code; + } + if (this.separatorType != null) { + data.separatorType = this.separatorType; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.has_common) + writer.writeMessage(1, this.common, () => this.common.serialize(writer)); + if (this.code.length) + writer.writeString(2, this.code); + if (this.separatorType.length) + writer.writeString(3, this.separatorType); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): Separator { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new Separator(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.common, () => message.common = CommonInfo.deserialize(reader)); + break; + case 2: + message.code = reader.readString(); + break; + case 3: + message.separatorType = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): Separator { + return Separator.deserialize(bytes); + } + } +} diff --git a/src/protos/train.ts b/src/protos/train.ts new file mode 100644 index 0000000..7d30ec9 --- /dev/null +++ b/src/protos/train.ts @@ -0,0 +1,1512 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: train.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as dependency_1 from "./device_status"; +import * as pb_1 from "google-protobuf"; +export namespace train { + export class TrainInfo extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + rtuId?: number; + window?: NccWindow; + devType?: dependency_1.state.DeviceType; + devName?: string; + trainIndex?: string; + groupId?: string; + trainId?: string; + globalId?: string; + destinationId?: number; + rollingStock?: number; + driverId?: string; + otpTime?: number; + mode?: dependency_1.state.TrainMode; + arriveTime?: number; + departTime?: number; + speed?: number; + type?: boolean; + routeId?: number; + rate?: number; + remove?: TrainRemove; + block?: TrainBlock; + record?: TrainRecord; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("rtuId" in data && data.rtuId != undefined) { + this.rtuId = data.rtuId; + } + if ("window" in data && data.window != undefined) { + this.window = data.window; + } + if ("devType" in data && data.devType != undefined) { + this.devType = data.devType; + } + if ("devName" in data && data.devName != undefined) { + this.devName = data.devName; + } + if ("trainIndex" in data && data.trainIndex != undefined) { + this.trainIndex = data.trainIndex; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + if ("trainId" in data && data.trainId != undefined) { + this.trainId = data.trainId; + } + if ("globalId" in data && data.globalId != undefined) { + this.globalId = data.globalId; + } + if ("destinationId" in data && data.destinationId != undefined) { + this.destinationId = data.destinationId; + } + if ("rollingStock" in data && data.rollingStock != undefined) { + this.rollingStock = data.rollingStock; + } + if ("driverId" in data && data.driverId != undefined) { + this.driverId = data.driverId; + } + if ("otpTime" in data && data.otpTime != undefined) { + this.otpTime = data.otpTime; + } + if ("mode" in data && data.mode != undefined) { + this.mode = data.mode; + } + if ("arriveTime" in data && data.arriveTime != undefined) { + this.arriveTime = data.arriveTime; + } + if ("departTime" in data && data.departTime != undefined) { + this.departTime = data.departTime; + } + if ("speed" in data && data.speed != undefined) { + this.speed = data.speed; + } + if ("type" in data && data.type != undefined) { + this.type = data.type; + } + if ("routeId" in data && data.routeId != undefined) { + this.routeId = data.routeId; + } + if ("rate" in data && data.rate != undefined) { + this.rate = data.rate; + } + if ("remove" in data && data.remove != undefined) { + this.remove = data.remove; + } + if ("block" in data && data.block != undefined) { + this.block = data.block; + } + if ("record" in data && data.record != undefined) { + this.record = data.record; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get rtuId() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set rtuId(value: number) { + pb_1.Message.setField(this, 2, value); + } + get window() { + return pb_1.Message.getWrapperField(this, NccWindow, 3) as NccWindow; + } + set window(value: NccWindow) { + pb_1.Message.setWrapperField(this, 3, value); + } + get has_window() { + return pb_1.Message.getField(this, 3) != null; + } + get devType() { + return pb_1.Message.getFieldWithDefault(this, 4, dependency_1.state.DeviceType.UNKNOW) as dependency_1.state.DeviceType; + } + set devType(value: dependency_1.state.DeviceType) { + pb_1.Message.setField(this, 4, value); + } + get devName() { + return pb_1.Message.getFieldWithDefault(this, 5, "") as string; + } + set devName(value: string) { + pb_1.Message.setField(this, 5, value); + } + get trainIndex() { + return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + } + set trainIndex(value: string) { + pb_1.Message.setField(this, 6, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 7, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 7, value); + } + get trainId() { + return pb_1.Message.getFieldWithDefault(this, 8, "") as string; + } + set trainId(value: string) { + pb_1.Message.setField(this, 8, value); + } + get globalId() { + return pb_1.Message.getFieldWithDefault(this, 9, "") as string; + } + set globalId(value: string) { + pb_1.Message.setField(this, 9, value); + } + get destinationId() { + return pb_1.Message.getFieldWithDefault(this, 10, 0) as number; + } + set destinationId(value: number) { + pb_1.Message.setField(this, 10, value); + } + get rollingStock() { + return pb_1.Message.getFieldWithDefault(this, 11, 0) as number; + } + set rollingStock(value: number) { + pb_1.Message.setField(this, 11, value); + } + get driverId() { + return pb_1.Message.getFieldWithDefault(this, 12, "") as string; + } + set driverId(value: string) { + pb_1.Message.setField(this, 12, value); + } + get otpTime() { + return pb_1.Message.getFieldWithDefault(this, 13, 0) as number; + } + set otpTime(value: number) { + pb_1.Message.setField(this, 13, value); + } + get mode() { + return pb_1.Message.getWrapperField(this, dependency_1.state.TrainMode, 14) as dependency_1.state.TrainMode; + } + set mode(value: dependency_1.state.TrainMode) { + pb_1.Message.setWrapperField(this, 14, value); + } + get has_mode() { + return pb_1.Message.getField(this, 14) != null; + } + get arriveTime() { + return pb_1.Message.getFieldWithDefault(this, 15, 0) as number; + } + set arriveTime(value: number) { + pb_1.Message.setField(this, 15, value); + } + get departTime() { + return pb_1.Message.getFieldWithDefault(this, 16, 0) as number; + } + set departTime(value: number) { + pb_1.Message.setField(this, 16, value); + } + get speed() { + return pb_1.Message.getFieldWithDefault(this, 17, 0) as number; + } + set speed(value: number) { + pb_1.Message.setField(this, 17, value); + } + get type() { + return pb_1.Message.getFieldWithDefault(this, 18, false) as boolean; + } + set type(value: boolean) { + pb_1.Message.setField(this, 18, value); + } + get routeId() { + return pb_1.Message.getFieldWithDefault(this, 19, 0) as number; + } + set routeId(value: number) { + pb_1.Message.setField(this, 19, value); + } + get rate() { + return pb_1.Message.getFieldWithDefault(this, 20, 0) as number; + } + set rate(value: number) { + pb_1.Message.setField(this, 20, value); + } + get remove() { + return pb_1.Message.getWrapperField(this, TrainRemove, 21) as TrainRemove; + } + set remove(value: TrainRemove) { + pb_1.Message.setWrapperField(this, 21, value); + } + get has_remove() { + return pb_1.Message.getField(this, 21) != null; + } + get block() { + return pb_1.Message.getWrapperField(this, TrainBlock, 22) as TrainBlock; + } + set block(value: TrainBlock) { + pb_1.Message.setWrapperField(this, 22, value); + } + get has_block() { + return pb_1.Message.getField(this, 22) != null; + } + get record() { + return pb_1.Message.getWrapperField(this, TrainRecord, 23) as TrainRecord; + } + set record(value: TrainRecord) { + pb_1.Message.setWrapperField(this, 23, value); + } + get has_record() { + return pb_1.Message.getField(this, 23) != null; + } + static fromObject(data: { + lineId?: number; + rtuId?: number; + window?: ReturnType; + devType?: dependency_1.state.DeviceType; + devName?: string; + trainIndex?: string; + groupId?: string; + trainId?: string; + globalId?: string; + destinationId?: number; + rollingStock?: number; + driverId?: string; + otpTime?: number; + mode?: ReturnType; + arriveTime?: number; + departTime?: number; + speed?: number; + type?: boolean; + routeId?: number; + rate?: number; + remove?: ReturnType; + block?: ReturnType; + record?: ReturnType; + }): TrainInfo { + const message = new TrainInfo({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.rtuId != null) { + message.rtuId = data.rtuId; + } + if (data.window != null) { + message.window = NccWindow.fromObject(data.window); + } + if (data.devType != null) { + message.devType = data.devType; + } + if (data.devName != null) { + message.devName = data.devName; + } + if (data.trainIndex != null) { + message.trainIndex = data.trainIndex; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + if (data.trainId != null) { + message.trainId = data.trainId; + } + if (data.globalId != null) { + message.globalId = data.globalId; + } + if (data.destinationId != null) { + message.destinationId = data.destinationId; + } + if (data.rollingStock != null) { + message.rollingStock = data.rollingStock; + } + if (data.driverId != null) { + message.driverId = data.driverId; + } + if (data.otpTime != null) { + message.otpTime = data.otpTime; + } + if (data.mode != null) { + message.mode = dependency_1.state.TrainMode.fromObject(data.mode); + } + if (data.arriveTime != null) { + message.arriveTime = data.arriveTime; + } + if (data.departTime != null) { + message.departTime = data.departTime; + } + if (data.speed != null) { + message.speed = data.speed; + } + if (data.type != null) { + message.type = data.type; + } + if (data.routeId != null) { + message.routeId = data.routeId; + } + if (data.rate != null) { + message.rate = data.rate; + } + if (data.remove != null) { + message.remove = TrainRemove.fromObject(data.remove); + } + if (data.block != null) { + message.block = TrainBlock.fromObject(data.block); + } + if (data.record != null) { + message.record = TrainRecord.fromObject(data.record); + } + return message; + } + toObject() { + const data: { + lineId?: number; + rtuId?: number; + window?: ReturnType; + devType?: dependency_1.state.DeviceType; + devName?: string; + trainIndex?: string; + groupId?: string; + trainId?: string; + globalId?: string; + destinationId?: number; + rollingStock?: number; + driverId?: string; + otpTime?: number; + mode?: ReturnType; + arriveTime?: number; + departTime?: number; + speed?: number; + type?: boolean; + routeId?: number; + rate?: number; + remove?: ReturnType; + block?: ReturnType; + record?: ReturnType; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.rtuId != null) { + data.rtuId = this.rtuId; + } + if (this.window != null) { + data.window = this.window.toObject(); + } + if (this.devType != null) { + data.devType = this.devType; + } + if (this.devName != null) { + data.devName = this.devName; + } + if (this.trainIndex != null) { + data.trainIndex = this.trainIndex; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + if (this.trainId != null) { + data.trainId = this.trainId; + } + if (this.globalId != null) { + data.globalId = this.globalId; + } + if (this.destinationId != null) { + data.destinationId = this.destinationId; + } + if (this.rollingStock != null) { + data.rollingStock = this.rollingStock; + } + if (this.driverId != null) { + data.driverId = this.driverId; + } + if (this.otpTime != null) { + data.otpTime = this.otpTime; + } + if (this.mode != null) { + data.mode = this.mode.toObject(); + } + if (this.arriveTime != null) { + data.arriveTime = this.arriveTime; + } + if (this.departTime != null) { + data.departTime = this.departTime; + } + if (this.speed != null) { + data.speed = this.speed; + } + if (this.type != null) { + data.type = this.type; + } + if (this.routeId != null) { + data.routeId = this.routeId; + } + if (this.rate != null) { + data.rate = this.rate; + } + if (this.remove != null) { + data.remove = this.remove.toObject(); + } + if (this.block != null) { + data.block = this.block.toObject(); + } + if (this.record != null) { + data.record = this.record.toObject(); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.rtuId != 0) + writer.writeInt32(2, this.rtuId); + if (this.has_window) + writer.writeMessage(3, this.window, () => this.window.serialize(writer)); + if (this.devType != dependency_1.state.DeviceType.UNKNOW) + writer.writeEnum(4, this.devType); + if (this.devName.length) + writer.writeString(5, this.devName); + if (this.trainIndex.length) + writer.writeString(6, this.trainIndex); + if (this.groupId.length) + writer.writeString(7, this.groupId); + if (this.trainId.length) + writer.writeString(8, this.trainId); + if (this.globalId.length) + writer.writeString(9, this.globalId); + if (this.destinationId != 0) + writer.writeInt32(10, this.destinationId); + if (this.rollingStock != 0) + writer.writeInt32(11, this.rollingStock); + if (this.driverId.length) + writer.writeString(12, this.driverId); + if (this.otpTime != 0) + writer.writeInt32(13, this.otpTime); + if (this.has_mode) + writer.writeMessage(14, this.mode, () => this.mode.serialize(writer)); + if (this.arriveTime != 0) + writer.writeInt64(15, this.arriveTime); + if (this.departTime != 0) + writer.writeInt64(16, this.departTime); + if (this.speed != 0) + writer.writeFloat(17, this.speed); + if (this.type != false) + writer.writeBool(18, this.type); + if (this.routeId != 0) + writer.writeInt32(19, this.routeId); + if (this.rate != 0) + writer.writeInt32(20, this.rate); + if (this.has_remove) + writer.writeMessage(21, this.remove, () => this.remove.serialize(writer)); + if (this.has_block) + writer.writeMessage(22, this.block, () => this.block.serialize(writer)); + if (this.has_record) + writer.writeMessage(23, this.record, () => this.record.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainInfo { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainInfo(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.rtuId = reader.readInt32(); + break; + case 3: + reader.readMessage(message.window, () => message.window = NccWindow.deserialize(reader)); + break; + case 4: + message.devType = reader.readEnum(); + break; + case 5: + message.devName = reader.readString(); + break; + case 6: + message.trainIndex = reader.readString(); + break; + case 7: + message.groupId = reader.readString(); + break; + case 8: + message.trainId = reader.readString(); + break; + case 9: + message.globalId = reader.readString(); + break; + case 10: + message.destinationId = reader.readInt32(); + break; + case 11: + message.rollingStock = reader.readInt32(); + break; + case 12: + message.driverId = reader.readString(); + break; + case 13: + message.otpTime = reader.readInt32(); + break; + case 14: + reader.readMessage(message.mode, () => message.mode = dependency_1.state.TrainMode.deserialize(reader)); + break; + case 15: + message.arriveTime = reader.readInt64(); + break; + case 16: + message.departTime = reader.readInt64(); + break; + case 17: + message.speed = reader.readFloat(); + break; + case 18: + message.type = reader.readBool(); + break; + case 19: + message.routeId = reader.readInt32(); + break; + case 20: + message.rate = reader.readInt32(); + break; + case 21: + reader.readMessage(message.remove, () => message.remove = TrainRemove.deserialize(reader)); + break; + case 22: + reader.readMessage(message.block, () => message.block = TrainBlock.deserialize(reader)); + break; + case 23: + reader.readMessage(message.record, () => message.record = TrainRecord.deserialize(reader)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainInfo { + return TrainInfo.deserialize(bytes); + } + } + export class NccWindow extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + nccWindow?: number; + nccWinOffset?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("nccWindow" in data && data.nccWindow != undefined) { + this.nccWindow = data.nccWindow; + } + if ("nccWinOffset" in data && data.nccWinOffset != undefined) { + this.nccWinOffset = data.nccWinOffset; + } + } + } + get nccWindow() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set nccWindow(value: number) { + pb_1.Message.setField(this, 1, value); + } + get nccWinOffset() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set nccWinOffset(value: number) { + pb_1.Message.setField(this, 2, value); + } + static fromObject(data: { + nccWindow?: number; + nccWinOffset?: number; + }): NccWindow { + const message = new NccWindow({}); + if (data.nccWindow != null) { + message.nccWindow = data.nccWindow; + } + if (data.nccWinOffset != null) { + message.nccWinOffset = data.nccWinOffset; + } + return message; + } + toObject() { + const data: { + nccWindow?: number; + nccWinOffset?: number; + } = {}; + if (this.nccWindow != null) { + data.nccWindow = this.nccWindow; + } + if (this.nccWinOffset != null) { + data.nccWinOffset = this.nccWinOffset; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.nccWindow != 0) + writer.writeInt32(1, this.nccWindow); + if (this.nccWinOffset != 0) + writer.writeInt32(2, this.nccWinOffset); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): NccWindow { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new NccWindow(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.nccWindow = reader.readInt32(); + break; + case 2: + message.nccWinOffset = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): NccWindow { + return NccWindow.deserialize(bytes); + } + } + export class TrainRemove extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + rtuId?: number; + window?: NccWindow; + deviceType?: dependency_1.state.DeviceType; + devName?: string; + trainIndex?: string; + groupId?: string; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("rtuId" in data && data.rtuId != undefined) { + this.rtuId = data.rtuId; + } + if ("window" in data && data.window != undefined) { + this.window = data.window; + } + if ("deviceType" in data && data.deviceType != undefined) { + this.deviceType = data.deviceType; + } + if ("devName" in data && data.devName != undefined) { + this.devName = data.devName; + } + if ("trainIndex" in data && data.trainIndex != undefined) { + this.trainIndex = data.trainIndex; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get rtuId() { + return pb_1.Message.getFieldWithDefault(this, 2, 0) as number; + } + set rtuId(value: number) { + pb_1.Message.setField(this, 2, value); + } + get window() { + return pb_1.Message.getWrapperField(this, NccWindow, 3) as NccWindow; + } + set window(value: NccWindow) { + pb_1.Message.setWrapperField(this, 3, value); + } + get has_window() { + return pb_1.Message.getField(this, 3) != null; + } + get deviceType() { + return pb_1.Message.getFieldWithDefault(this, 4, dependency_1.state.DeviceType.UNKNOW) as dependency_1.state.DeviceType; + } + set deviceType(value: dependency_1.state.DeviceType) { + pb_1.Message.setField(this, 4, value); + } + get devName() { + return pb_1.Message.getFieldWithDefault(this, 5, "") as string; + } + set devName(value: string) { + pb_1.Message.setField(this, 5, value); + } + get trainIndex() { + return pb_1.Message.getFieldWithDefault(this, 6, "") as string; + } + set trainIndex(value: string) { + pb_1.Message.setField(this, 6, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 7, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 7, value); + } + static fromObject(data: { + lineId?: number; + rtuId?: number; + window?: ReturnType; + deviceType?: dependency_1.state.DeviceType; + devName?: string; + trainIndex?: string; + groupId?: string; + }): TrainRemove { + const message = new TrainRemove({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.rtuId != null) { + message.rtuId = data.rtuId; + } + if (data.window != null) { + message.window = NccWindow.fromObject(data.window); + } + if (data.deviceType != null) { + message.deviceType = data.deviceType; + } + if (data.devName != null) { + message.devName = data.devName; + } + if (data.trainIndex != null) { + message.trainIndex = data.trainIndex; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + return message; + } + toObject() { + const data: { + lineId?: number; + rtuId?: number; + window?: ReturnType; + deviceType?: dependency_1.state.DeviceType; + devName?: string; + trainIndex?: string; + groupId?: string; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.rtuId != null) { + data.rtuId = this.rtuId; + } + if (this.window != null) { + data.window = this.window.toObject(); + } + if (this.deviceType != null) { + data.deviceType = this.deviceType; + } + if (this.devName != null) { + data.devName = this.devName; + } + if (this.trainIndex != null) { + data.trainIndex = this.trainIndex; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.rtuId != 0) + writer.writeInt32(2, this.rtuId); + if (this.has_window) + writer.writeMessage(3, this.window, () => this.window.serialize(writer)); + if (this.deviceType != dependency_1.state.DeviceType.UNKNOW) + writer.writeEnum(4, this.deviceType); + if (this.devName.length) + writer.writeString(5, this.devName); + if (this.trainIndex.length) + writer.writeString(6, this.trainIndex); + if (this.groupId.length) + writer.writeString(7, this.groupId); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainRemove { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainRemove(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.rtuId = reader.readInt32(); + break; + case 3: + reader.readMessage(message.window, () => message.window = NccWindow.deserialize(reader)); + break; + case 4: + message.deviceType = reader.readEnum(); + break; + case 5: + message.devName = reader.readString(); + break; + case 6: + message.trainIndex = reader.readString(); + break; + case 7: + message.groupId = reader.readString(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainRemove { + return TrainRemove.deserialize(bytes); + } + } + export class TrainBlock extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + groupId?: string; + trainId?: string; + direction?: number; + stationIDInUpSide?: number; + stationIDInDownSide?: number; + rtuId?: number; + deviceType?: dependency_1.state.DeviceType; + DevName?: string; + blockFlag?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + if ("trainId" in data && data.trainId != undefined) { + this.trainId = data.trainId; + } + if ("direction" in data && data.direction != undefined) { + this.direction = data.direction; + } + if ("stationIDInUpSide" in data && data.stationIDInUpSide != undefined) { + this.stationIDInUpSide = data.stationIDInUpSide; + } + if ("stationIDInDownSide" in data && data.stationIDInDownSide != undefined) { + this.stationIDInDownSide = data.stationIDInDownSide; + } + if ("rtuId" in data && data.rtuId != undefined) { + this.rtuId = data.rtuId; + } + if ("deviceType" in data && data.deviceType != undefined) { + this.deviceType = data.deviceType; + } + if ("DevName" in data && data.DevName != undefined) { + this.DevName = data.DevName; + } + if ("blockFlag" in data && data.blockFlag != undefined) { + this.blockFlag = data.blockFlag; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 2, value); + } + get trainId() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set trainId(value: string) { + pb_1.Message.setField(this, 3, value); + } + get direction() { + return pb_1.Message.getFieldWithDefault(this, 4, 0) as number; + } + set direction(value: number) { + pb_1.Message.setField(this, 4, value); + } + get stationIDInUpSide() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set stationIDInUpSide(value: number) { + pb_1.Message.setField(this, 5, value); + } + get stationIDInDownSide() { + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; + } + set stationIDInDownSide(value: number) { + pb_1.Message.setField(this, 6, value); + } + get rtuId() { + return pb_1.Message.getFieldWithDefault(this, 7, 0) as number; + } + set rtuId(value: number) { + pb_1.Message.setField(this, 7, value); + } + get deviceType() { + return pb_1.Message.getFieldWithDefault(this, 8, dependency_1.state.DeviceType.UNKNOW) as dependency_1.state.DeviceType; + } + set deviceType(value: dependency_1.state.DeviceType) { + pb_1.Message.setField(this, 8, value); + } + get DevName() { + return pb_1.Message.getFieldWithDefault(this, 9, "") as string; + } + set DevName(value: string) { + pb_1.Message.setField(this, 9, value); + } + get blockFlag() { + return pb_1.Message.getFieldWithDefault(this, 10, 0) as number; + } + set blockFlag(value: number) { + pb_1.Message.setField(this, 10, value); + } + static fromObject(data: { + lineId?: number; + groupId?: string; + trainId?: string; + direction?: number; + stationIDInUpSide?: number; + stationIDInDownSide?: number; + rtuId?: number; + deviceType?: dependency_1.state.DeviceType; + DevName?: string; + blockFlag?: number; + }): TrainBlock { + const message = new TrainBlock({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + if (data.trainId != null) { + message.trainId = data.trainId; + } + if (data.direction != null) { + message.direction = data.direction; + } + if (data.stationIDInUpSide != null) { + message.stationIDInUpSide = data.stationIDInUpSide; + } + if (data.stationIDInDownSide != null) { + message.stationIDInDownSide = data.stationIDInDownSide; + } + if (data.rtuId != null) { + message.rtuId = data.rtuId; + } + if (data.deviceType != null) { + message.deviceType = data.deviceType; + } + if (data.DevName != null) { + message.DevName = data.DevName; + } + if (data.blockFlag != null) { + message.blockFlag = data.blockFlag; + } + return message; + } + toObject() { + const data: { + lineId?: number; + groupId?: string; + trainId?: string; + direction?: number; + stationIDInUpSide?: number; + stationIDInDownSide?: number; + rtuId?: number; + deviceType?: dependency_1.state.DeviceType; + DevName?: string; + blockFlag?: number; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + if (this.trainId != null) { + data.trainId = this.trainId; + } + if (this.direction != null) { + data.direction = this.direction; + } + if (this.stationIDInUpSide != null) { + data.stationIDInUpSide = this.stationIDInUpSide; + } + if (this.stationIDInDownSide != null) { + data.stationIDInDownSide = this.stationIDInDownSide; + } + if (this.rtuId != null) { + data.rtuId = this.rtuId; + } + if (this.deviceType != null) { + data.deviceType = this.deviceType; + } + if (this.DevName != null) { + data.DevName = this.DevName; + } + if (this.blockFlag != null) { + data.blockFlag = this.blockFlag; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.groupId.length) + writer.writeString(2, this.groupId); + if (this.trainId.length) + writer.writeString(3, this.trainId); + if (this.direction != 0) + writer.writeInt32(4, this.direction); + if (this.stationIDInUpSide != 0) + writer.writeInt32(5, this.stationIDInUpSide); + if (this.stationIDInDownSide != 0) + writer.writeInt32(6, this.stationIDInDownSide); + if (this.rtuId != 0) + writer.writeInt32(7, this.rtuId); + if (this.deviceType != dependency_1.state.DeviceType.UNKNOW) + writer.writeEnum(8, this.deviceType); + if (this.DevName.length) + writer.writeString(9, this.DevName); + if (this.blockFlag != 0) + writer.writeInt32(10, this.blockFlag); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainBlock { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainBlock(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.groupId = reader.readString(); + break; + case 3: + message.trainId = reader.readString(); + break; + case 4: + message.direction = reader.readInt32(); + break; + case 5: + message.stationIDInUpSide = reader.readInt32(); + break; + case 6: + message.stationIDInDownSide = reader.readInt32(); + break; + case 7: + message.rtuId = reader.readInt32(); + break; + case 8: + message.deviceType = reader.readEnum(); + break; + case 9: + message.DevName = reader.readString(); + break; + case 10: + message.blockFlag = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainBlock { + return TrainBlock.deserialize(bytes); + } + } + export class TrainRecord extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + trainId?: string; + globalId?: string; + localSubId?: number; + groupId?: string; + destinationId?: number; + trainType?: number; + dir?: number; + stationId?: number; + sideId?: number; + trackName?: string; + recordType?: boolean; + recordTime?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("trainId" in data && data.trainId != undefined) { + this.trainId = data.trainId; + } + if ("globalId" in data && data.globalId != undefined) { + this.globalId = data.globalId; + } + if ("localSubId" in data && data.localSubId != undefined) { + this.localSubId = data.localSubId; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + if ("destinationId" in data && data.destinationId != undefined) { + this.destinationId = data.destinationId; + } + if ("trainType" in data && data.trainType != undefined) { + this.trainType = data.trainType; + } + if ("dir" in data && data.dir != undefined) { + this.dir = data.dir; + } + if ("stationId" in data && data.stationId != undefined) { + this.stationId = data.stationId; + } + if ("sideId" in data && data.sideId != undefined) { + this.sideId = data.sideId; + } + if ("trackName" in data && data.trackName != undefined) { + this.trackName = data.trackName; + } + if ("recordType" in data && data.recordType != undefined) { + this.recordType = data.recordType; + } + if ("recordTime" in data && data.recordTime != undefined) { + this.recordTime = data.recordTime; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get trainId() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set trainId(value: string) { + pb_1.Message.setField(this, 2, value); + } + get globalId() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set globalId(value: string) { + pb_1.Message.setField(this, 3, value); + } + get localSubId() { + return pb_1.Message.getFieldWithDefault(this, 4, 0) as number; + } + set localSubId(value: number) { + pb_1.Message.setField(this, 4, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 5, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 5, value); + } + get destinationId() { + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; + } + set destinationId(value: number) { + pb_1.Message.setField(this, 6, value); + } + get trainType() { + return pb_1.Message.getFieldWithDefault(this, 7, 0) as number; + } + set trainType(value: number) { + pb_1.Message.setField(this, 7, value); + } + get dir() { + return pb_1.Message.getFieldWithDefault(this, 8, 0) as number; + } + set dir(value: number) { + pb_1.Message.setField(this, 8, value); + } + get stationId() { + return pb_1.Message.getFieldWithDefault(this, 9, 0) as number; + } + set stationId(value: number) { + pb_1.Message.setField(this, 9, value); + } + get sideId() { + return pb_1.Message.getFieldWithDefault(this, 10, 0) as number; + } + set sideId(value: number) { + pb_1.Message.setField(this, 10, value); + } + get trackName() { + return pb_1.Message.getFieldWithDefault(this, 11, "") as string; + } + set trackName(value: string) { + pb_1.Message.setField(this, 11, value); + } + get recordType() { + return pb_1.Message.getFieldWithDefault(this, 12, false) as boolean; + } + set recordType(value: boolean) { + pb_1.Message.setField(this, 12, value); + } + get recordTime() { + return pb_1.Message.getFieldWithDefault(this, 13, 0) as number; + } + set recordTime(value: number) { + pb_1.Message.setField(this, 13, value); + } + static fromObject(data: { + lineId?: number; + trainId?: string; + globalId?: string; + localSubId?: number; + groupId?: string; + destinationId?: number; + trainType?: number; + dir?: number; + stationId?: number; + sideId?: number; + trackName?: string; + recordType?: boolean; + recordTime?: number; + }): TrainRecord { + const message = new TrainRecord({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.trainId != null) { + message.trainId = data.trainId; + } + if (data.globalId != null) { + message.globalId = data.globalId; + } + if (data.localSubId != null) { + message.localSubId = data.localSubId; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + if (data.destinationId != null) { + message.destinationId = data.destinationId; + } + if (data.trainType != null) { + message.trainType = data.trainType; + } + if (data.dir != null) { + message.dir = data.dir; + } + if (data.stationId != null) { + message.stationId = data.stationId; + } + if (data.sideId != null) { + message.sideId = data.sideId; + } + if (data.trackName != null) { + message.trackName = data.trackName; + } + if (data.recordType != null) { + message.recordType = data.recordType; + } + if (data.recordTime != null) { + message.recordTime = data.recordTime; + } + return message; + } + toObject() { + const data: { + lineId?: number; + trainId?: string; + globalId?: string; + localSubId?: number; + groupId?: string; + destinationId?: number; + trainType?: number; + dir?: number; + stationId?: number; + sideId?: number; + trackName?: string; + recordType?: boolean; + recordTime?: number; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.trainId != null) { + data.trainId = this.trainId; + } + if (this.globalId != null) { + data.globalId = this.globalId; + } + if (this.localSubId != null) { + data.localSubId = this.localSubId; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + if (this.destinationId != null) { + data.destinationId = this.destinationId; + } + if (this.trainType != null) { + data.trainType = this.trainType; + } + if (this.dir != null) { + data.dir = this.dir; + } + if (this.stationId != null) { + data.stationId = this.stationId; + } + if (this.sideId != null) { + data.sideId = this.sideId; + } + if (this.trackName != null) { + data.trackName = this.trackName; + } + if (this.recordType != null) { + data.recordType = this.recordType; + } + if (this.recordTime != null) { + data.recordTime = this.recordTime; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.trainId.length) + writer.writeString(2, this.trainId); + if (this.globalId.length) + writer.writeString(3, this.globalId); + if (this.localSubId != 0) + writer.writeInt32(4, this.localSubId); + if (this.groupId.length) + writer.writeString(5, this.groupId); + if (this.destinationId != 0) + writer.writeInt32(6, this.destinationId); + if (this.trainType != 0) + writer.writeInt32(7, this.trainType); + if (this.dir != 0) + writer.writeInt32(8, this.dir); + if (this.stationId != 0) + writer.writeInt32(9, this.stationId); + if (this.sideId != 0) + writer.writeInt32(10, this.sideId); + if (this.trackName.length) + writer.writeString(11, this.trackName); + if (this.recordType != false) + writer.writeBool(12, this.recordType); + if (this.recordTime != 0) + writer.writeInt64(13, this.recordTime); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): TrainRecord { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new TrainRecord(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.trainId = reader.readString(); + break; + case 3: + message.globalId = reader.readString(); + break; + case 4: + message.localSubId = reader.readInt32(); + break; + case 5: + message.groupId = reader.readString(); + break; + case 6: + message.destinationId = reader.readInt32(); + break; + case 7: + message.trainType = reader.readInt32(); + break; + case 8: + message.dir = reader.readInt32(); + break; + case 9: + message.stationId = reader.readInt32(); + break; + case 10: + message.sideId = reader.readInt32(); + break; + case 11: + message.trackName = reader.readString(); + break; + case 12: + message.recordType = reader.readBool(); + break; + case 13: + message.recordTime = reader.readInt64(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): TrainRecord { + return TrainRecord.deserialize(bytes); + } + } +} diff --git a/src/protos/ws_message.ts b/src/protos/ws_message.ts new file mode 100644 index 0000000..628cde0 --- /dev/null +++ b/src/protos/ws_message.ts @@ -0,0 +1,646 @@ +/** + * Generated by the protoc-gen-ts. DO NOT EDIT! + * compiler version: 4.23.1 + * source: ws_message.proto + * git: https://github.com/thesayyn/protoc-gen-ts */ +import * as dependency_1 from "./device_status"; +import * as dependency_2 from "./train"; +import * as pb_1 from "google-protobuf"; +export namespace state { + export class WsLineMessage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + rtu?: dependency_1.state.Rtu[]; + station?: dependency_1.state.Station[]; + signal?: dependency_1.state.Signal[]; + entry?: dependency_1.state.Entry[]; + switch?: dependency_1.state.Switch[]; + track?: dependency_1.state.Track[]; + platform?: dependency_1.state.Platform[]; + scada?: dependency_1.state.Scada[]; + waterProofDoor?: dependency_1.state.WaterProofDoor[]; + workArea?: dependency_1.state.WorkArea[]; + gama?: dependency_1.state.Gama[]; + netWork?: dependency_1.state.OccNccFepNetwork[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("rtu" in data && data.rtu != undefined) { + this.rtu = data.rtu; + } + if ("station" in data && data.station != undefined) { + this.station = data.station; + } + if ("signal" in data && data.signal != undefined) { + this.signal = data.signal; + } + if ("entry" in data && data.entry != undefined) { + this.entry = data.entry; + } + if ("switch" in data && data.switch != undefined) { + this.switch = data.switch; + } + if ("track" in data && data.track != undefined) { + this.track = data.track; + } + if ("platform" in data && data.platform != undefined) { + this.platform = data.platform; + } + if ("scada" in data && data.scada != undefined) { + this.scada = data.scada; + } + if ("waterProofDoor" in data && data.waterProofDoor != undefined) { + this.waterProofDoor = data.waterProofDoor; + } + if ("workArea" in data && data.workArea != undefined) { + this.workArea = data.workArea; + } + if ("gama" in data && data.gama != undefined) { + this.gama = data.gama; + } + if ("netWork" in data && data.netWork != undefined) { + this.netWork = data.netWork; + } + } + } + get rtu() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Rtu, 1) as dependency_1.state.Rtu[]; + } + set rtu(value: dependency_1.state.Rtu[]) { + pb_1.Message.setRepeatedWrapperField(this, 1, value); + } + get station() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Station, 2) as dependency_1.state.Station[]; + } + set station(value: dependency_1.state.Station[]) { + pb_1.Message.setRepeatedWrapperField(this, 2, value); + } + get signal() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Signal, 3) as dependency_1.state.Signal[]; + } + set signal(value: dependency_1.state.Signal[]) { + pb_1.Message.setRepeatedWrapperField(this, 3, value); + } + get entry() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Entry, 4) as dependency_1.state.Entry[]; + } + set entry(value: dependency_1.state.Entry[]) { + pb_1.Message.setRepeatedWrapperField(this, 4, value); + } + get switch() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Switch, 5) as dependency_1.state.Switch[]; + } + set switch(value: dependency_1.state.Switch[]) { + pb_1.Message.setRepeatedWrapperField(this, 5, value); + } + get track() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Track, 6) as dependency_1.state.Track[]; + } + set track(value: dependency_1.state.Track[]) { + pb_1.Message.setRepeatedWrapperField(this, 6, value); + } + get platform() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Platform, 7) as dependency_1.state.Platform[]; + } + set platform(value: dependency_1.state.Platform[]) { + pb_1.Message.setRepeatedWrapperField(this, 7, value); + } + get scada() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Scada, 8) as dependency_1.state.Scada[]; + } + set scada(value: dependency_1.state.Scada[]) { + pb_1.Message.setRepeatedWrapperField(this, 8, value); + } + get waterProofDoor() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.WaterProofDoor, 9) as dependency_1.state.WaterProofDoor[]; + } + set waterProofDoor(value: dependency_1.state.WaterProofDoor[]) { + pb_1.Message.setRepeatedWrapperField(this, 9, value); + } + get workArea() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.WorkArea, 10) as dependency_1.state.WorkArea[]; + } + set workArea(value: dependency_1.state.WorkArea[]) { + pb_1.Message.setRepeatedWrapperField(this, 10, value); + } + get gama() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.Gama, 11) as dependency_1.state.Gama[]; + } + set gama(value: dependency_1.state.Gama[]) { + pb_1.Message.setRepeatedWrapperField(this, 11, value); + } + get netWork() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_1.state.OccNccFepNetwork, 12) as dependency_1.state.OccNccFepNetwork[]; + } + set netWork(value: dependency_1.state.OccNccFepNetwork[]) { + pb_1.Message.setRepeatedWrapperField(this, 12, value); + } + static fromObject(data: { + rtu?: ReturnType[]; + station?: ReturnType[]; + signal?: ReturnType[]; + entry?: ReturnType[]; + switch?: ReturnType[]; + track?: ReturnType[]; + platform?: ReturnType[]; + scada?: ReturnType[]; + waterProofDoor?: ReturnType[]; + workArea?: ReturnType[]; + gama?: ReturnType[]; + netWork?: ReturnType[]; + }): WsLineMessage { + const message = new WsLineMessage({}); + if (data.rtu != null) { + message.rtu = data.rtu.map(item => dependency_1.state.Rtu.fromObject(item)); + } + if (data.station != null) { + message.station = data.station.map(item => dependency_1.state.Station.fromObject(item)); + } + if (data.signal != null) { + message.signal = data.signal.map(item => dependency_1.state.Signal.fromObject(item)); + } + if (data.entry != null) { + message.entry = data.entry.map(item => dependency_1.state.Entry.fromObject(item)); + } + if (data.switch != null) { + message.switch = data.switch.map(item => dependency_1.state.Switch.fromObject(item)); + } + if (data.track != null) { + message.track = data.track.map(item => dependency_1.state.Track.fromObject(item)); + } + if (data.platform != null) { + message.platform = data.platform.map(item => dependency_1.state.Platform.fromObject(item)); + } + if (data.scada != null) { + message.scada = data.scada.map(item => dependency_1.state.Scada.fromObject(item)); + } + if (data.waterProofDoor != null) { + message.waterProofDoor = data.waterProofDoor.map(item => dependency_1.state.WaterProofDoor.fromObject(item)); + } + if (data.workArea != null) { + message.workArea = data.workArea.map(item => dependency_1.state.WorkArea.fromObject(item)); + } + if (data.gama != null) { + message.gama = data.gama.map(item => dependency_1.state.Gama.fromObject(item)); + } + if (data.netWork != null) { + message.netWork = data.netWork.map(item => dependency_1.state.OccNccFepNetwork.fromObject(item)); + } + return message; + } + toObject() { + const data: { + rtu?: ReturnType[]; + station?: ReturnType[]; + signal?: ReturnType[]; + entry?: ReturnType[]; + switch?: ReturnType[]; + track?: ReturnType[]; + platform?: ReturnType[]; + scada?: ReturnType[]; + waterProofDoor?: ReturnType[]; + workArea?: ReturnType[]; + gama?: ReturnType[]; + netWork?: ReturnType[]; + } = {}; + if (this.rtu != null) { + data.rtu = this.rtu.map((item: dependency_1.state.Rtu) => item.toObject()); + } + if (this.station != null) { + data.station = this.station.map((item: dependency_1.state.Station) => item.toObject()); + } + if (this.signal != null) { + data.signal = this.signal.map((item: dependency_1.state.Signal) => item.toObject()); + } + if (this.entry != null) { + data.entry = this.entry.map((item: dependency_1.state.Entry) => item.toObject()); + } + if (this.switch != null) { + data.switch = this.switch.map((item: dependency_1.state.Switch) => item.toObject()); + } + if (this.track != null) { + data.track = this.track.map((item: dependency_1.state.Track) => item.toObject()); + } + if (this.platform != null) { + data.platform = this.platform.map((item: dependency_1.state.Platform) => item.toObject()); + } + if (this.scada != null) { + data.scada = this.scada.map((item: dependency_1.state.Scada) => item.toObject()); + } + if (this.waterProofDoor != null) { + data.waterProofDoor = this.waterProofDoor.map((item: dependency_1.state.WaterProofDoor) => item.toObject()); + } + if (this.workArea != null) { + data.workArea = this.workArea.map((item: dependency_1.state.WorkArea) => item.toObject()); + } + if (this.gama != null) { + data.gama = this.gama.map((item: dependency_1.state.Gama) => item.toObject()); + } + if (this.netWork != null) { + data.netWork = this.netWork.map((item: dependency_1.state.OccNccFepNetwork) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.rtu.length) + writer.writeRepeatedMessage(1, this.rtu, (item: dependency_1.state.Rtu) => item.serialize(writer)); + if (this.station.length) + writer.writeRepeatedMessage(2, this.station, (item: dependency_1.state.Station) => item.serialize(writer)); + if (this.signal.length) + writer.writeRepeatedMessage(3, this.signal, (item: dependency_1.state.Signal) => item.serialize(writer)); + if (this.entry.length) + writer.writeRepeatedMessage(4, this.entry, (item: dependency_1.state.Entry) => item.serialize(writer)); + if (this.switch.length) + writer.writeRepeatedMessage(5, this.switch, (item: dependency_1.state.Switch) => item.serialize(writer)); + if (this.track.length) + writer.writeRepeatedMessage(6, this.track, (item: dependency_1.state.Track) => item.serialize(writer)); + if (this.platform.length) + writer.writeRepeatedMessage(7, this.platform, (item: dependency_1.state.Platform) => item.serialize(writer)); + if (this.scada.length) + writer.writeRepeatedMessage(8, this.scada, (item: dependency_1.state.Scada) => item.serialize(writer)); + if (this.waterProofDoor.length) + writer.writeRepeatedMessage(9, this.waterProofDoor, (item: dependency_1.state.WaterProofDoor) => item.serialize(writer)); + if (this.workArea.length) + writer.writeRepeatedMessage(10, this.workArea, (item: dependency_1.state.WorkArea) => item.serialize(writer)); + if (this.gama.length) + writer.writeRepeatedMessage(11, this.gama, (item: dependency_1.state.Gama) => item.serialize(writer)); + if (this.netWork.length) + writer.writeRepeatedMessage(12, this.netWork, (item: dependency_1.state.OccNccFepNetwork) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): WsLineMessage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new WsLineMessage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.rtu, () => pb_1.Message.addToRepeatedWrapperField(message, 1, dependency_1.state.Rtu.deserialize(reader), dependency_1.state.Rtu)); + break; + case 2: + reader.readMessage(message.station, () => pb_1.Message.addToRepeatedWrapperField(message, 2, dependency_1.state.Station.deserialize(reader), dependency_1.state.Station)); + break; + case 3: + reader.readMessage(message.signal, () => pb_1.Message.addToRepeatedWrapperField(message, 3, dependency_1.state.Signal.deserialize(reader), dependency_1.state.Signal)); + break; + case 4: + reader.readMessage(message.entry, () => pb_1.Message.addToRepeatedWrapperField(message, 4, dependency_1.state.Entry.deserialize(reader), dependency_1.state.Entry)); + break; + case 5: + reader.readMessage(message.switch, () => pb_1.Message.addToRepeatedWrapperField(message, 5, dependency_1.state.Switch.deserialize(reader), dependency_1.state.Switch)); + break; + case 6: + reader.readMessage(message.track, () => pb_1.Message.addToRepeatedWrapperField(message, 6, dependency_1.state.Track.deserialize(reader), dependency_1.state.Track)); + break; + case 7: + reader.readMessage(message.platform, () => pb_1.Message.addToRepeatedWrapperField(message, 7, dependency_1.state.Platform.deserialize(reader), dependency_1.state.Platform)); + break; + case 8: + reader.readMessage(message.scada, () => pb_1.Message.addToRepeatedWrapperField(message, 8, dependency_1.state.Scada.deserialize(reader), dependency_1.state.Scada)); + break; + case 9: + reader.readMessage(message.waterProofDoor, () => pb_1.Message.addToRepeatedWrapperField(message, 9, dependency_1.state.WaterProofDoor.deserialize(reader), dependency_1.state.WaterProofDoor)); + break; + case 10: + reader.readMessage(message.workArea, () => pb_1.Message.addToRepeatedWrapperField(message, 10, dependency_1.state.WorkArea.deserialize(reader), dependency_1.state.WorkArea)); + break; + case 11: + reader.readMessage(message.gama, () => pb_1.Message.addToRepeatedWrapperField(message, 11, dependency_1.state.Gama.deserialize(reader), dependency_1.state.Gama)); + break; + case 12: + reader.readMessage(message.netWork, () => pb_1.Message.addToRepeatedWrapperField(message, 12, dependency_1.state.OccNccFepNetwork.deserialize(reader), dependency_1.state.OccNccFepNetwork)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): WsLineMessage { + return WsLineMessage.deserialize(bytes); + } + } + export class WsLineTrainMessage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + trainInfo?: dependency_2.train.TrainInfo[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("trainInfo" in data && data.trainInfo != undefined) { + this.trainInfo = data.trainInfo; + } + } + } + get trainInfo() { + return pb_1.Message.getRepeatedWrapperField(this, dependency_2.train.TrainInfo, 1) as dependency_2.train.TrainInfo[]; + } + set trainInfo(value: dependency_2.train.TrainInfo[]) { + pb_1.Message.setRepeatedWrapperField(this, 1, value); + } + static fromObject(data: { + trainInfo?: ReturnType[]; + }): WsLineTrainMessage { + const message = new WsLineTrainMessage({}); + if (data.trainInfo != null) { + message.trainInfo = data.trainInfo.map(item => dependency_2.train.TrainInfo.fromObject(item)); + } + return message; + } + toObject() { + const data: { + trainInfo?: ReturnType[]; + } = {}; + if (this.trainInfo != null) { + data.trainInfo = this.trainInfo.map((item: dependency_2.train.TrainInfo) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.trainInfo.length) + writer.writeRepeatedMessage(1, this.trainInfo, (item: dependency_2.train.TrainInfo) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): WsLineTrainMessage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new WsLineTrainMessage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.trainInfo, () => pb_1.Message.addToRepeatedWrapperField(message, 1, dependency_2.train.TrainInfo.deserialize(reader), dependency_2.train.TrainInfo)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): WsLineTrainMessage { + return WsLineTrainMessage.deserialize(bytes); + } + } + export class WsLineNetMessage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + offset?: WsLineNetTrainOffsetMessage[]; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [1], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("offset" in data && data.offset != undefined) { + this.offset = data.offset; + } + } + } + get offset() { + return pb_1.Message.getRepeatedWrapperField(this, WsLineNetTrainOffsetMessage, 1) as WsLineNetTrainOffsetMessage[]; + } + set offset(value: WsLineNetTrainOffsetMessage[]) { + pb_1.Message.setRepeatedWrapperField(this, 1, value); + } + static fromObject(data: { + offset?: ReturnType[]; + }): WsLineNetMessage { + const message = new WsLineNetMessage({}); + if (data.offset != null) { + message.offset = data.offset.map(item => WsLineNetTrainOffsetMessage.fromObject(item)); + } + return message; + } + toObject() { + const data: { + offset?: ReturnType[]; + } = {}; + if (this.offset != null) { + data.offset = this.offset.map((item: WsLineNetTrainOffsetMessage) => item.toObject()); + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.offset.length) + writer.writeRepeatedMessage(1, this.offset, (item: WsLineNetTrainOffsetMessage) => item.serialize(writer)); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): WsLineNetMessage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new WsLineNetMessage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + reader.readMessage(message.offset, () => pb_1.Message.addToRepeatedWrapperField(message, 1, WsLineNetTrainOffsetMessage.deserialize(reader), WsLineNetTrainOffsetMessage)); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): WsLineNetMessage { + return WsLineNetMessage.deserialize(bytes); + } + } + export class WsLineNetTrainOffsetMessage extends pb_1.Message { + #one_of_decls: number[][] = []; + constructor(data?: any[] | { + lineId?: number; + trainIndex?: string; + groupId?: string; + show?: boolean; + kilometerCode?: number; + dir?: number; + }) { + super(); + pb_1.Message.initialize(this, Array.isArray(data) ? data : [], 0, -1, [], this.#one_of_decls); + if (!Array.isArray(data) && typeof data == "object") { + if ("lineId" in data && data.lineId != undefined) { + this.lineId = data.lineId; + } + if ("trainIndex" in data && data.trainIndex != undefined) { + this.trainIndex = data.trainIndex; + } + if ("groupId" in data && data.groupId != undefined) { + this.groupId = data.groupId; + } + if ("show" in data && data.show != undefined) { + this.show = data.show; + } + if ("kilometerCode" in data && data.kilometerCode != undefined) { + this.kilometerCode = data.kilometerCode; + } + if ("dir" in data && data.dir != undefined) { + this.dir = data.dir; + } + } + } + get lineId() { + return pb_1.Message.getFieldWithDefault(this, 1, 0) as number; + } + set lineId(value: number) { + pb_1.Message.setField(this, 1, value); + } + get trainIndex() { + return pb_1.Message.getFieldWithDefault(this, 2, "") as string; + } + set trainIndex(value: string) { + pb_1.Message.setField(this, 2, value); + } + get groupId() { + return pb_1.Message.getFieldWithDefault(this, 3, "") as string; + } + set groupId(value: string) { + pb_1.Message.setField(this, 3, value); + } + get show() { + return pb_1.Message.getFieldWithDefault(this, 4, false) as boolean; + } + set show(value: boolean) { + pb_1.Message.setField(this, 4, value); + } + get kilometerCode() { + return pb_1.Message.getFieldWithDefault(this, 5, 0) as number; + } + set kilometerCode(value: number) { + pb_1.Message.setField(this, 5, value); + } + get dir() { + return pb_1.Message.getFieldWithDefault(this, 6, 0) as number; + } + set dir(value: number) { + pb_1.Message.setField(this, 6, value); + } + static fromObject(data: { + lineId?: number; + trainIndex?: string; + groupId?: string; + show?: boolean; + kilometerCode?: number; + dir?: number; + }): WsLineNetTrainOffsetMessage { + const message = new WsLineNetTrainOffsetMessage({}); + if (data.lineId != null) { + message.lineId = data.lineId; + } + if (data.trainIndex != null) { + message.trainIndex = data.trainIndex; + } + if (data.groupId != null) { + message.groupId = data.groupId; + } + if (data.show != null) { + message.show = data.show; + } + if (data.kilometerCode != null) { + message.kilometerCode = data.kilometerCode; + } + if (data.dir != null) { + message.dir = data.dir; + } + return message; + } + toObject() { + const data: { + lineId?: number; + trainIndex?: string; + groupId?: string; + show?: boolean; + kilometerCode?: number; + dir?: number; + } = {}; + if (this.lineId != null) { + data.lineId = this.lineId; + } + if (this.trainIndex != null) { + data.trainIndex = this.trainIndex; + } + if (this.groupId != null) { + data.groupId = this.groupId; + } + if (this.show != null) { + data.show = this.show; + } + if (this.kilometerCode != null) { + data.kilometerCode = this.kilometerCode; + } + if (this.dir != null) { + data.dir = this.dir; + } + return data; + } + serialize(): Uint8Array; + serialize(w: pb_1.BinaryWriter): void; + serialize(w?: pb_1.BinaryWriter): Uint8Array | void { + const writer = w || new pb_1.BinaryWriter(); + if (this.lineId != 0) + writer.writeInt32(1, this.lineId); + if (this.trainIndex.length) + writer.writeString(2, this.trainIndex); + if (this.groupId.length) + writer.writeString(3, this.groupId); + if (this.show != false) + writer.writeBool(4, this.show); + if (this.kilometerCode != 0) + writer.writeInt64(5, this.kilometerCode); + if (this.dir != 0) + writer.writeInt32(6, this.dir); + if (!w) + return writer.getResultBuffer(); + } + static deserialize(bytes: Uint8Array | pb_1.BinaryReader): WsLineNetTrainOffsetMessage { + const reader = bytes instanceof pb_1.BinaryReader ? bytes : new pb_1.BinaryReader(bytes), message = new WsLineNetTrainOffsetMessage(); + while (reader.nextField()) { + if (reader.isEndGroup()) + break; + switch (reader.getFieldNumber()) { + case 1: + message.lineId = reader.readInt32(); + break; + case 2: + message.trainIndex = reader.readString(); + break; + case 3: + message.groupId = reader.readString(); + break; + case 4: + message.show = reader.readBool(); + break; + case 5: + message.kilometerCode = reader.readInt64(); + break; + case 6: + message.dir = reader.readInt32(); + break; + default: reader.skipField(); + } + } + return message; + } + serializeBinary(): Uint8Array { + return this.serialize(); + } + static deserializeBinary(bytes: Uint8Array): WsLineNetTrainOffsetMessage { + return WsLineNetTrainOffsetMessage.deserialize(bytes); + } + } +} diff --git a/src/quasar.d.ts b/src/quasar.d.ts new file mode 100644 index 0000000..5937f7a --- /dev/null +++ b/src/quasar.d.ts @@ -0,0 +1,9 @@ +/* eslint-disable */ + +// Forces TS to apply `@quasar/app-vite` augmentations of `quasar` package +// Removing this would break `quasar/wrappers` imports as those typings are declared +// into `@quasar/app-vite` +// As a side effect, since `@quasar/app-vite` reference `quasar` to augment it, +// this declaration also apply `quasar` own +// augmentations (eg. adds `$q` into Vue component context) +/// diff --git a/src/router/index.ts b/src/router/index.ts new file mode 100644 index 0000000..4531114 --- /dev/null +++ b/src/router/index.ts @@ -0,0 +1,36 @@ +import { route } from 'quasar/wrappers'; +import { + createMemoryHistory, + createRouter, + createWebHashHistory, + createWebHistory, +} from 'vue-router'; + +import routes from './routes'; + +/* + * If not building with SSR mode, you can + * directly export the Router instantiation; + * + * The function below can be async too; either use + * async/await or return a Promise which resolves + * with the Router instance. + */ + +export default route(function (/* { store, ssrContext } */) { + const createHistory = process.env.SERVER + ? createMemoryHistory + : (process.env.VUE_ROUTER_MODE === 'history' ? createWebHistory : createWebHashHistory); + + const Router = createRouter({ + scrollBehavior: () => ({ left: 0, top: 0 }), + routes, + + // Leave this as is and make changes in quasar.conf.js instead! + // quasar.conf.js -> build -> vueRouterMode + // quasar.conf.js -> build -> publicPath + history: createHistory(process.env.VUE_ROUTER_BASE), + }); + + return Router; +}); diff --git a/src/router/routes.ts b/src/router/routes.ts new file mode 100644 index 0000000..b553b77 --- /dev/null +++ b/src/router/routes.ts @@ -0,0 +1,90 @@ +import { RouteRecordRaw } from 'vue-router'; + +const routes: RouteRecordRaw[] = [ + { + path: '/', + name: 'home', + redirect: '/monitor', + component: () => import('layouts/MainLayout.vue'), + children: [{ path: '', component: () => import('pages/IndexPage.vue') }], + }, + + { + path: '/login', + name: 'login', + component: () => import('pages/UserLogin.vue'), + }, + + { + path: '/register', + name: 'register', + component: () => import('pages/UserRegister.vue'), + }, + { + path: '/dataManage', + name: 'dataManage', + component: () => import('layouts/MainLayout.vue'), + children: [ + { + path: 'draft', + name: 'draft', + component: () => import('pages/DraftManage.vue'), + }, + { + path: 'publish', + name: 'publish', + component: () => import('pages/PublishManage.vue'), + }, + { + path: 'lineInfo', + name: 'lineInfo', + component: () => import('pages/LineInfoManage.vue'), + }, + ], + }, + { + path: '/sysManage', + name: 'sysManage', + component: () => import('layouts/MainLayout.vue'), + children: [ + { + path: 'user', + name: 'user', + meta: { + description: '用户管理', + }, + component: () => import('pages/UserManage.vue'), + }, + ], + }, + { + path: '/painting/:id/:type', + name: 'painting', + component: () => import('layouts/DrawLayout.vue'), + }, + { + path: '/linemap/:id/:type', + name: 'linemap', + component: () => import('layouts/LineLayout.vue'), + }, + { + path: '/line/monitor/:lineId', + name: 'linemonitor', + component: () => import('pages/LineMonitorPage.vue'), + }, + { + path: '/monitor', + name: 'monitor', + component: () => import('layouts/MainLayout.vue'), + children: [{ path: '', component: () => import('pages/MonitorPage.vue') }], + }, + + // Always leave this as last one, + // but you can also remove it + { + path: '/:catchAll(.*)*', + component: () => import('pages/ErrorNotFound.vue'), + }, +]; + +export default routes; diff --git a/src/shims-vue.d.ts b/src/shims-vue.d.ts new file mode 100644 index 0000000..4e6894b --- /dev/null +++ b/src/shims-vue.d.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ + +/// + +// Mocks all files ending in `.vue` showing them as plain Vue instances +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/src/stores/draw-store.ts b/src/stores/draw-store.ts new file mode 100644 index 0000000..e1a35af --- /dev/null +++ b/src/stores/draw-store.ts @@ -0,0 +1,87 @@ +import { defineStore } from 'pinia'; +import { destroyDrawApp, getDrawApp, initDrawApp } from 'src/drawApp'; +import { DrawAssistant, JlCanvas, JlDrawApp, JlGraphic } from 'src/jl-graphic'; + +export const useDrawStore = defineStore('draw', { + state: () => ({ + drawAssistant: null as DrawAssistant | null, + selectedGraphics: null as JlGraphic[] | null, + draftId: null as number | null, + draftType: 'Line', + oneClickType: '', + }), + getters: { + drawMode: (state) => state.drawAssistant != null, + drawGraphicType: (state) => state.drawAssistant?.type, + drawGraphicName: (state) => state.drawAssistant?.description, + drawGraphicTemplate: (state) => state.drawAssistant?.graphicTemplate, + + selectedGraphicType: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0].type; + } + } + }, + selectedObjName: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length == 0) { + return '画布'; + } else if (state.selectedGraphics.length == 1) { + return state.selectedGraphics[0].type; + } + return '多选'; + } + return ''; + }, + selectedGraphic: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0]; + } + } + return null; + }, + }, + actions: { + getDrawApp(): JlDrawApp { + const app = getDrawApp(); + if (app == null) { + throw new Error('未初始化app'); + } + return app; + }, + getJlCanvas(): JlCanvas { + return this.getDrawApp().canvas; + }, + initDrawApp(dom: HTMLElement) { + const app = initDrawApp(dom); + app.on('interaction-plugin-resume', (plugin) => { + if (plugin.isAppPlugin()) { + if (Object.hasOwn(plugin, '__GraphicDrawAssistant')) { + this.drawAssistant = plugin as DrawAssistant; + } else { + this.drawAssistant = null; + } + } + }); + app.on('graphicselectedchange', () => { + this.selectedGraphics = app.selectedGraphics; + }); + this.selectedGraphics = []; + return app; + }, + destroy() { + // console.log('绘制状态清空,绘制应用销毁'); + this.drawAssistant = null; + this.selectedGraphics = null; + destroyDrawApp(); + }, + setDraftId(id: number | null) { + this.draftId = id; + }, + setDraftType(type: string) { + this.draftType = type; + }, + }, +}); diff --git a/src/stores/example-store.ts b/src/stores/example-store.ts new file mode 100644 index 0000000..83e8390 --- /dev/null +++ b/src/stores/example-store.ts @@ -0,0 +1,15 @@ +import { defineStore } from 'pinia'; + +export const useCounterStore = defineStore('counter', { + state: () => ({ + counter: 0, + }), + getters: { + doubleCount: (state) => state.counter * 2, + }, + actions: { + increment() { + this.counter++; + }, + }, +}); diff --git a/src/stores/index.ts b/src/stores/index.ts new file mode 100644 index 0000000..d30b7cf --- /dev/null +++ b/src/stores/index.ts @@ -0,0 +1,32 @@ +import { store } from 'quasar/wrappers' +import { createPinia } from 'pinia' +import { Router } from 'vue-router'; + +/* + * When adding new properties to stores, you should also + * extend the `PiniaCustomProperties` interface. + * @see https://pinia.vuejs.org/core-concepts/plugins.html#typing-new-store-properties + */ +declare module 'pinia' { + export interface PiniaCustomProperties { + readonly router: Router; + } +} + +/* + * If not building with SSR mode, you can + * directly export the Store instantiation; + * + * The function below can be async too; either use + * async/await or return a Promise which resolves + * with the Store instance. + */ + +export default store((/* { ssrContext } */) => { + const pinia = createPinia() + + // You can add Pinia plugins here + // pinia.use(SomePiniaPlugin) + + return pinia +}) diff --git a/src/stores/line-net-store.ts b/src/stores/line-net-store.ts new file mode 100644 index 0000000..c8fdad6 --- /dev/null +++ b/src/stores/line-net-store.ts @@ -0,0 +1,58 @@ +import { defineStore } from 'pinia'; +import { JlCanvas, JlGraphic, GraphicApp } from 'src/jl-graphic'; +import { + initLineNetApp, + getLineNetApp, + destroyLineNetApp, +} from 'src/drawApp/lineNetApp'; + +export const useLineNetStore = defineStore('lineNet', { + state: () => ({ + selectedGraphics: null as JlGraphic[] | null, + lineNetName: null as string | null, + }), + getters: { + selectedGraphicType: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0].type; + } + } + }, + selectedGraphic: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0]; + } + } + return null; + }, + }, + actions: { + getLineNetApp(): GraphicApp { + const app = getLineNetApp(); + if (app == null) { + throw new Error('未初始化app'); + } + return app; + }, + getJlCanvas(): JlCanvas { + return this.getLineNetApp().canvas; + }, + initLineNetApp(dom: HTMLElement) { + const app = initLineNetApp(dom); + app.on('graphicselectedchange', () => { + this.selectedGraphics = app.selectedGraphics; + }); + this.selectedGraphics = []; + return app; + }, + destroy() { + this.selectedGraphics = null; + destroyLineNetApp(); + }, + setLineNetName(name: string | null) { + this.lineNetName = name; + }, + }, +}); diff --git a/src/stores/line-store.ts b/src/stores/line-store.ts new file mode 100644 index 0000000..5a6ae1a --- /dev/null +++ b/src/stores/line-store.ts @@ -0,0 +1,50 @@ +import { defineStore } from 'pinia'; +import { JlCanvas, JlGraphic, GraphicApp } from 'src/jl-graphic'; +import { initLineApp, getLineApp, destroyLineApp } from 'src/drawApp/lineApp'; + +export const useLineStore = defineStore('line', { + state: () => ({ + selectedGraphics: null as JlGraphic[] | null, + lineId: null as number | null, + lineName: null as string | null, + }), + getters: { + selectedGraphicType: (state) => { + if (state.selectedGraphics) { + if (state.selectedGraphics.length === 1) { + return state.selectedGraphics[0].type; + } + } + }, + }, + actions: { + getLineApp(): GraphicApp { + const app = getLineApp(); + if (app == null) { + throw new Error('未初始化app'); + } + return app; + }, + getJlCanvas(): JlCanvas { + return this.getLineApp().canvas; + }, + initLineApp(dom: HTMLElement) { + const app = initLineApp(dom); + app.on('graphicselectedchange', () => { + this.selectedGraphics = app.selectedGraphics; + }); + this.selectedGraphics = []; + return app; + }, + destroy() { + this.selectedGraphics = null; + destroyLineApp(); + }, + setLineId(id: number | null) { + this.lineId = id; + }, + setLineName(name: string | null) { + this.lineName = name; + }, + }, +}); diff --git a/src/stores/store-flag.d.ts b/src/stores/store-flag.d.ts new file mode 100644 index 0000000..7677175 --- /dev/null +++ b/src/stores/store-flag.d.ts @@ -0,0 +1,10 @@ +/* eslint-disable */ +// THIS FEATURE-FLAG FILE IS AUTOGENERATED, +// REMOVAL OR CHANGES WILL CAUSE RELATED TYPES TO STOP WORKING +import "quasar/dist/types/feature-flag"; + +declare module "quasar/dist/types/feature-flag" { + interface QuasarFeatureFlags { + store: true; + } +} diff --git a/src/utils/CommonNotify.ts b/src/utils/CommonNotify.ts new file mode 100644 index 0000000..aee90fd --- /dev/null +++ b/src/utils/CommonNotify.ts @@ -0,0 +1,38 @@ +import { AxiosError } from 'axios'; +import { Notify } from 'quasar'; + +export function successNotify(message: string) { + Notify.create({ + type: 'positive', + message: message, + }); +} + +export function errorNotify(message: string, error: any): void { + console.error(error); + let errMsg = ''; + if (error instanceof AxiosError) { + errMsg = error.response?.data.errMsg; + } else if (error.data) { + errMsg = error.data.errMsg; + } else if (error.message) { + errMsg = error.message; + } + Notify.create({ + type: 'negative', + message: `${message}: ${errMsg}`, + }); +} + +export function errorDismissNotify( + message: string, + onDismiss: () => void, + error: any +): void { + console.error(error); + Notify.create({ + type: 'negative', + message: message, + onDismiss, + }); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..483ae96 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "@quasar/app-vite/tsconfig-preset", + "compilerOptions": { + "baseUrl": "." + }, + "include": ["src/**/*"], + "exclude": ["/graphic-pixi/*/**.ts"] +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..e9656b7 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3399 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/parser@^7.20.15", "@babel/parser@^7.21.3": + version "7.22.4" + resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.22.4.tgz" + integrity sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA== + +"@esbuild/linux-loong64@0.14.54": + version "0.14.54" + resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.14.54.tgz#de2a4be678bd4d0d1ffbb86e6de779cde5999028" + integrity sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.3.0": + version "4.4.0" + resolved "https://registry.npmmirror.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.4.0": + version "4.5.1" + resolved "https://registry.npmmirror.com/@eslint-community/regexpp/-/regexpp-4.5.1.tgz" + integrity sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ== + +"@eslint/eslintrc@^2.0.3": + version "2.0.3" + resolved "https://registry.npmmirror.com/@eslint/eslintrc/-/eslintrc-2.0.3.tgz" + integrity sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.5.2" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.41.0": + version "8.41.0" + resolved "https://registry.npmmirror.com/@eslint/js/-/js-8.41.0.tgz" + integrity sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA== + +"@humanwhocodes/config-array@^0.11.8": + version "0.11.8" + resolved "https://registry.npmmirror.com/@humanwhocodes/config-array/-/config-array-0.11.8.tgz" + integrity sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.npmmirror.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + +"@jridgewell/sourcemap-codec@^1.4.13": + version "1.4.15" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.npmmirror.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmmirror.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pixi/accessibility@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/accessibility/-/accessibility-7.2.4.tgz" + integrity sha512-EVjuqUqv9FeYFXCv0S0qj1hgCtbAMNBPCbOGEtiMogpM++/IySxBZvcOYg3rRgo9inwt2s4Bi7kUiqMPD8hItw== + +"@pixi/app@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/app/-/app-7.2.4.tgz" + integrity sha512-eJ2jpu5P28ip07nLItw6sETXn45P4KR/leMJ6zPHRlhT1m8t5zTsWr3jK4Uj8LF2E+6KlPNzLQh5Alf/unn/aQ== + +"@pixi/assets@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/assets/-/assets-7.2.4.tgz" + integrity sha512-7199re3wvMAlVqXLaCyAr8IkJSXqkeVAxcYyB2rBu4Id5m2hhlGX1dQsdMBiCXLwu6/LLVqDvJggSNVQBzL6ZQ== + dependencies: + "@types/css-font-loading-module" "^0.0.7" + +"@pixi/color@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/color/-/color-7.2.4.tgz" + integrity sha512-B/+9JRcXe2uE8wQfsueFRPZVayF2VEMRB7XGeRAsWCryOX19nmWhv0Nt3nOU2rvzI0niz9XgugJXsB6vVmDFSg== + dependencies: + colord "^2.9.3" + +"@pixi/compressed-textures@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/compressed-textures/-/compressed-textures-7.2.4.tgz" + integrity sha512-atnWyw/ot/Wg69qhgskKiuTYCZx15IxV35sa0KyXMthyjyvDLCIvOn0nczM6wCBy9H96SjJbfgynVWhVrip6qw== + +"@pixi/constants@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/constants/-/constants-7.2.4.tgz" + integrity sha512-hKuHBWR6N4Q0Sf5MGF3/9l+POg/G5rqhueHfzofiuelnKg7aBs3BVjjZ+6hZbd6M++vOUmxYelEX/NEFBxrheA== + +"@pixi/core@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/core/-/core-7.2.4.tgz" + integrity sha512-0XtvrfxHlS2T+beBBSpo7GI8+QLyyTqMVQpNmPqB4woYxzrOEJ9JaUFBaBfCvycLeUkfVih1u6HAbtF+2d1EjQ== + dependencies: + "@pixi/color" "7.2.4" + "@pixi/constants" "7.2.4" + "@pixi/extensions" "7.2.4" + "@pixi/math" "7.2.4" + "@pixi/runner" "7.2.4" + "@pixi/settings" "7.2.4" + "@pixi/ticker" "7.2.4" + "@pixi/utils" "7.2.4" + "@types/offscreencanvas" "^2019.6.4" + +"@pixi/display@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/display/-/display-7.2.4.tgz" + integrity sha512-w5tqb8cWEO5qIDaO9GEqRvxYhL0iMk0Wsngw23bbLm1gLEQmrFkB2tpJlRAqd7H82C3DrDDeWvkrrxW6+m4apg== + +"@pixi/events@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/events/-/events-7.2.4.tgz" + integrity sha512-/JtmoB98fzIU8giN9xvlRvmvOi6u4MaD2DnKNOMHkQ1MBraj3pmrXM9fZ0JbNzi+324GraAAY76QidgHjIYoYQ== + +"@pixi/extensions@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/extensions/-/extensions-7.2.4.tgz" + integrity sha512-Mnqv9scbL1ARD3QFKfOWs2aSVJJfP1dL8g5UiqGImYO3rZbz/9QCzXOeMVIZ5n3iaRyKMNhFFr84/zUja2H7Dw== + +"@pixi/extract@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/extract/-/extract-7.2.4.tgz" + integrity sha512-wlXZg+J2L/1jQhRi5nZQP/cXshovhjksjss91eAKMvY5aGxNAQovCP4xotJ/XJjfTvPMpeRzHPFYzm3PrOPQ7g== + +"@pixi/filter-alpha@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/filter-alpha/-/filter-alpha-7.2.4.tgz" + integrity sha512-UTUMSGyktUr+I9vmigqJo9iUhb0nwGyqTTME2xBWZvVGCnl5z+/wHxvIBBCe5pNZ66IM15pGXQ4cDcfqCuP2kA== + +"@pixi/filter-blur@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/filter-blur/-/filter-blur-7.2.4.tgz" + integrity sha512-aLyXIoxy14bTansCPtbY8x7Sdn2OrrqkF/pcKiRXHJGGhi7wPacvB/NcmYJdnI/n2ExQ6V5Njuj/nfrsejVwcA== + +"@pixi/filter-color-matrix@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/filter-color-matrix/-/filter-color-matrix-7.2.4.tgz" + integrity sha512-DFtayybYXoUh73eHUFRK5REbi1t3FZuVUnaQTj+euHKF9L7EaYc3Q9wctpx1WPRcwkqEX50M4SNFhxpA7Pxtaw== + +"@pixi/filter-displacement@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/filter-displacement/-/filter-displacement-7.2.4.tgz" + integrity sha512-Simq3IBJKt7+Gvk4kK7OFkfoeYUMhNhIyATCdeT+Jkdkq5WV7pYnH5hqO0YW7eAHrgjV13yn6t4H/GC4+6LhEA== + +"@pixi/filter-fxaa@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/filter-fxaa/-/filter-fxaa-7.2.4.tgz" + integrity sha512-qzKjdL+Ih18uGTJLg8tT/H+YCsTeGkw2uF7lyKnw/lxGLJQhLWIhM95M9qSNgxbXyW1vp7SbG81a9aAEz2HAhA== + +"@pixi/filter-noise@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/filter-noise/-/filter-noise-7.2.4.tgz" + integrity sha512-QAU9Ybj2ZQrWM9ZEjTTC0iLnQcuyNoZNRinxSbg1G0yacpmsSb9wvV5ltIZ66+hfY+90+u2Nudt/v9g6pvOdGg== + +"@pixi/filter-outline@^5.2.0": + version "5.2.0" + resolved "https://registry.npmmirror.com/@pixi/filter-outline/-/filter-outline-5.2.0.tgz" + integrity sha512-xKfAouhZNKl6A0RvxT5i+2/ean7r16dE/QswwIkbWvr2hhHlp4p9U6XsqdgUERCDxK+IZibMAumbWs4DGxOUeQ== + +"@pixi/graphics-extras@^7.2.4": + version "7.2.4" + resolved "https://registry.yarnpkg.com/@pixi/graphics-extras/-/graphics-extras-7.2.4.tgz#72ac967992f239d3671d6e680ac891471619fe07" + integrity sha512-0yT91yqF3KLiZI/iLRcfcYlTVpkVyWsfGtWEIorZs0eX+/zYx7um7EJ2h7tFORI/1FxA2maR4td5vpgCwOLJAQ== + +"@pixi/graphics@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/graphics/-/graphics-7.2.4.tgz" + integrity sha512-3A2EumTjWJgXlDLOyuBrl9b6v1Za/E+/IjOGUIX843HH4NYaf1a2sfDfljx6r3oiDvy+VhuBFmgynRcV5IyA0Q== + +"@pixi/math@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/math/-/math-7.2.4.tgz" + integrity sha512-LJB+mozyEPllxa0EssFZrKNfVwysfaBun4b2dJKQQInp0DafgbA0j7A+WVg0oe51KhFULTJMpDqbLn/ITFc41A== + +"@pixi/mesh-extras@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/mesh-extras/-/mesh-extras-7.2.4.tgz" + integrity sha512-Lxqq/1E2EmDgjZX8KzjhBy3VvITIQ00arr2ikyHYF1d0XtQTKEYpr8VKzhchqZ5/9DuyTDbDMYGhcxoNXQmZrQ== + +"@pixi/mesh@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/mesh/-/mesh-7.2.4.tgz" + integrity sha512-wiALIqcRKib2BqeH9kOA5fOKWN352nqAspgbDa8gA7OyWzmNwqIedIlElixd0oLFOrIN5jOZAdzeKnoYQlt9Aw== + +"@pixi/mixin-cache-as-bitmap@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-7.2.4.tgz" + integrity sha512-95L/9nzfLHw6GoeqqRl/RjSloKvRt0xrc2inCmjMZvMsFUEtHN2F8IWd1k5vcv0S+83NCreFkJg6nJm1m5AZqg== + +"@pixi/mixin-get-child-by-name@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-7.2.4.tgz" + integrity sha512-9g17KgSBEEhkinnKk4dqmxagzHOCPSTvGB6lOopBq4yyXmr/2WVv+QGjuzE0O+p80szQeBJjPBQxzrfBILaSRw== + +"@pixi/mixin-get-global-position@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/mixin-get-global-position/-/mixin-get-global-position-7.2.4.tgz" + integrity sha512-UrAUF2BXCeWtFgR2m+er41Ky7zShT7r228cZkB6ZfYwMeThhwqG5mH68UeCyP6p68JMpT1gjI2DPfeSRY3ecnA== + +"@pixi/particle-container@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/particle-container/-/particle-container-7.2.4.tgz" + integrity sha512-tpSzilZGFtAoi8XhzL0TecLPNRQAbY8nWV9XNGXJDw+nxXp18GCe8L6eEmnHLlAug67BRHl65DtrdvTknPX+4g== + +"@pixi/prepare@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/prepare/-/prepare-7.2.4.tgz" + integrity sha512-Yff5Sh4kTLdKc5VkkM44LW9gpj7Izw8ns3P1TzWxqeGjzPZ3folr/tQujGL+Qw+8A9VESp+hX9MSIHyw+jpyrg== + +"@pixi/runner@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/runner/-/runner-7.2.4.tgz" + integrity sha512-YtyqPk1LA+0guEFKSFx6t/YSvbEQwajFwi4Ft8iDhioa6VK2MmTir1GjWwy7JQYLcDmYSAcQjnmFtVTZohyYSw== + +"@pixi/settings@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/settings/-/settings-7.2.4.tgz" + integrity sha512-ZPKRar9EwibijGmH8EViu4Greq1I/O7V/xQx2rNqN23XA7g09Qo6yfaeQpufu5xl8+/lZrjuHtQSnuY7OgG1CA== + dependencies: + "@pixi/constants" "7.2.4" + "@types/css-font-loading-module" "^0.0.7" + ismobilejs "^1.1.0" + +"@pixi/sprite-animated@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/sprite-animated/-/sprite-animated-7.2.4.tgz" + integrity sha512-9eRriPSC0QVS7U9zQlrG3uEI5+h3fi+mqofXy+yjk1sGCmXSIJME5p2wg2mzxoJk3qkSMagQA9QHtL26Fti8Iw== + +"@pixi/sprite-tiling@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/sprite-tiling/-/sprite-tiling-7.2.4.tgz" + integrity sha512-nGfxQoACRx49dUN0oW1vFm3141M+7gkAbzoNJym2Pljd2dpLME9fb5E6Lyahu0yWMaPRhhGorn6z9VIGmTF3Jw== + +"@pixi/sprite@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/sprite/-/sprite-7.2.4.tgz" + integrity sha512-DhR1B+/d0eXpxHIesJMXcVPrKFwQ+zRA1LvEIFfzewqfaRN3X6PMIuoKX8SIb6tl+Hq8Ba9Pe28zI7d2rmRzrA== + +"@pixi/spritesheet@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/spritesheet/-/spritesheet-7.2.4.tgz" + integrity sha512-LNmlavyiMQeCF0U4S+yhzxUYmPmat6EpLjLnkGukQTZV5CZkxDCVgXM9uKoRF2DvNydj4yuwZ6+JjK8QssHI8Q== + +"@pixi/text-bitmap@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/text-bitmap/-/text-bitmap-7.2.4.tgz" + integrity sha512-3u2CP4VN+muCaq/jtj7gn0hb3DET/X2S04zTBcgc2WVGufJc62yz+UDzS9jC+ellotVdt9c8U74++vpz3zJGfw== + +"@pixi/text-html@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/text-html/-/text-html-7.2.4.tgz" + integrity sha512-0NfLAE/w51ZtatxVqLvDS62iO0VLKsSdctqTAVv4Zlgdk9TKJmX1WUucHJboTvbm2SbDjNDGfZ6qXM5nAslIDQ== + +"@pixi/text@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/text/-/text-7.2.4.tgz" + integrity sha512-DGu7ktpe+zHhqR2sG9NsJt4mgvSObv5EqXTtUxD4Z0li1gmqF7uktpLyn5I6vSg1TTEL4TECClRDClVDGiykWw== + +"@pixi/ticker@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/ticker/-/ticker-7.2.4.tgz" + integrity sha512-hQQHIHvGeFsP4GNezZqjzuhUgNQEVgCH9+qU05UX1Mc5UHC9l6OJnY4VTVhhcHxZjA6RnyaY+1zBxCnoXuazpg== + dependencies: + "@pixi/extensions" "7.2.4" + "@pixi/settings" "7.2.4" + "@pixi/utils" "7.2.4" + +"@pixi/utils@7.2.4": + version "7.2.4" + resolved "https://registry.npmmirror.com/@pixi/utils/-/utils-7.2.4.tgz" + integrity sha512-VUGQHBOINIS4ePzoqafwxaGPVRTa3oM/mEutIIHbNGI3b+QvSO+1Dnk40M0zcH6Bo+MxQZbOZK5X/wO9oU5+LQ== + dependencies: + "@pixi/color" "7.2.4" + "@pixi/constants" "7.2.4" + "@pixi/settings" "7.2.4" + "@types/earcut" "^2.1.0" + earcut "^2.2.4" + eventemitter3 "^4.0.0" + url "^0.11.0" + +"@quasar/app-vite@^1.0.0": + version "1.4.3" + resolved "https://registry.npmmirror.com/@quasar/app-vite/-/app-vite-1.4.3.tgz" + integrity sha512-5iMs1sk6fyYTFoRVySwFXWL/PS23UEsdk+YSFejhXnSs5fVDmb2GQMguCHwDl3jPIHjZ7A+XKkb2iWx9pjiPXw== + dependencies: + "@quasar/render-ssr-error" "^1.0.1" + "@quasar/vite-plugin" "^1.3.3" + "@rollup/pluginutils" "^4.1.2" + "@types/chrome" "^0.0.208" + "@types/compression" "^1.7.2" + "@types/cordova" "0.0.34" + "@types/express" "^4.17.13" + "@vitejs/plugin-vue" "^2.2.0" + archiver "^5.3.0" + chokidar "^3.5.3" + ci-info "^3.7.1" + compression "^1.7.4" + cross-spawn "^7.0.3" + dot-prop "6.0.1" + elementtree "0.1.7" + esbuild "0.14.51" + express "^4.17.3" + fast-glob "3.2.12" + fs-extra "^11.1.0" + html-minifier "^4.0.0" + inquirer "^8.2.1" + isbinaryfile "^5.0.0" + kolorist "^1.5.1" + lodash "^4.17.21" + minimist "^1.2.6" + open "^8.4.0" + register-service-worker "^1.7.2" + rollup-plugin-visualizer "^5.5.4" + sass "1.32.12" + semver "^7.3.5" + serialize-javascript "^6.0.0" + table "^6.8.0" + vite "^2.9.13" + webpack-merge "^5.8.0" + +"@quasar/extras@^1.0.0": + version "1.16.4" + resolved "https://registry.npmmirror.com/@quasar/extras/-/extras-1.16.4.tgz" + integrity sha512-q2kPTNHI5aprgE2yQfRIf6aud+qSXH3YTNmhcfRp/rENh7kRjoM+b5BBPxgHlO1si1ARddbmr+Fxu/L05hfXnQ== + +"@quasar/render-ssr-error@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@quasar/render-ssr-error/-/render-ssr-error-1.0.1.tgz" + integrity sha512-4Shxl079hew/yZnIsDtWpRD8enOmqMjMu/s2bkGN0QBvlsRkpWv9pwOz5geJXZxBa17q1S4txvByBxkhPfhWaQ== + dependencies: + stack-trace "^1.0.0-pre2" + +"@quasar/vite-plugin@^1.3.3": + version "1.3.3" + resolved "https://registry.npmmirror.com/@quasar/vite-plugin/-/vite-plugin-1.3.3.tgz" + integrity sha512-HSX/Vgec5/Y8fiJRfpf1MR7+um+rdpbilktBGQkYOKw4A9d0smGq4jtSS/K4O2GTXRYqDmZ/5sgCeBcmhB3OCw== + +"@rollup/pluginutils@^4.1.2": + version "4.2.1" + resolved "https://registry.npmmirror.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz" + integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ== + dependencies: + estree-walker "^2.0.1" + picomatch "^2.2.2" + +"@stomp/stompjs@^7.0.0": + version "7.0.0" + resolved "https://registry.npmmirror.com/@stomp/stompjs/-/stompjs-7.0.0.tgz" + integrity sha512-fGdq4wPDnSV/KyOsjq4P+zLc8MFWC3lMmP5FBgLWKPJTYcuCbAIrnRGjB7q2jHZdYCOD5vxLuFoKIYLy5/u8Pw== + +"@types/body-parser@*": + version "1.19.2" + resolved "https://registry.npmmirror.com/@types/body-parser/-/body-parser-1.19.2.tgz" + integrity sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/chrome@^0.0.208": + version "0.0.208" + resolved "https://registry.npmmirror.com/@types/chrome/-/chrome-0.0.208.tgz" + integrity sha512-VDU/JnXkF5qaI7WBz14Azpa2VseZTgML0ia/g/B1sr9OfdOnHiH/zZ7P7qCDqxSlkqJh76/bPc8jLFcx8rHJmw== + dependencies: + "@types/filesystem" "*" + "@types/har-format" "*" + +"@types/compression@^1.7.2": + version "1.7.2" + resolved "https://registry.npmmirror.com/@types/compression/-/compression-1.7.2.tgz" + integrity sha512-lwEL4M/uAGWngWFLSG87ZDr2kLrbuR8p7X+QZB1OQlT+qkHsCPDVFnHPyXf4Vyl4yDDorNY+mAhosxkCvppatg== + dependencies: + "@types/express" "*" + +"@types/connect@*": + version "3.4.35" + resolved "https://registry.npmmirror.com/@types/connect/-/connect-3.4.35.tgz" + integrity sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ== + dependencies: + "@types/node" "*" + +"@types/cordova@0.0.34": + version "0.0.34" + resolved "https://registry.npmmirror.com/@types/cordova/-/cordova-0.0.34.tgz" + integrity sha512-rkiiTuf/z2wTd4RxFOb+clE7PF4AEJU0hsczbUdkHHBtkUmpWQpEddynNfJYKYtZFJKbq4F+brfekt1kx85IZA== + +"@types/css-font-loading-module@^0.0.7": + version "0.0.7" + resolved "https://registry.npmmirror.com/@types/css-font-loading-module/-/css-font-loading-module-0.0.7.tgz" + integrity sha512-nl09VhutdjINdWyXxHWN/w9zlNCfr60JUqJbd24YXUuCwgeL0TpFSdElCwb6cxfB6ybE19Gjj4g0jsgkXxKv1Q== + +"@types/earcut@^2.1.0": + version "2.1.1" + resolved "https://registry.npmmirror.com/@types/earcut/-/earcut-2.1.1.tgz" + integrity sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ== + +"@types/express-serve-static-core@^4.17.33": + version "4.17.35" + resolved "https://registry.npmmirror.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.35.tgz" + integrity sha512-wALWQwrgiB2AWTT91CB62b6Yt0sNHpznUXeZEcnPU3DRdlDIz74x8Qg1UUYKSVFi+va5vKOLYRBI1bRKiLLKIg== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@*", "@types/express@^4.17.13": + version "4.17.17" + resolved "https://registry.npmmirror.com/@types/express/-/express-4.17.17.tgz" + integrity sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^4.17.33" + "@types/qs" "*" + "@types/serve-static" "*" + +"@types/filesystem@*": + version "0.0.32" + resolved "https://registry.npmmirror.com/@types/filesystem/-/filesystem-0.0.32.tgz" + integrity sha512-Yuf4jR5YYMR2DVgwuCiP11s0xuVRyPKmz8vo6HBY3CGdeMj8af93CFZX+T82+VD1+UqHOxTq31lO7MI7lepBtQ== + dependencies: + "@types/filewriter" "*" + +"@types/filewriter@*": + version "0.0.29" + resolved "https://registry.npmmirror.com/@types/filewriter/-/filewriter-0.0.29.tgz" + integrity sha512-BsPXH/irW0ht0Ji6iw/jJaK8Lj3FJemon2gvEqHKpCdDCeemHa+rI3WBGq5z7cDMZgoLjY40oninGxqk+8NzNQ== + +"@types/google-protobuf@^3.15.6": + version "3.15.6" + resolved "https://registry.npmmirror.com/@types/google-protobuf/-/google-protobuf-3.15.6.tgz" + integrity sha512-pYVNNJ+winC4aek+lZp93sIKxnXt5qMkuKmaqS3WGuTq0Bw1ZDYNBgzG5kkdtwcv+GmYJGo3yEg6z2cKKAiEdw== + +"@types/har-format@*": + version "1.2.10" + resolved "https://registry.npmmirror.com/@types/har-format/-/har-format-1.2.10.tgz" + integrity sha512-o0J30wqycjF5miWDKYKKzzOU1ZTLuA42HZ4HE7/zqTOc/jTLdQ5NhYWvsRQo45Nfi1KHoRdNhteSI4BAxTF1Pg== + +"@types/json-schema@^7.0.9": + version "7.0.12" + resolved "https://registry.npmmirror.com/@types/json-schema/-/json-schema-7.0.12.tgz" + integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== + +"@types/mime@*": + version "3.0.1" + resolved "https://registry.npmmirror.com/@types/mime/-/mime-3.0.1.tgz" + integrity sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA== + +"@types/mime@^1": + version "1.3.2" + resolved "https://registry.npmmirror.com/@types/mime/-/mime-1.3.2.tgz" + integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== + +"@types/node@*": + version "20.2.5" + resolved "https://registry.npmmirror.com/@types/node/-/node-20.2.5.tgz" + integrity sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ== + +"@types/node@^12.20.21": + version "12.20.55" + resolved "https://registry.npmmirror.com/@types/node/-/node-12.20.55.tgz" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/offscreencanvas@^2019.6.4": + version "2019.7.0" + resolved "https://registry.npmmirror.com/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz" + integrity sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg== + +"@types/qs@*": + version "6.9.7" + resolved "https://registry.npmmirror.com/@types/qs/-/qs-6.9.7.tgz" + integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== + +"@types/range-parser@*": + version "1.2.4" + resolved "https://registry.npmmirror.com/@types/range-parser/-/range-parser-1.2.4.tgz" + integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== + +"@types/semver@^7.3.12": + version "7.5.0" + resolved "https://registry.npmmirror.com/@types/semver/-/semver-7.5.0.tgz" + integrity sha512-G8hZ6XJiHnuhQKR7ZmysCeJWE08o8T0AXtk5darsCaTVsYZhhgUrq53jizaR2FvsoeCwJhlmwTjkXBY5Pn/ZHw== + +"@types/send@*": + version "0.17.1" + resolved "https://registry.npmmirror.com/@types/send/-/send-0.17.1.tgz" + integrity sha512-Cwo8LE/0rnvX7kIIa3QHCkcuF21c05Ayb0ZfxPiv0W8VRiZiNW/WuRupHKpqqGVGf7SUA44QSOUKaEd9lIrd/Q== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.1" + resolved "https://registry.npmmirror.com/@types/serve-static/-/serve-static-1.15.1.tgz" + integrity sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ== + dependencies: + "@types/mime" "*" + "@types/node" "*" + +"@typescript-eslint/eslint-plugin@^5.10.0": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.8.tgz" + integrity sha512-JDMOmhXteJ4WVKOiHXGCoB96ADWg9q7efPWHRViT/f09bA8XOMLAVHHju3l0MkZnG1izaWXYmgvQcUjTRcpShQ== + dependencies: + "@eslint-community/regexpp" "^4.4.0" + "@typescript-eslint/scope-manager" "5.59.8" + "@typescript-eslint/type-utils" "5.59.8" + "@typescript-eslint/utils" "5.59.8" + debug "^4.3.4" + grapheme-splitter "^1.0.4" + ignore "^5.2.0" + natural-compare-lite "^1.4.0" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/parser@^5.10.0": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/parser/-/parser-5.59.8.tgz" + integrity sha512-AnR19RjJcpjoeGojmwZtCwBX/RidqDZtzcbG3xHrmz0aHHoOcbWnpDllenRDmDvsV0RQ6+tbb09/kyc+UT9Orw== + dependencies: + "@typescript-eslint/scope-manager" "5.59.8" + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/typescript-estree" "5.59.8" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@5.59.8": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/scope-manager/-/scope-manager-5.59.8.tgz" + integrity sha512-/w08ndCYI8gxGf+9zKf1vtx/16y8MHrZs5/tnjHhMLNSixuNcJavSX4wAiPf4aS5x41Es9YPCn44MIe4cxIlig== + dependencies: + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/visitor-keys" "5.59.8" + +"@typescript-eslint/type-utils@5.59.8": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/type-utils/-/type-utils-5.59.8.tgz" + integrity sha512-+5M518uEIHFBy3FnyqZUF3BMP+AXnYn4oyH8RF012+e7/msMY98FhGL5SrN29NQ9xDgvqCgYnsOiKp1VjZ/fpA== + dependencies: + "@typescript-eslint/typescript-estree" "5.59.8" + "@typescript-eslint/utils" "5.59.8" + debug "^4.3.4" + tsutils "^3.21.0" + +"@typescript-eslint/types@5.59.8": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/types/-/types-5.59.8.tgz" + integrity sha512-+uWuOhBTj/L6awoWIg0BlWy0u9TyFpCHrAuQ5bNfxDaZ1Ppb3mx6tUigc74LHcbHpOHuOTOJrBoAnhdHdaea1w== + +"@typescript-eslint/typescript-estree@5.59.8": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.59.8.tgz" + integrity sha512-Jy/lPSDJGNow14vYu6IrW790p7HIf/SOV1Bb6lZ7NUkLc2iB2Z9elESmsaUtLw8kVqogSbtLH9tut5GCX1RLDg== + dependencies: + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/visitor-keys" "5.59.8" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.59.8": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/utils/-/utils-5.59.8.tgz" + integrity sha512-Tr65630KysnNn9f9G7ROF3w1b5/7f6QVCJ+WK9nhIocWmx9F+TmCAcglF26Vm7z8KCTwoKcNEBZrhlklla3CKg== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.59.8" + "@typescript-eslint/types" "5.59.8" + "@typescript-eslint/typescript-estree" "5.59.8" + eslint-scope "^5.1.1" + semver "^7.3.7" + +"@typescript-eslint/visitor-keys@5.59.8": + version "5.59.8" + resolved "https://registry.npmmirror.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.59.8.tgz" + integrity sha512-pJhi2ms0x0xgloT7xYabil3SGGlojNNKjK/q6dB3Ey0uJLMjK2UDGJvHieiyJVW/7C3KI+Z4Q3pEHkm4ejA+xQ== + dependencies: + "@typescript-eslint/types" "5.59.8" + eslint-visitor-keys "^3.3.0" + +"@vitejs/plugin-vue@^2.2.0": + version "2.3.4" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-2.3.4.tgz" + integrity sha512-IfFNbtkbIm36O9KB8QodlwwYvTEsJb4Lll4c2IwB3VHc2gie2mSPtSzL0eYay7X2jd/2WX02FjSGTWR6OPr/zg== + +"@vue/compiler-core@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.3.4.tgz" + integrity sha512-cquyDNvZ6jTbf/+x+AgM2Arrp6G4Dzbb0R64jiG804HRMfRiFXWI6kqUVqZ6ZR0bQhIoQjB4+2bhNtVwndW15g== + dependencies: + "@babel/parser" "^7.21.3" + "@vue/shared" "3.3.4" + estree-walker "^2.0.2" + source-map-js "^1.0.2" + +"@vue/compiler-dom@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.3.4.tgz" + integrity sha512-wyM+OjOVpuUukIq6p5+nwHYtj9cFroz9cwkfmP9O1nzH68BenTTv0u7/ndggT8cIQlnBeOo6sUT/gvHcIkLA5w== + dependencies: + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" + +"@vue/compiler-sfc@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.3.4.tgz" + integrity sha512-6y/d8uw+5TkCuzBkgLS0v3lSM3hJDntFEiUORM11pQ/hKvkhSKZrXW6i69UyXlJQisJxuUEJKAWEqWbWsLeNKQ== + dependencies: + "@babel/parser" "^7.20.15" + "@vue/compiler-core" "3.3.4" + "@vue/compiler-dom" "3.3.4" + "@vue/compiler-ssr" "3.3.4" + "@vue/reactivity-transform" "3.3.4" + "@vue/shared" "3.3.4" + estree-walker "^2.0.2" + magic-string "^0.30.0" + postcss "^8.1.10" + source-map-js "^1.0.2" + +"@vue/compiler-ssr@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.3.4.tgz" + integrity sha512-m0v6oKpup2nMSehwA6Uuu+j+wEwcy7QmwMkVNVfrV9P2qE5KshC6RwOCq8fjGS/Eak/uNb8AaWekfiXxbBB6gQ== + dependencies: + "@vue/compiler-dom" "3.3.4" + "@vue/shared" "3.3.4" + +"@vue/devtools-api@^6.5.0": + version "6.5.0" + resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz" + integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q== + +"@vue/reactivity-transform@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/reactivity-transform/-/reactivity-transform-3.3.4.tgz" + integrity sha512-MXgwjako4nu5WFLAjpBnCj/ieqcjE2aJBINUNQzkZQfzIZA4xn+0fV1tIYBJvvva3N3OvKGofRLvQIwEQPpaXw== + dependencies: + "@babel/parser" "^7.20.15" + "@vue/compiler-core" "3.3.4" + "@vue/shared" "3.3.4" + estree-walker "^2.0.2" + magic-string "^0.30.0" + +"@vue/reactivity@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.3.4.tgz" + integrity sha512-kLTDLwd0B1jG08NBF3R5rqULtv/f8x3rOFByTDz4J53ttIQEDmALqKqXY0J+XQeN0aV2FBxY8nJDf88yvOPAqQ== + dependencies: + "@vue/shared" "3.3.4" + +"@vue/runtime-core@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.3.4.tgz" + integrity sha512-R+bqxMN6pWO7zGI4OMlmvePOdP2c93GsHFM/siJI7O2nxFRzj55pLwkpCedEY+bTMgp5miZ8CxfIZo3S+gFqvA== + dependencies: + "@vue/reactivity" "3.3.4" + "@vue/shared" "3.3.4" + +"@vue/runtime-dom@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.3.4.tgz" + integrity sha512-Aj5bTJ3u5sFsUckRghsNjVTtxZQ1OyMWCr5dZRAPijF/0Vy4xEoRCwLyHXcj4D0UFbJ4lbx3gPTgg06K/GnPnQ== + dependencies: + "@vue/runtime-core" "3.3.4" + "@vue/shared" "3.3.4" + csstype "^3.1.1" + +"@vue/server-renderer@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.3.4.tgz" + integrity sha512-Q6jDDzR23ViIb67v+vM1Dqntu+HUexQcsWKhhQa4ARVzxOY2HbC7QRW/ggkDBd5BU+uM1sV6XOAP0b216o34JQ== + dependencies: + "@vue/compiler-ssr" "3.3.4" + "@vue/shared" "3.3.4" + +"@vue/shared@3.3.4": + version "3.3.4" + resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.3.4.tgz" + integrity sha512-7OjdcV8vQ74eiz1TZLzZP4JwqM5fA94K6yntPS5Z25r9HDuGNzaGdgvwKYq6S+MxwF0TFRwe50fIR/MYnakdkQ== + +accepts@~1.3.5, accepts@~1.3.8: + version "1.3.8" + resolved "https://registry.npmmirror.com/accepts/-/accepts-1.3.8.tgz" + integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== + dependencies: + mime-types "~2.1.34" + negotiator "0.6.3" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmmirror.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.8.0: + version "8.8.2" + resolved "https://registry.npmmirror.com/acorn/-/acorn-8.8.2.tgz" + integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== + +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ajv@^8.0.1: + version "8.12.0" + resolved "https://registry.npmmirror.com/ajv/-/ajv-8.12.0.tgz" + integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.npmmirror.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/ansi-styles/-/ansi-styles-4.3.0.tgz" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +archiver-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/archiver-utils/-/archiver-utils-2.1.0.tgz" + integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== + dependencies: + glob "^7.1.4" + graceful-fs "^4.2.0" + lazystream "^1.0.0" + lodash.defaults "^4.2.0" + lodash.difference "^4.5.0" + lodash.flatten "^4.4.0" + lodash.isplainobject "^4.0.6" + lodash.union "^4.6.0" + normalize-path "^3.0.0" + readable-stream "^2.0.0" + +archiver@^5.3.0: + version "5.3.1" + resolved "https://registry.npmmirror.com/archiver/-/archiver-5.3.1.tgz" + integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== + dependencies: + archiver-utils "^2.1.0" + async "^3.2.3" + buffer-crc32 "^0.2.1" + readable-stream "^3.6.0" + readdir-glob "^1.0.0" + tar-stream "^2.2.0" + zip-stream "^4.1.0" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/array-flatten/-/array-flatten-1.1.1.tgz" + integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/array-union/-/array-union-2.1.0.tgz" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/astral-regex/-/astral-regex-2.0.0.tgz" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^3.2.3: + version "3.2.4" + resolved "https://registry.npmmirror.com/async/-/async-3.2.4.tgz" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +autoprefixer@^10.4.2: + version "10.4.14" + resolved "https://registry.npmmirror.com/autoprefixer/-/autoprefixer-10.4.14.tgz" + integrity sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ== + dependencies: + browserslist "^4.21.5" + caniuse-lite "^1.0.30001464" + fraction.js "^4.2.0" + normalize-range "^0.1.2" + picocolors "^1.0.0" + postcss-value-parser "^4.2.0" + +axios@^1.2.1: + version "1.4.0" + resolved "https://registry.npmmirror.com/axios/-/axios-1.4.0.tgz" + integrity sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA== + dependencies: + follow-redirects "^1.15.0" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.2.0.tgz" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bl@^4.0.3, bl@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/bl/-/bl-4.1.0.tgz" + integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== + dependencies: + buffer "^5.5.0" + inherits "^2.0.4" + readable-stream "^3.4.0" + +body-parser@1.20.1: + version "1.20.1" + resolved "https://registry.npmmirror.com/body-parser/-/body-parser-1.20.1.tgz" + integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== + dependencies: + bytes "3.1.2" + content-type "~1.0.4" + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + http-errors "2.0.0" + iconv-lite "0.4.24" + on-finished "2.4.1" + qs "6.11.0" + raw-body "2.5.1" + type-is "~1.6.18" + unpipe "1.0.0" + +boolbase@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz" + integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/braces/-/braces-3.0.2.tgz" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browserslist@^4.21.5: + version "4.21.7" + resolved "https://registry.npmmirror.com/browserslist/-/browserslist-4.21.7.tgz" + integrity sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA== + dependencies: + caniuse-lite "^1.0.30001489" + electron-to-chromium "^1.4.411" + node-releases "^2.0.12" + update-browserslist-db "^1.0.11" + +buffer-crc32@^0.2.1, buffer-crc32@^0.2.13: + version "0.2.13" + resolved "https://registry.npmmirror.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer@^5.5.0: + version "5.7.1" + resolved "https://registry.npmmirror.com/buffer/-/buffer-5.7.1.tgz" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/bytes/-/bytes-3.0.0.tgz" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + +bytes@3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind@^1.0.0: + version "1.0.2" + resolved "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.2.tgz" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camel-case@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/camel-case/-/camel-case-3.0.0.tgz" + integrity sha512-+MbKztAYHXPr1jNTSKQF52VpcFjwY5RkR7fxksV8Doo4KAYc5Fl4UJRgthBbTmEx8C54DqahhbLJkDwjI3PI/w== + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +caniuse-lite@^1.0.30001464, caniuse-lite@^1.0.30001489: + version "1.0.30001489" + resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001489.tgz" + integrity sha512-x1mgZEXK8jHIfAxm+xgdpHpk50IN3z3q3zP261/WS+uvePxW8izXuCu6AHz0lkuYTlATDehiZ/tNyYBdSQsOUQ== + +chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: + version "4.1.2" + resolved "https://registry.npmmirror.com/chalk/-/chalk-4.1.2.tgz" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.npmmirror.com/chardet/-/chardet-0.7.0.tgz" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + +"chokidar@>=3.0.0 <4.0.0", chokidar@^3.5.3: + version "3.5.3" + resolved "https://registry.npmmirror.com/chokidar/-/chokidar-3.5.3.tgz" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +ci-info@^3.7.1: + version "3.8.0" + resolved "https://registry.npmmirror.com/ci-info/-/ci-info-3.8.0.tgz" + integrity sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw== + +clean-css@^4.2.1: + version "4.2.4" + resolved "https://registry.npmmirror.com/clean-css/-/clean-css-4.2.4.tgz" + integrity sha512-EJUDT7nDVFDvaQgAo2G/PJvxmp1o/c6iXLbswsBbUFXi1Nr+AjA2cKmfbKDMjMvzEe75g3P6JkaDDAKk96A85A== + dependencies: + source-map "~0.6.0" + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/cli-cursor/-/cli-cursor-3.1.0.tgz" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-spinners@^2.5.0: + version "2.9.0" + resolved "https://registry.npmmirror.com/cli-spinners/-/cli-spinners-2.9.0.tgz" + integrity sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g== + +cli-width@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/cli-width/-/cli-width-3.0.0.tgz" + integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.npmmirror.com/cliui/-/cliui-8.0.1.tgz" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +clone-deep@^4.0.1: + version "4.0.1" + resolved "https://registry.npmmirror.com/clone-deep/-/clone-deep-4.0.1.tgz" + integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== + dependencies: + is-plain-object "^2.0.4" + kind-of "^6.0.2" + shallow-clone "^3.0.0" + +clone@^1.0.2: + version "1.0.4" + resolved "https://registry.npmmirror.com/clone/-/clone-1.0.4.tgz" + integrity sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colord@^2.9.3: + version "2.9.3" + resolved "https://registry.npmmirror.com/colord/-/colord-2.9.3.tgz" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^2.19.0: + version "2.20.3" + resolved "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +compress-commons@^4.1.0: + version "4.1.1" + resolved "https://registry.npmmirror.com/compress-commons/-/compress-commons-4.1.1.tgz" + integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== + dependencies: + buffer-crc32 "^0.2.13" + crc32-stream "^4.0.2" + normalize-path "^3.0.0" + readable-stream "^3.6.0" + +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.npmmirror.com/compressible/-/compressible-2.0.18.tgz" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.npmmirror.com/compression/-/compression-1.7.4.tgz" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@0.5.4: + version "0.5.4" + resolved "https://registry.npmmirror.com/content-disposition/-/content-disposition-0.5.4.tgz" + integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== + dependencies: + safe-buffer "5.2.1" + +content-type@~1.0.4: + version "1.0.5" + resolved "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.npmmirror.com/crc-32/-/crc-32-1.2.2.tgz" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +crc32-stream@^4.0.2: + version "4.0.2" + resolved "https://registry.npmmirror.com/crc32-stream/-/crc32-stream-4.0.2.tgz" + integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== + dependencies: + crc-32 "^1.2.0" + readable-stream "^3.4.0" + +cross-spawn@^7.0.2, cross-spawn@^7.0.3: + version "7.0.3" + resolved "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/cssesc/-/cssesc-3.0.0.tgz" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +csstype@^3.1.1: + version "3.1.2" + resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.2.tgz" + integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== + +debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmmirror.com/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + +debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmmirror.com/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmmirror.com/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +defaults@^1.0.3: + version "1.0.4" + resolved "https://registry.npmmirror.com/defaults/-/defaults-1.0.4.tgz" + integrity sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A== + dependencies: + clone "^1.0.2" + +define-lazy-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz" + integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +destroy@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/destroy/-/destroy-1.2.0.tgz" + integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/dir-glob/-/dir-glob-3.0.1.tgz" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +dot-prop@6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/dot-prop/-/dot-prop-6.0.1.tgz" + integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== + dependencies: + is-obj "^2.0.0" + +earcut@^2.2.4: + version "2.2.4" + resolved "https://registry.npmmirror.com/earcut/-/earcut-2.2.4.tgz" + integrity sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ== + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +electron-to-chromium@^1.4.411: + version "1.4.413" + resolved "https://registry.npmmirror.com/electron-to-chromium/-/electron-to-chromium-1.4.413.tgz" + integrity sha512-Gd+/OAhRca06dkVxIQo/W7dr6Nmk9cx6lQdZ19GvFp51k5B/lUAokm6SJfNkdV8kFLsC3Z4sLTyEHWCnB1Efbw== + +elementtree@0.1.7: + version "0.1.7" + resolved "https://registry.npmmirror.com/elementtree/-/elementtree-0.1.7.tgz" + integrity sha512-wkgGT6kugeQk/P6VZ/f4T+4HB41BVgNBq5CDIZVbQ02nvTVqAiVTbskxxu3eA/X96lMlfYOwnLQpN2v5E1zDEg== + dependencies: + sax "1.1.4" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/encodeurl/-/encodeurl-1.0.2.tgz" + integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== + +end-of-stream@^1.4.1: + version "1.4.4" + resolved "https://registry.npmmirror.com/end-of-stream/-/end-of-stream-1.4.4.tgz" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +esbuild-android-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.51.tgz#414a087cb0de8db1e347ecca6c8320513de433db" + integrity sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ== + +esbuild-android-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-android-64/-/esbuild-android-64-0.14.54.tgz#505f41832884313bbaffb27704b8bcaa2d8616be" + integrity sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ== + +esbuild-android-arm64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.51.tgz#55de3bce2aab72bcd2b606da4318ad00fb9c8151" + integrity sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A== + +esbuild-android-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.54.tgz#8ce69d7caba49646e009968fe5754a21a9871771" + integrity sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg== + +esbuild-darwin-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.51.tgz#4259f23ed6b4cea2ec8a28d87b7fb9801f093754" + integrity sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA== + +esbuild-darwin-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.54.tgz#24ba67b9a8cb890a3c08d9018f887cc221cdda25" + integrity sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug== + +esbuild-darwin-arm64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.51.tgz#d77b4366a71d84e530ba019d540b538b295d494a" + integrity sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow== + +esbuild-darwin-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.54.tgz#3f7cdb78888ee05e488d250a2bdaab1fa671bf73" + integrity sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw== + +esbuild-freebsd-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.51.tgz#27b6587b3639f10519c65e07219d249b01f2ad38" + integrity sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g== + +esbuild-freebsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.54.tgz#09250f997a56ed4650f3e1979c905ffc40bbe94d" + integrity sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg== + +esbuild-freebsd-arm64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.51.tgz#63c435917e566808c71fafddc600aca4d78be1ec" + integrity sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg== + +esbuild-freebsd-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.54.tgz#bafb46ed04fc5f97cbdb016d86947a79579f8e48" + integrity sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q== + +esbuild-linux-32@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.14.51.tgz#c3da774143a37e7f11559b9369d98f11f997a5d9" + integrity sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w== + +esbuild-linux-32@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-32/-/esbuild-linux-32-0.14.54.tgz#e2a8c4a8efdc355405325033fcebeb941f781fe5" + integrity sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw== + +esbuild-linux-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.14.51.tgz" + integrity sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA== + +esbuild-linux-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-64/-/esbuild-linux-64-0.14.54.tgz" + integrity sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg== + +esbuild-linux-arm64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.51.tgz#dac84740516e859d8b14e1ecc478dd5241b10c93" + integrity sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw== + +esbuild-linux-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.54.tgz#dae4cd42ae9787468b6a5c158da4c84e83b0ce8b" + integrity sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig== + +esbuild-linux-arm@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.51.tgz#b3ae7000696cd53ed95b2b458554ff543a60e106" + integrity sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg== + +esbuild-linux-arm@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.54.tgz#a2c1dff6d0f21dbe8fc6998a122675533ddfcd59" + integrity sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw== + +esbuild-linux-mips64le@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.51.tgz#dad10770fac94efa092b5a0643821c955a9dd385" + integrity sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A== + +esbuild-linux-mips64le@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.54.tgz#d9918e9e4cb972f8d6dae8e8655bf9ee131eda34" + integrity sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw== + +esbuild-linux-ppc64le@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.51.tgz#b68c2f8294d012a16a88073d67e976edd4850ae0" + integrity sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ== + +esbuild-linux-ppc64le@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.54.tgz#3f9a0f6d41073fb1a640680845c7de52995f137e" + integrity sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ== + +esbuild-linux-riscv64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.51.tgz#608a318b8697123e44c1e185cdf6708e3df50b93" + integrity sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA== + +esbuild-linux-riscv64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.54.tgz#618853c028178a61837bc799d2013d4695e451c8" + integrity sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg== + +esbuild-linux-s390x@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.51.tgz#c9e7791170a3295dba79b93aa452beb9838a8625" + integrity sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw== + +esbuild-linux-s390x@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.54.tgz#d1885c4c5a76bbb5a0fe182e2c8c60eb9e29f2a6" + integrity sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA== + +esbuild-netbsd-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.51.tgz#0abd40b8c2e37fda6f5cc41a04cb2b690823d891" + integrity sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A== + +esbuild-netbsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.54.tgz#69ae917a2ff241b7df1dbf22baf04bd330349e81" + integrity sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w== + +esbuild-openbsd-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.51.tgz#4adba0b7ea7eb1428bb00d8e94c199a949b130e8" + integrity sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA== + +esbuild-openbsd-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.54.tgz#db4c8495287a350a6790de22edea247a57c5d47b" + integrity sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw== + +esbuild-sunos-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.51.tgz#4b8a6d97dfedda30a6e39607393c5c90ebf63891" + integrity sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA== + +esbuild-sunos-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.54.tgz#54287ee3da73d3844b721c21bc80c1dc7e1bf7da" + integrity sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw== + +esbuild-windows-32@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.14.51.tgz#d31d8ca0c1d314fb1edea163685a423b62e9ac17" + integrity sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg== + +esbuild-windows-32@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-windows-32/-/esbuild-windows-32-0.14.54.tgz#f8aaf9a5667630b40f0fb3aa37bf01bbd340ce31" + integrity sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w== + +esbuild-windows-64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz#7d3c09c8652d222925625637bdc7e6c223e0085d" + integrity sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA== + +esbuild-windows-64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-windows-64/-/esbuild-windows-64-0.14.54.tgz#bf54b51bd3e9b0f1886ffdb224a4176031ea0af4" + integrity sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ== + +esbuild-windows-arm64@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.51.tgz#0220d2304bfdc11bc27e19b2aaf56edf183e4ae9" + integrity sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g== + +esbuild-windows-arm64@0.14.54: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.54.tgz#937d15675a15e4b0e4fafdbaa3a01a776a2be982" + integrity sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg== + +esbuild@0.14.51: + version "0.14.51" + resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.51.tgz" + integrity sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw== + optionalDependencies: + esbuild-android-64 "0.14.51" + esbuild-android-arm64 "0.14.51" + esbuild-darwin-64 "0.14.51" + esbuild-darwin-arm64 "0.14.51" + esbuild-freebsd-64 "0.14.51" + esbuild-freebsd-arm64 "0.14.51" + esbuild-linux-32 "0.14.51" + esbuild-linux-64 "0.14.51" + esbuild-linux-arm "0.14.51" + esbuild-linux-arm64 "0.14.51" + esbuild-linux-mips64le "0.14.51" + esbuild-linux-ppc64le "0.14.51" + esbuild-linux-riscv64 "0.14.51" + esbuild-linux-s390x "0.14.51" + esbuild-netbsd-64 "0.14.51" + esbuild-openbsd-64 "0.14.51" + esbuild-sunos-64 "0.14.51" + esbuild-windows-32 "0.14.51" + esbuild-windows-64 "0.14.51" + esbuild-windows-arm64 "0.14.51" + +esbuild@^0.14.27: + version "0.14.54" + resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.14.54.tgz" + integrity sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA== + optionalDependencies: + "@esbuild/linux-loong64" "0.14.54" + esbuild-android-64 "0.14.54" + esbuild-android-arm64 "0.14.54" + esbuild-darwin-64 "0.14.54" + esbuild-darwin-arm64 "0.14.54" + esbuild-freebsd-64 "0.14.54" + esbuild-freebsd-arm64 "0.14.54" + esbuild-linux-32 "0.14.54" + esbuild-linux-64 "0.14.54" + esbuild-linux-arm "0.14.54" + esbuild-linux-arm64 "0.14.54" + esbuild-linux-mips64le "0.14.54" + esbuild-linux-ppc64le "0.14.54" + esbuild-linux-riscv64 "0.14.54" + esbuild-linux-s390x "0.14.54" + esbuild-netbsd-64 "0.14.54" + esbuild-openbsd-64 "0.14.54" + esbuild-sunos-64 "0.14.54" + esbuild-windows-32 "0.14.54" + esbuild-windows-64 "0.14.54" + esbuild-windows-arm64 "0.14.54" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/escalade/-/escalade-3.1.1.tgz" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-config-prettier@^8.1.0: + version "8.8.0" + resolved "https://registry.npmmirror.com/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz" + integrity sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA== + +eslint-plugin-vue@^9.0.0: + version "9.14.1" + resolved "https://registry.npmmirror.com/eslint-plugin-vue/-/eslint-plugin-vue-9.14.1.tgz" + integrity sha512-LQazDB1qkNEKejLe/b5a9VfEbtbczcOaui5lQ4Qw0tbRBbQYREyxxOV5BQgNDTqGPs9pxqiEpbMi9ywuIaF7vw== + dependencies: + "@eslint-community/eslint-utils" "^4.3.0" + natural-compare "^1.4.0" + nth-check "^2.0.1" + postcss-selector-parser "^6.0.9" + semver "^7.3.5" + vue-eslint-parser "^9.3.0" + xml-name-validator "^4.0.0" + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-5.1.1.tgz" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + +eslint-scope@^7.1.1, eslint-scope@^7.2.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/eslint-scope/-/eslint-scope-7.2.0.tgz" + integrity sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1: + version "3.4.1" + resolved "https://registry.npmmirror.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.1.tgz" + integrity sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA== + +eslint@^8.10.0: + version "8.41.0" + resolved "https://registry.npmmirror.com/eslint/-/eslint-8.41.0.tgz" + integrity sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.4.0" + "@eslint/eslintrc" "^2.0.3" + "@eslint/js" "8.41.0" + "@humanwhocodes/config-array" "^0.11.8" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.0" + eslint-visitor-keys "^3.4.1" + espree "^9.5.2" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + +espree@^9.3.1, espree@^9.5.2: + version "9.5.2" + resolved "https://registry.npmmirror.com/espree/-/espree-9.5.2.tgz" + integrity sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw== + dependencies: + acorn "^8.8.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.0, esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.npmmirror.com/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmmirror.com/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.npmmirror.com/estraverse/-/estraverse-4.3.0.tgz" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.npmmirror.com/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^2.0.1, estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmmirror.com/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@~1.8.1: + version "1.8.1" + resolved "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventemitter3@^4.0.0: + version "4.0.7" + resolved "https://registry.npmmirror.com/eventemitter3/-/eventemitter3-4.0.7.tgz" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +express@^4.17.3: + version "4.18.2" + resolved "https://registry.npmmirror.com/express/-/express-4.18.2.tgz" + integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== + dependencies: + accepts "~1.3.8" + array-flatten "1.1.1" + body-parser "1.20.1" + content-disposition "0.5.4" + content-type "~1.0.4" + cookie "0.5.0" + cookie-signature "1.0.6" + debug "2.6.9" + depd "2.0.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + finalhandler "1.2.0" + fresh "0.5.2" + http-errors "2.0.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "2.4.1" + parseurl "~1.3.3" + path-to-regexp "0.1.7" + proxy-addr "~2.0.7" + qs "6.11.0" + range-parser "~1.2.1" + safe-buffer "5.2.1" + send "0.18.0" + serve-static "1.15.0" + setprototypeof "1.2.0" + statuses "2.0.1" + type-is "~1.6.18" + utils-merge "1.0.1" + vary "~1.1.2" + +external-editor@^3.0.3: + version "3.1.0" + resolved "https://registry.npmmirror.com/external-editor/-/external-editor-3.1.0.tgz" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@3.2.12, fast-glob@^3.2.9: + version "3.2.12" + resolved "https://registry.npmmirror.com/fast-glob/-/fast-glob-3.2.12.tgz" + integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmmirror.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.15.0" + resolved "https://registry.npmmirror.com/fastq/-/fastq-1.15.0.tgz" + integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + dependencies: + reusify "^1.0.4" + +figures@^3.0.0: + version "3.2.0" + resolved "https://registry.npmmirror.com/figures/-/figures-3.2.0.tgz" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/fill-range/-/fill-range-7.0.1.tgz" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/finalhandler/-/finalhandler-1.2.0.tgz" + integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== + dependencies: + debug "2.6.9" + encodeurl "~1.0.2" + escape-html "~1.0.3" + on-finished "2.4.1" + parseurl "~1.3.3" + statuses "2.0.1" + unpipe "~1.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/find-up/-/find-up-5.0.0.tgz" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.npmmirror.com/flat-cache/-/flat-cache-3.0.4.tgz" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.7" + resolved "https://registry.npmmirror.com/flatted/-/flatted-3.2.7.tgz" + integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== + +follow-redirects@^1.15.0: + version "1.15.2" + resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.2.tgz" + integrity sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA== + +form-data@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fraction.js@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/fraction.js/-/fraction.js-4.2.0.tgz" + integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== + +fresh@0.5.2: + version "0.5.2" + resolved "https://registry.npmmirror.com/fresh/-/fresh-0.5.2.tgz" + integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== + +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs-constants/-/fs-constants-1.0.0.tgz" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-extra@^11.1.0: + version "11.1.1" + resolved "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.1.1.tgz" + integrity sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.2" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== + +function-bind@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.1.tgz" + integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.npmmirror.com/get-caller-file/-/get-caller-file-2.0.5.tgz" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.0.2: + version "1.2.1" + resolved "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.2.1.tgz" + integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-proto "^1.0.1" + has-symbols "^1.0.3" + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmmirror.com/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.20.0" + resolved "https://registry.npmmirror.com/globals/-/globals-13.20.0.tgz" + integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== + dependencies: + type-fest "^0.20.2" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmmirror.com/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +google-protobuf@^3.21.2: + version "3.21.2" + resolved "https://registry.npmmirror.com/google-protobuf/-/google-protobuf-3.21.2.tgz" + integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.11" + resolved "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +grapheme-splitter@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz" + integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/graphemer/-/graphemer-1.4.0.tgz" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/has-flag/-/has-flag-4.0.0.tgz" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/has-proto/-/has-proto-1.0.1.tgz" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/has/-/has-1.0.3.tgz" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/he/-/he-1.2.0.tgz" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +html-minifier@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/html-minifier/-/html-minifier-4.0.0.tgz" + integrity sha512-aoGxanpFPLg7MkIl/DDFYtb0iWz7jMFGqFhvEDZga6/4QTjneiD8I/NXL1x5aaoCp7FSIT6h/OhykDdPsbtMig== + dependencies: + camel-case "^3.0.0" + clean-css "^4.2.1" + commander "^2.19.0" + he "^1.2.0" + param-case "^2.1.1" + relateurl "^0.2.7" + uglify-js "^3.5.1" + +http-errors@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.0.tgz" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +iconv-lite@0.4.24, iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.4.24.tgz" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +ignore@^5.2.0: + version "5.2.4" + resolved "https://registry.npmmirror.com/ignore/-/ignore-5.2.4.tgz" + integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmmirror.com/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmmirror.com/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: + version "2.0.4" + resolved "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inquirer@^8.2.1: + version "8.2.5" + resolved "https://registry.npmmirror.com/inquirer/-/inquirer-8.2.5.tgz" + integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ== + dependencies: + ansi-escapes "^4.2.1" + chalk "^4.1.1" + cli-cursor "^3.1.0" + cli-width "^3.0.0" + external-editor "^3.0.3" + figures "^3.0.0" + lodash "^4.17.21" + mute-stream "0.0.8" + ora "^5.4.1" + run-async "^2.4.0" + rxjs "^7.5.5" + string-width "^4.1.0" + strip-ansi "^6.0.0" + through "^2.3.6" + wrap-ansi "^7.0.0" + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-core-module@^2.11.0: + version "2.12.1" + resolved "https://registry.npmmirror.com/is-core-module/-/is-core-module-2.12.1.tgz" + integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== + dependencies: + has "^1.0.3" + +is-docker@^2.0.0, is-docker@^2.1.1: + version "2.2.1" + resolved "https://registry.npmmirror.com/is-docker/-/is-docker-2.2.1.tgz" + integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-interactive@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/is-interactive/-/is-interactive-1.0.0.tgz" + integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-obj@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/is-obj/-/is-obj-2.0.0.tgz" + integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmmirror.com/is-path-inside/-/is-path-inside-3.0.3.tgz" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-plain-object@^2.0.4: + version "2.0.4" + resolved "https://registry.npmmirror.com/is-plain-object/-/is-plain-object-2.0.4.tgz" + integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== + dependencies: + isobject "^3.0.1" + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +is-wsl@^2.2.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/is-wsl/-/is-wsl-2.2.0.tgz" + integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== + dependencies: + is-docker "^2.0.0" + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isbinaryfile@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/isbinaryfile/-/isbinaryfile-5.0.0.tgz" + integrity sha512-UDdnyGvMajJUWCkib7Cei/dvyJrrvo4FIrsvSFWdPpXSUorzXrDJ0S+X5Q4ZlasfPjca4yqCNNsjbCeiy8FFeg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +ismobilejs@^1.1.0: + version "1.1.1" + resolved "https://registry.npmmirror.com/ismobilejs/-/ismobilejs-1.1.1.tgz" + integrity sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw== + +isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/isobject/-/isobject-3.0.1.tgz" + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== + +js-base64@^3.7.5: + version "3.7.5" + resolved "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.5.tgz" + integrity sha512-3MEt5DTINKqfScXKfJFrRbxkrnk2AxPWGBL/ycjz4dK8iqiSJ06UxD8jh8xuh6p10TX4t2+7FsBYVxxQbMg+qA== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.1.0.tgz" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +kind-of@^6.0.2: + version "6.0.3" + resolved "https://registry.npmmirror.com/kind-of/-/kind-of-6.0.3.tgz" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +kolorist@^1.5.1: + version "1.8.0" + resolved "https://registry.npmmirror.com/kolorist/-/kolorist-1.8.0.tgz" + integrity sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ== + +lazystream@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/lazystream/-/lazystream-1.0.1.tgz" + integrity sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw== + dependencies: + readable-stream "^2.0.5" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/locate-path/-/locate-path-6.0.0.tgz" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.defaults@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz" + integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== + +lodash.difference@^4.5.0: + version "4.5.0" + resolved "https://registry.npmmirror.com/lodash.difference/-/lodash.difference-4.5.0.tgz" + integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== + +lodash.flatten@^4.4.0: + version "4.4.0" + resolved "https://registry.npmmirror.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz" + integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== + +lodash.isplainobject@^4.0.6: + version "4.0.6" + resolved "https://registry.npmmirror.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" + integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmmirror.com/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.npmmirror.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash.union@^4.6.0: + version "4.6.0" + resolved "https://registry.npmmirror.com/lodash.union/-/lodash.union-4.6.0.tgz" + integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/log-symbols/-/log-symbols-4.1.0.tgz" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.npmmirror.com/lower-case/-/lower-case-1.1.4.tgz" + integrity sha512-2Fgx1Ycm599x+WGpIYwJOvsjmXFzTSc34IwDWALRA/8AopUKAVPwfJ+h5+f85BCp0PWmmJcWzEpxOpoXycMpdA== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.30.0: + version "0.30.0" + resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.0.tgz" + integrity sha512-LA+31JYDJLs82r2ScLrlz1GjSgu66ZV518eyWT+S8VhyQn/JL0u9MeBOvQMGYiPk1DBiSN9DDMOcXvigJZaViQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.13" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.npmmirror.com/media-typer/-/media-typer-0.3.0.tgz" + integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz" + integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmmirror.com/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/methods/-/methods-1.1.2.tgz" + integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmmirror.com/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": + version "1.52.0" + resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.24, mime-types@~2.1.34: + version "2.1.35" + resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mime@1.6.0: + version "1.6.0" + resolved "https://registry.npmmirror.com/mime/-/mime-1.6.0.tgz" + integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/mimic-fn/-/mimic-fn-2.1.0.tgz" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.1.0: + version "5.1.6" + resolved "https://registry.npmmirror.com/minimatch/-/minimatch-5.1.6.tgz" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.npmmirror.com/minimist/-/minimist-1.2.8.tgz" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/ms/-/ms-2.0.0.tgz" + integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mute-stream@0.0.8: + version "0.0.8" + resolved "https://registry.npmmirror.com/mute-stream/-/mute-stream-0.0.8.tgz" + integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== + +nanoid@^3.3.6: + version "3.3.6" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.6.tgz" + integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== + +natural-compare-lite@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz" + integrity sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +negotiator@0.6.3: + version "0.6.3" + resolved "https://registry.npmmirror.com/negotiator/-/negotiator-0.6.3.tgz" + integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== + +no-case@^2.2.0: + version "2.3.2" + resolved "https://registry.npmmirror.com/no-case/-/no-case-2.3.2.tgz" + integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ== + dependencies: + lower-case "^1.1.1" + +node-releases@^2.0.12: + version "2.0.12" + resolved "https://registry.npmmirror.com/node-releases/-/node-releases-2.0.12.tgz" + integrity sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.npmmirror.com/normalize-range/-/normalize-range-0.1.2.tgz" + integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== + +nth-check@^2.0.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/nth-check/-/nth-check-2.1.1.tgz" + integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w== + dependencies: + boolbase "^1.0.0" + +object-inspect@^1.9.0: + version "1.12.3" + resolved "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.12.3.tgz" + integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== + +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/on-headers/-/on-headers-1.0.2.tgz" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.npmmirror.com/once/-/once-1.4.0.tgz" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.npmmirror.com/onetime/-/onetime-5.1.2.tgz" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +open@^8.4.0: + version "8.4.2" + resolved "https://registry.npmmirror.com/open/-/open-8.4.2.tgz" + integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== + dependencies: + define-lazy-prop "^2.0.0" + is-docker "^2.1.1" + is-wsl "^2.2.0" + +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.npmmirror.com/optionator/-/optionator-0.9.1.tgz" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + +ora@^5.4.1: + version "5.4.1" + resolved "https://registry.npmmirror.com/ora/-/ora-5.4.1.tgz" + integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== + dependencies: + bl "^4.1.0" + chalk "^4.1.0" + cli-cursor "^3.1.0" + cli-spinners "^2.5.0" + is-interactive "^1.0.0" + is-unicode-supported "^0.1.0" + log-symbols "^4.1.0" + strip-ansi "^6.0.0" + wcwidth "^1.0.1" + +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.npmmirror.com/p-limit/-/p-limit-3.1.0.tgz" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.npmmirror.com/p-locate/-/p-locate-5.0.0.tgz" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +param-case@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/param-case/-/param-case-2.1.1.tgz" + integrity sha512-eQE845L6ot89sk2N8liD8HAuH4ca6Vvr7VWAWwt7+kvvG5aBcPmmphQ68JsEG2qa9n1TykS2DLeMt363AAH8/w== + dependencies: + no-case "^2.2.0" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parseurl@~1.3.3: + version "1.3.3" + resolved "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-exists/-/path-exists-4.0.0.tgz" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmmirror.com/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz" + integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/path-type/-/path-type-4.0.0.tgz" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.0.0.tgz" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pinia@^2.0.11: + version "2.1.3" + resolved "https://registry.npmmirror.com/pinia/-/pinia-2.1.3.tgz" + integrity sha512-XNA/z/ye4P5rU1pieVmh0g/hSuDO98/a5UC8oSP0DNdvt6YtetJNHTrXwpwsQuflkGT34qKxAEcp7lSxXNjf/A== + dependencies: + "@vue/devtools-api" "^6.5.0" + vue-demi ">=0.14.5" + +pixi-viewport@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/pixi-viewport/-/pixi-viewport-5.0.1.tgz" + integrity sha512-fIILU9xztqGnhGF5SYfjn1Rir/7asWkJ8zSUay2hwzPrdGTWFtB4yiIlZDeFaLf7KHA04RRb2kI01Sy1kNksAw== + +pixi.js@^7.2.4: + version "7.2.4" + resolved "https://registry.npmmirror.com/pixi.js/-/pixi.js-7.2.4.tgz" + integrity sha512-nBH60meoLnHxoMFz17HoMxXS4uJpG5jwIdL+Gx2S11TzWgP3iKF+/WLOTrkSdyuQoQSdIBxVqpnYii0Wiox15A== + dependencies: + "@pixi/accessibility" "7.2.4" + "@pixi/app" "7.2.4" + "@pixi/assets" "7.2.4" + "@pixi/compressed-textures" "7.2.4" + "@pixi/core" "7.2.4" + "@pixi/display" "7.2.4" + "@pixi/events" "7.2.4" + "@pixi/extensions" "7.2.4" + "@pixi/extract" "7.2.4" + "@pixi/filter-alpha" "7.2.4" + "@pixi/filter-blur" "7.2.4" + "@pixi/filter-color-matrix" "7.2.4" + "@pixi/filter-displacement" "7.2.4" + "@pixi/filter-fxaa" "7.2.4" + "@pixi/filter-noise" "7.2.4" + "@pixi/graphics" "7.2.4" + "@pixi/mesh" "7.2.4" + "@pixi/mesh-extras" "7.2.4" + "@pixi/mixin-cache-as-bitmap" "7.2.4" + "@pixi/mixin-get-child-by-name" "7.2.4" + "@pixi/mixin-get-global-position" "7.2.4" + "@pixi/particle-container" "7.2.4" + "@pixi/prepare" "7.2.4" + "@pixi/sprite" "7.2.4" + "@pixi/sprite-animated" "7.2.4" + "@pixi/sprite-tiling" "7.2.4" + "@pixi/spritesheet" "7.2.4" + "@pixi/text" "7.2.4" + "@pixi/text-bitmap" "7.2.4" + "@pixi/text-html" "7.2.4" + +postcss-selector-parser@^6.0.9: + version "6.0.13" + resolved "https://registry.npmmirror.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz" + integrity sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + +postcss@^8.1.10, postcss@^8.4.13: + version "8.4.24" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.24.tgz" + integrity sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg== + dependencies: + nanoid "^3.3.6" + picocolors "^1.0.0" + source-map-js "^1.0.2" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier@^2.5.1: + version "2.8.8" + resolved "https://registry.npmmirror.com/prettier/-/prettier-2.8.8.tgz" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +protoc-gen-ts@^0.8.6: + version "0.8.6" + resolved "https://registry.npmmirror.com/protoc-gen-ts/-/protoc-gen-ts-0.8.6.tgz" + integrity sha512-66oeorGy4QBvYjQGd/gaeOYyFqKyRmRgTpofmnw8buMG0P7A0jQjoKSvKJz5h5tNUaVkIzvGBUTRVGakrhhwpA== + +proxy-addr@~2.0.7: + version "2.0.7" + resolved "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +proxy-from-env@^1.1.0: + version "1.1.0" + resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.npmmirror.com/punycode/-/punycode-1.3.2.tgz" + integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/punycode/-/punycode-2.3.0.tgz" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +qs@6.11.0: + version "6.11.0" + resolved "https://registry.npmmirror.com/qs/-/qs-6.11.0.tgz" + integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== + dependencies: + side-channel "^1.0.4" + +quasar@^2.6.0: + version "2.12.0" + resolved "https://registry.npmmirror.com/quasar/-/quasar-2.12.0.tgz" + integrity sha512-B8xoeOWNs/Iv7M+FGRvXGYI1qDnJH8AtIb7RiP+zMfMkBcEp+6HJHU/9ODPemC4yteDjO+HPX2f7OhNZKgsPIw== + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/querystring/-/querystring-0.2.0.tgz" + integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmmirror.com/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.npmmirror.com/randombytes/-/randombytes-2.1.0.tgz" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +range-parser@~1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/range-parser/-/range-parser-1.2.1.tgz" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@2.5.1: + version "2.5.1" + resolved "https://registry.npmmirror.com/raw-body/-/raw-body-2.5.1.tgz" + integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.4.24" + unpipe "1.0.0" + +readable-stream@^2.0.0, readable-stream@^2.0.5: + version "2.3.8" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + +readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readdir-glob@^1.0.0: + version "1.1.3" + resolved "https://registry.npmmirror.com/readdir-glob/-/readdir-glob-1.1.3.tgz" + integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== + dependencies: + minimatch "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +register-service-worker@^1.7.2: + version "1.7.2" + resolved "https://registry.npmmirror.com/register-service-worker/-/register-service-worker-1.7.2.tgz" + integrity sha512-CiD3ZSanZqcMPRhtfct5K9f7i3OLCcBBWsJjLh1gW9RO/nS94sVzY59iS+fgYBOBqaBpf4EzfqUF3j9IG+xo8A== + +relateurl@^0.2.7: + version "0.2.7" + resolved "https://registry.npmmirror.com/relateurl/-/relateurl-0.2.7.tgz" + integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.npmmirror.com/require-directory/-/require-directory-2.1.1.tgz" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve@^1.22.0: + version "1.22.2" + resolved "https://registry.npmmirror.com/resolve/-/resolve-1.22.2.tgz" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== + dependencies: + is-core-module "^2.11.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/restore-cursor/-/restore-cursor-3.1.0.tgz" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup-plugin-visualizer@^5.5.4: + version "5.9.0" + resolved "https://registry.npmmirror.com/rollup-plugin-visualizer/-/rollup-plugin-visualizer-5.9.0.tgz" + integrity sha512-bbDOv47+Bw4C/cgs0czZqfm8L82xOZssk4ayZjG40y9zbXclNk7YikrZTDao6p7+HDiGxrN0b65SgZiVm9k1Cg== + dependencies: + open "^8.4.0" + picomatch "^2.3.1" + source-map "^0.7.4" + yargs "^17.5.1" + +"rollup@>=2.59.0 <2.78.0": + version "2.77.3" + resolved "https://registry.npmmirror.com/rollup/-/rollup-2.77.3.tgz" + integrity sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g== + optionalDependencies: + fsevents "~2.3.2" + +run-async@^2.4.0: + version "2.4.1" + resolved "https://registry.npmmirror.com/run-async/-/run-async-2.4.1.tgz" + integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmmirror.com/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.5.5: + version "7.8.1" + resolved "https://registry.npmmirror.com/rxjs/-/rxjs-7.8.1.tgz" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-buffer@5.2.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3": + version "2.1.2" + resolved "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +sass@1.32.12: + version "1.32.12" + resolved "https://registry.npmmirror.com/sass/-/sass-1.32.12.tgz" + integrity sha512-zmXn03k3hN0KaiVTjohgkg98C3UowhL1/VSGdj4/VAAiMKGQOE80PFPxFP2Kyq0OUskPKcY5lImkhBKEHlypJA== + dependencies: + chokidar ">=3.0.0 <4.0.0" + +sax@1.1.4: + version "1.1.4" + resolved "https://registry.npmmirror.com/sax/-/sax-1.1.4.tgz" + integrity sha512-5f3k2PbGGp+YtKJjOItpg3P99IMD84E4HOvcfleTb5joCHNXYLsR9yWFPOYGgaeMPDubQILTCMdsFb2OMeOjtg== + +semver@^7.3.5, semver@^7.3.6, semver@^7.3.7: + version "7.5.1" + resolved "https://registry.npmmirror.com/semver/-/semver-7.5.1.tgz" + integrity sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw== + dependencies: + lru-cache "^6.0.0" + +send@0.18.0: + version "0.18.0" + resolved "https://registry.npmmirror.com/send/-/send-0.18.0.tgz" + integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== + dependencies: + debug "2.6.9" + depd "2.0.0" + destroy "1.2.0" + encodeurl "~1.0.2" + escape-html "~1.0.3" + etag "~1.8.1" + fresh "0.5.2" + http-errors "2.0.0" + mime "1.6.0" + ms "2.1.3" + on-finished "2.4.1" + range-parser "~1.2.1" + statuses "2.0.1" + +serialize-javascript@^6.0.0: + version "6.0.1" + resolved "https://registry.npmmirror.com/serialize-javascript/-/serialize-javascript-6.0.1.tgz" + integrity sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w== + dependencies: + randombytes "^2.1.0" + +serve-static@1.15.0: + version "1.15.0" + resolved "https://registry.npmmirror.com/serve-static/-/serve-static-1.15.0.tgz" + integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== + dependencies: + encodeurl "~1.0.2" + escape-html "~1.0.3" + parseurl "~1.3.3" + send "0.18.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shallow-clone@^3.0.0: + version "3.0.1" + resolved "https://registry.npmmirror.com/shallow-clone/-/shallow-clone-3.0.1.tgz" + integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== + dependencies: + kind-of "^6.0.2" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel@^1.0.4: + version "1.0.4" + resolved "https://registry.npmmirror.com/side-channel/-/side-channel-1.0.4.tgz" + integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== + dependencies: + call-bind "^1.0.0" + get-intrinsic "^1.0.2" + object-inspect "^1.9.0" + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmmirror.com/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/slice-ansi/-/slice-ansi-4.0.0.tgz" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +source-map-js@^1.0.2: + version "1.0.2" + resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.0.2.tgz" + integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== + +source-map@^0.7.4: + version "0.7.4" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.7.4.tgz" + integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== + +source-map@~0.6.0: + version "0.6.1" + resolved "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +stack-trace@^1.0.0-pre2: + version "1.0.0-pre2" + resolved "https://registry.npmmirror.com/stack-trace/-/stack-trace-1.0.0-pre2.tgz" + integrity sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A== + +statuses@2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/statuses/-/statuses-2.0.1.tgz" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.npmmirror.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.npmmirror.com/supports-color/-/supports-color-7.2.0.tgz" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +table@^6.8.0: + version "6.8.1" + resolved "https://registry.npmmirror.com/table/-/table-6.8.1.tgz" + integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + +tar-stream@^2.2.0: + version "2.2.0" + resolved "https://registry.npmmirror.com/tar-stream/-/tar-stream-2.2.0.tgz" + integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== + dependencies: + bl "^4.0.3" + end-of-stream "^1.4.1" + fs-constants "^1.0.0" + inherits "^2.0.3" + readable-stream "^3.1.1" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmmirror.com/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +through@^2.3.6: + version "2.3.8" + resolved "https://registry.npmmirror.com/through/-/through-2.3.8.tgz" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.npmmirror.com/tmp/-/tmp-0.0.33.tgz" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +ts-md5@^1.3.1: + version "1.3.1" + resolved "https://registry.npmmirror.com/ts-md5/-/ts-md5-1.3.1.tgz" + integrity sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg== + +tslib@^1.8.1: + version "1.14.1" + resolved "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz" + integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== + +tslib@^2.1.0: + version "2.5.2" + resolved "https://registry.npmmirror.com/tslib/-/tslib-2.5.2.tgz" + integrity sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA== + +tsutils@^3.21.0: + version "3.21.0" + resolved "https://registry.npmmirror.com/tsutils/-/tsutils-3.21.0.tgz" + integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== + dependencies: + tslib "^1.8.1" + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmmirror.com/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.npmmirror.com/type-fest/-/type-fest-0.21.3.tgz" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-is@~1.6.18: + version "1.6.18" + resolved "https://registry.npmmirror.com/type-is/-/type-is-1.6.18.tgz" + integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== + dependencies: + media-typer "0.3.0" + mime-types "~2.1.24" + +typescript@^4.5.4: + version "4.9.5" + resolved "https://registry.npmmirror.com/typescript/-/typescript-4.9.5.tgz" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +uglify-js@^3.5.1: + version "3.17.4" + resolved "https://registry.npmmirror.com/uglify-js/-/uglify-js-3.17.4.tgz" + integrity sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +unpipe@1.0.0, unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.0.11: + version "1.0.11" + resolved "https://registry.npmmirror.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz" + integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.npmmirror.com/upper-case/-/upper-case-1.1.3.tgz" + integrity sha512-WRbjgmYzgXkCV7zNVpy5YgrHgbBv126rMALQQMrmzOVC4GM2waQ9x7xtm8VU+1yF2kWyPzI9zbZ48n4vSxwfSA== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.npmmirror.com/url/-/url-0.11.0.tgz" + integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +utils-merge@1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/utils-merge/-/utils-merge-1.0.1.tgz" + integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== + +vary@~1.1.2: + version "1.1.2" + resolved "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +vite@^2.9.13: + version "2.9.16" + resolved "https://registry.npmmirror.com/vite/-/vite-2.9.16.tgz" + integrity sha512-X+6q8KPyeuBvTQV8AVSnKDvXoBMnTx8zxh54sOwmmuOdxkjMmEJXH2UEchA+vTMps1xw9vL64uwJOWryULg7nA== + dependencies: + esbuild "^0.14.27" + postcss "^8.4.13" + resolve "^1.22.0" + rollup ">=2.59.0 <2.78.0" + optionalDependencies: + fsevents "~2.3.2" + +vue-demi@>=0.14.5: + version "0.14.5" + resolved "https://registry.npmmirror.com/vue-demi/-/vue-demi-0.14.5.tgz" + integrity sha512-o9NUVpl/YlsGJ7t+xuqJKx8EBGf1quRhCiT6D/J0pfwmk9zUwYkC7yrF4SZCe6fETvSM3UNL2edcbYrSyc4QHA== + +vue-eslint-parser@^9.3.0: + version "9.3.0" + resolved "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-9.3.0.tgz" + integrity sha512-48IxT9d0+wArT1+3wNIy0tascRoywqSUe2E1YalIC1L8jsUGe5aJQItWfRok7DVFGz3UYvzEI7n5wiTXsCMAcQ== + dependencies: + debug "^4.3.4" + eslint-scope "^7.1.1" + eslint-visitor-keys "^3.3.0" + espree "^9.3.1" + esquery "^1.4.0" + lodash "^4.17.21" + semver "^7.3.6" + +vue-router@^4.0.0: + version "4.2.2" + resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.2.2.tgz" + integrity sha512-cChBPPmAflgBGmy3tBsjeoe3f3VOSG6naKyY5pjtrqLGbNEXdzCigFUHgBvp9e3ysAtFtEx7OLqcSDh/1Cq2TQ== + dependencies: + "@vue/devtools-api" "^6.5.0" + +vue@^3.0.0: + version "3.3.4" + resolved "https://registry.npmmirror.com/vue/-/vue-3.3.4.tgz" + integrity sha512-VTyEYn3yvIeY1Py0WaYGZsXnz3y5UnGi62GjVEqvEGPl6nxbOrCXbVOTQWBEJUqAyTUk2uJ5JLVnYJ6ZzGbrSw== + dependencies: + "@vue/compiler-dom" "3.3.4" + "@vue/compiler-sfc" "3.3.4" + "@vue/runtime-dom" "3.3.4" + "@vue/server-renderer" "3.3.4" + "@vue/shared" "3.3.4" + +wcwidth@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/wcwidth/-/wcwidth-1.0.1.tgz" + integrity sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg== + dependencies: + defaults "^1.0.3" + +webpack-merge@^5.8.0: + version "5.9.0" + resolved "https://registry.npmmirror.com/webpack-merge/-/webpack-merge-5.9.0.tgz" + integrity sha512-6NbRQw4+Sy50vYNTw7EyOn41OZItPiXB8GNv3INSoe3PSFaHJEz3SHTrYVaRm2LilNGnFUzh0FAwqPEmU/CwDg== + dependencies: + clone-deep "^4.0.1" + wildcard "^2.0.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.npmmirror.com/which/-/which-2.0.2.tgz" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wildcard@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/wildcard/-/wildcard-2.0.1.tgz" + integrity sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ== + +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.npmmirror.com/word-wrap/-/word-wrap-1.2.3.tgz" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.npmmirror.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.npmmirror.com/y18n/-/y18n-5.0.8.tgz" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.npmmirror.com/yargs-parser/-/yargs-parser-21.1.1.tgz" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^17.5.1: + version "17.7.2" + resolved "https://registry.npmmirror.com/yargs/-/yargs-17.7.2.tgz" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.npmmirror.com/yocto-queue/-/yocto-queue-0.1.0.tgz" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zip-stream@^4.1.0: + version "4.1.0" + resolved "https://registry.npmmirror.com/zip-stream/-/zip-stream-4.1.0.tgz" + integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== + dependencies: + archiver-utils "^2.1.0" + compress-commons "^4.1.0" + readable-stream "^3.6.0"