├── .editorconfig
├── .eslintrc.json
├── .gitignore
├── LICENSE
├── README.md
├── angular.json
├── dist
└── ngx-flowchart
│ ├── .npmignore
│ ├── README.md
│ ├── esm2022
│ ├── lib
│ │ ├── connector.directive.mjs
│ │ ├── default-node.component.mjs
│ │ ├── edge-dragging.service.mjs
│ │ ├── edge-drawing.service.mjs
│ │ ├── magnet.directive.mjs
│ │ ├── model.service.mjs
│ │ ├── modelvalidation.service.mjs
│ │ ├── mouseover.service.mjs
│ │ ├── ngx-flowchart.component.mjs
│ │ ├── ngx-flowchart.models.mjs
│ │ ├── ngx-flowchart.module.mjs
│ │ ├── node-dragging.service.mjs
│ │ ├── node.component.mjs
│ │ ├── rectangleselect.service.mjs
│ │ └── scrollparent.mjs
│ ├── ngx-flowchart.mjs
│ └── public-api.mjs
│ ├── fesm2022
│ ├── ngx-flowchart.mjs
│ └── ngx-flowchart.mjs.map
│ ├── index.d.ts
│ ├── lib
│ ├── connector.directive.d.ts
│ ├── default-node.component.d.ts
│ ├── edge-dragging.service.d.ts
│ ├── edge-drawing.service.d.ts
│ ├── magnet.directive.d.ts
│ ├── model.service.d.ts
│ ├── modelvalidation.service.d.ts
│ ├── mouseover.service.d.ts
│ ├── ngx-flowchart.component.d.ts
│ ├── ngx-flowchart.models.d.ts
│ ├── ngx-flowchart.module.d.ts
│ ├── node-dragging.service.d.ts
│ ├── node.component.d.ts
│ ├── rectangleselect.service.d.ts
│ └── scrollparent.d.ts
│ ├── package.json
│ └── public-api.d.ts
├── package.json
├── projects
└── ngx-flowchart
│ ├── .eslintrc.json
│ ├── README.md
│ ├── ng-package.json
│ ├── package.json
│ ├── src
│ ├── lib
│ │ ├── connector.directive.ts
│ │ ├── default-node.component.html
│ │ ├── default-node.component.scss
│ │ ├── default-node.component.ts
│ │ ├── edge-dragging.service.ts
│ │ ├── edge-drawing.service.ts
│ │ ├── magnet.directive.ts
│ │ ├── model.service.ts
│ │ ├── modelvalidation.service.ts
│ │ ├── mouseover.service.ts
│ │ ├── ngx-flowchart.component.html
│ │ ├── ngx-flowchart.component.scss
│ │ ├── ngx-flowchart.component.ts
│ │ ├── ngx-flowchart.models.ts
│ │ ├── ngx-flowchart.module.ts
│ │ ├── node-dragging.service.ts
│ │ ├── node.component.scss
│ │ ├── node.component.ts
│ │ ├── rectangleselect.service.ts
│ │ └── scrollparent.ts
│ └── public-api.ts
│ ├── tsconfig.lib.json
│ └── tsconfig.lib.prod.json
├── src
├── app
│ ├── app.component.html
│ ├── app.component.scss
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── test-node.component.html
│ └── test-node.component.ts
├── assets
│ └── .gitkeep
├── environments
│ ├── environment.prod.ts
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
└── styles.scss
├── tsconfig.app.json
├── tsconfig.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Editor configuration, see https://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | charset = utf-8
6 | indent_style = space
7 | indent_size = 2
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 |
11 | [*.md]
12 | max_line_length = off
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "root": true,
3 | "ignorePatterns": [
4 | "projects/**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "parserOptions": {
12 | "project": [
13 | "tsconfig.json"
14 | ],
15 | "createDefaultProgram": true
16 | },
17 | "extends": [
18 | "plugin:@typescript-eslint/recommended",
19 | "plugin:@angular-eslint/recommended",
20 | "plugin:@angular-eslint/template/process-inline-templates"
21 | ],
22 | "rules": {
23 | "@angular-eslint/component-selector": [
24 | "error",
25 | {
26 | "type": "element",
27 | "prefix": "app",
28 | "style": "kebab-case"
29 | }
30 | ],
31 | "@angular-eslint/directive-selector": [
32 | "error",
33 | {
34 | "type": "attribute",
35 | "prefix": "app",
36 | "style": "camelCase"
37 | }
38 | ],
39 | "@typescript-eslint/explicit-member-accessibility": [
40 | "off",
41 | {
42 | "accessibility": "explicit"
43 | }
44 | ],
45 | "@typescript-eslint/no-use-before-define": "error",
46 | "arrow-parens": [
47 | "off",
48 | "always"
49 | ],
50 | "import/order": "off",
51 | "@typescript-eslint/member-ordering": "off"
52 | }
53 | },
54 | {
55 | "files": [
56 | "*.html"
57 | ],
58 | "extends": [
59 | "plugin:@angular-eslint/template/recommended"
60 | ],
61 | "rules": {}
62 | }
63 | ]
64 | }
65 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See http://help.github.com/ignore-files/ for more about ignoring files.
2 |
3 | # compiled output
4 | /tmp
5 | /out-tsc
6 | # Only exists if Bazel was run
7 | /bazel-out
8 |
9 | # dependencies
10 | /node_modules
11 |
12 | # profiling files
13 | chrome-profiler-events.json
14 | speed-measure-plugin.json
15 |
16 | # IDEs and editors
17 | /.idea
18 | .project
19 | .classpath
20 | .c9/
21 | *.launch
22 | .settings/
23 | *.sublime-workspace
24 |
25 | # IDE - VSCode
26 | .vscode/*
27 | !.vscode/settings.json
28 | !.vscode/tasks.json
29 | !.vscode/launch.json
30 | !.vscode/extensions.json
31 | .history/*
32 |
33 | # misc
34 | /.angular/cache
35 | /.sass-cache
36 | /connect.lock
37 | /coverage
38 | /libpeerconnection.log
39 | npm-debug.log
40 | yarn-error.log
41 | testem.log
42 | /typings
43 |
44 | # System Files
45 | .DS_Store
46 | Thumbs.db
47 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright 2016 The Thingsboard Authors
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NgxFlowchart
2 |
3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.1.
4 |
5 | ## Development server
6 |
7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.
8 |
9 | ## Code scaffolding
10 |
11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.
12 |
13 | ## Build
14 |
15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.
16 |
17 | ## Further help
18 |
19 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
20 |
--------------------------------------------------------------------------------
/angular.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "version": 1,
4 | "newProjectRoot": "projects",
5 | "projects": {
6 | "ngx-flowchart-demo": {
7 | "root": "",
8 | "sourceRoot": "src",
9 | "projectType": "application",
10 | "prefix": "app",
11 | "schematics": {
12 | "@schematics/angular:component": {
13 | "style": "scss"
14 | },
15 | "@schematics/angular:application": {
16 | "strict": true
17 | }
18 | },
19 | "architect": {
20 | "build": {
21 | "builder": "@angular-devkit/build-angular:application",
22 | "options": {
23 | "outputPath": {
24 | "base": "dist/ngx-flowchart-demo"
25 | },
26 | "index": "src/index.html",
27 | "polyfills": [
28 | "src/polyfills.ts"
29 | ],
30 | "tsConfig": "tsconfig.app.json",
31 | "aot": true,
32 | "assets": [
33 | "src/favicon.ico",
34 | "src/assets"
35 | ],
36 | "styles": [
37 | "src/styles.scss"
38 | ],
39 | "scripts": [
40 | "node_modules/jquery/dist/jquery.min.js"
41 | ],
42 | "browser": "src/main.ts"
43 | },
44 | "configurations": {
45 | "production": {
46 | "fileReplacements": [
47 | {
48 | "replace": "src/environments/environment.ts",
49 | "with": "src/environments/environment.prod.ts"
50 | }
51 | ],
52 | "optimization": true,
53 | "outputHashing": "all",
54 | "sourceMap": false,
55 | "namedChunks": false,
56 | "aot": true,
57 | "extractLicenses": true,
58 | "budgets": [
59 | {
60 | "type": "initial",
61 | "maximumWarning": "2mb",
62 | "maximumError": "5mb"
63 | },
64 | {
65 | "type": "anyComponentStyle",
66 | "maximumWarning": "6kb"
67 | }
68 | ]
69 | }
70 | }
71 | },
72 | "serve": {
73 | "builder": "@angular-devkit/build-angular:dev-server",
74 | "options": {
75 | "buildTarget": "ngx-flowchart-demo:build"
76 | },
77 | "configurations": {
78 | "production": {
79 | "buildTarget": "ngx-flowchart-demo:build:production"
80 | }
81 | }
82 | },
83 | "extract-i18n": {
84 | "builder": "@angular-devkit/build-angular:extract-i18n",
85 | "options": {
86 | "buildTarget": "ngx-flowchart-demo:build"
87 | }
88 | },
89 | "lint": {
90 | "builder": "@angular-eslint/builder:lint",
91 | "options": {
92 | "lintFilePatterns": [
93 | "src/**/*.ts",
94 | "src/**/*.html"
95 | ]
96 | }
97 | }
98 | }
99 | },
100 | "ngx-flowchart": {
101 | "projectType": "library",
102 | "root": "projects/ngx-flowchart",
103 | "sourceRoot": "projects/ngx-flowchart/src",
104 | "prefix": "fc",
105 | "schematics": {
106 | "@schematics/angular:component": {
107 | "style": "scss"
108 | }
109 | },
110 | "architect": {
111 | "build": {
112 | "builder": "@angular-devkit/build-angular:ng-packagr",
113 | "options": {
114 | "project": "projects/ngx-flowchart/ng-package.json"
115 | },
116 | "configurations": {
117 | "production": {
118 | "tsConfig": "projects/ngx-flowchart/tsconfig.lib.prod.json"
119 | },
120 | "development": {
121 | "tsConfig": "projects/ngx-flowchart/tsconfig.lib.json"
122 | }
123 | },
124 | "defaultConfiguration": "production"
125 | },
126 | "test": {
127 | "builder": "@angular-devkit/build-angular:karma",
128 | "options": {
129 | "main": "projects/ngx-flowchart/src/test.ts",
130 | "tsConfig": "projects/ngx-flowchart/tsconfig.spec.json",
131 | "karmaConfig": "projects/ngx-flowchart/karma.conf.js"
132 | }
133 | },
134 | "lint": {
135 | "builder": "@angular-eslint/builder:lint",
136 | "options": {
137 | "lintFilePatterns": [
138 | "projects/ngx-flowchart/**/*.ts",
139 | "projects/ngx-flowchart/**/*.html"
140 | ]
141 | }
142 | }
143 | }
144 | }
145 | },
146 | "cli": {
147 | "packageManager": "yarn",
148 | "analytics": false,
149 | "schematicCollections": [
150 | "@angular-eslint/schematics"
151 | ]
152 | },
153 | "schematics": {
154 | "@angular-eslint/schematics:application": {
155 | "setParserOptionsProject": true
156 | },
157 | "@angular-eslint/schematics:library": {
158 | "setParserOptionsProject": true
159 | }
160 | }
161 | }
162 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/.npmignore:
--------------------------------------------------------------------------------
1 | # Nested package.json's are only needed for development.
2 | **/package.json
--------------------------------------------------------------------------------
/dist/ngx-flowchart/README.md:
--------------------------------------------------------------------------------
1 | # NgxFlowchart
2 |
3 | This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.0.
4 |
5 | ## Code scaffolding
6 |
7 | Run `ng generate component component-name --project ngx-flowchart` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ngx-flowchart`.
8 | > Note: Don't forget to add `--project ngx-flowchart` or else it will be added to the default project in your `angular.json` file.
9 |
10 | ## Build
11 |
12 | Run `ng build ngx-flowchart` to build the project. The build artifacts will be stored in the `dist/` directory.
13 |
14 | ## Publishing
15 |
16 | After building your library with `ng build ngx-flowchart`, go to the dist folder `cd dist/ngx-flowchart` and run `npm publish`.
17 |
18 | ## Further help
19 |
20 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
21 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/connector.directive.mjs:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, HostListener, Input } from '@angular/core';
2 | import { FlowchartConstants } from './ngx-flowchart.models';
3 | import { FcModelService } from './model.service';
4 | import * as i0 from "@angular/core";
5 | export class FcConnectorDirective {
6 | constructor(elementRef) {
7 | this.elementRef = elementRef;
8 | }
9 | ngOnInit() {
10 | const element = $(this.elementRef.nativeElement);
11 | element.addClass(FlowchartConstants.connectorClass);
12 | if (this.modelservice.isEditable()) {
13 | element.attr('draggable', 'true');
14 | this.updateConnectorClass();
15 | }
16 | const connectorRectInfo = {
17 | type: this.connector.type,
18 | width: this.elementRef.nativeElement.offsetWidth,
19 | height: this.elementRef.nativeElement.offsetHeight,
20 | nodeRectInfo: this.nodeRectInfo
21 | };
22 | this.modelservice.connectors.setConnectorRectInfo(this.connector.id, connectorRectInfo);
23 | }
24 | ngOnChanges(changes) {
25 | let updateConnector = false;
26 | for (const propName of Object.keys(changes)) {
27 | const change = changes[propName];
28 | if (!change.firstChange && change.currentValue !== change.previousValue) {
29 | if (propName === 'mouseOverConnector') {
30 | updateConnector = true;
31 | }
32 | }
33 | }
34 | if (updateConnector && this.modelservice.isEditable()) {
35 | this.updateConnectorClass();
36 | }
37 | }
38 | updateConnectorClass() {
39 | const element = $(this.elementRef.nativeElement);
40 | if (this.connector === this.mouseOverConnector) {
41 | element.addClass(FlowchartConstants.hoverClass);
42 | }
43 | else {
44 | element.removeClass(FlowchartConstants.hoverClass);
45 | }
46 | }
47 | dragover(event) {
48 | // Skip - conflict with magnet
49 | /* if (this.modelservice.isEditable()) {
50 | return this.callbacks.edgeDragoverConnector(event, this.connector);
51 | }*/
52 | }
53 | drop(event) {
54 | if (this.modelservice.isEditable()) {
55 | return this.callbacks.edgeDrop(event, this.connector);
56 | }
57 | }
58 | dragend(event) {
59 | if (this.modelservice.isEditable()) {
60 | this.callbacks.edgeDragend(event);
61 | }
62 | }
63 | dragstart(event) {
64 | if (this.modelservice.isEditable()) {
65 | this.callbacks.edgeDragstart(event, this.connector);
66 | }
67 | }
68 | mouseenter(event) {
69 | if (this.modelservice.isEditable()) {
70 | this.callbacks.connectorMouseEnter(event, this.connector);
71 | }
72 | }
73 | mouseleave(event) {
74 | if (this.modelservice.isEditable()) {
75 | this.callbacks.connectorMouseLeave(event, this.connector);
76 | }
77 | }
78 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcConnectorDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
79 | static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.6", type: FcConnectorDirective, selector: "[fc-connector]", inputs: { callbacks: "callbacks", modelservice: "modelservice", connector: "connector", nodeRectInfo: "nodeRectInfo", mouseOverConnector: "mouseOverConnector" }, host: { listeners: { "dragover": "dragover($event)", "drop": "drop($event)", "dragend": "dragend($event)", "dragstart": "dragstart($event)", "mouseenter": "mouseenter($event)", "mouseleave": "mouseleave($event)" } }, usesOnChanges: true, ngImport: i0 }); }
80 | }
81 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcConnectorDirective, decorators: [{
82 | type: Directive,
83 | args: [{
84 | // eslint-disable-next-line @angular-eslint/directive-selector
85 | selector: '[fc-connector]'
86 | }]
87 | }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { callbacks: [{
88 | type: Input
89 | }], modelservice: [{
90 | type: Input
91 | }], connector: [{
92 | type: Input
93 | }], nodeRectInfo: [{
94 | type: Input
95 | }], mouseOverConnector: [{
96 | type: Input
97 | }], dragover: [{
98 | type: HostListener,
99 | args: ['dragover', ['$event']]
100 | }], drop: [{
101 | type: HostListener,
102 | args: ['drop', ['$event']]
103 | }], dragend: [{
104 | type: HostListener,
105 | args: ['dragend', ['$event']]
106 | }], dragstart: [{
107 | type: HostListener,
108 | args: ['dragstart', ['$event']]
109 | }], mouseenter: [{
110 | type: HostListener,
111 | args: ['mouseenter', ['$event']]
112 | }], mouseleave: [{
113 | type: HostListener,
114 | args: ['mouseleave', ['$event']]
115 | }] } });
116 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29ubmVjdG9yLmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1mbG93Y2hhcnQvc3JjL2xpYi9jb25uZWN0b3IuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQW9DLE1BQU0sZUFBZSxDQUFDO0FBQzdHLE9BQU8sRUFBaUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUMzSCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7O0FBTWpELE1BQU0sT0FBTyxvQkFBb0I7SUFpQi9CLFlBQW1CLFVBQW1DO1FBQW5DLGVBQVUsR0FBVixVQUFVLENBQXlCO0lBQ3RELENBQUM7SUFFRCxRQUFRO1FBQ04sTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDakQsT0FBTyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUNwRCxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQztZQUNuQyxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNsQyxJQUFJLENBQUMsb0JBQW9CLEVBQUUsQ0FBQztRQUM5QixDQUFDO1FBQ0QsTUFBTSxpQkFBaUIsR0FBd0I7WUFDN0MsSUFBSSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSTtZQUN6QixLQUFLLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsV0FBVztZQUNoRCxNQUFNLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxhQUFhLENBQUMsWUFBWTtZQUNsRCxZQUFZLEVBQUUsSUFBSSxDQUFDLFlBQVk7U0FDaEMsQ0FBQztRQUNGLElBQUksQ0FBQyxZQUFZLENBQUMsVUFBVSxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxFQUFFLGlCQUFpQixDQUFDLENBQUM7SUFDMUYsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxJQUFJLGVBQWUsR0FBRyxLQUFLLENBQUM7UUFDNUIsS0FBSyxNQUFNLFFBQVEsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDNUMsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ2pDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxJQUFJLE1BQU0sQ0FBQyxZQUFZLEtBQUssTUFBTSxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUN4RSxJQUFJLFFBQVEsS0FBSyxvQkFBb0IsRUFBRSxDQUFDO29CQUN0QyxlQUFlLEdBQUcsSUFBSSxDQUFDO2dCQUN6QixDQUFDO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFDRCxJQUFJLGVBQWUsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUM7WUFDdEQsSUFBSSxDQUFDLG9CQUFvQixFQUFFLENBQUM7UUFDOUIsQ0FBQztJQUNILENBQUM7SUFFTyxvQkFBb0I7UUFDMUIsTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDakQsSUFBSSxJQUFJLENBQUMsU0FBUyxLQUFLLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO1lBQy9DLE9BQU8sQ0FBQyxRQUFRLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFDLENBQUM7UUFDbEQsQ0FBQzthQUFNLENBQUM7WUFDTixPQUFPLENBQUMsV0FBVyxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3JELENBQUM7SUFDSCxDQUFDO0lBR0QsUUFBUSxDQUFDLEtBQWtCO1FBQ3pCLDhCQUE4QjtRQUM5Qjs7V0FFRztJQUNMLENBQUM7SUFHRCxJQUFJLENBQUMsS0FBa0I7UUFDckIsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUM7WUFDbkMsT0FBTyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3hELENBQUM7SUFDSCxDQUFDO0lBR0QsT0FBTyxDQUFDLEtBQWtCO1FBQ3hCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3BDLENBQUM7SUFDSCxDQUFDO0lBR0QsU0FBUyxDQUFDLEtBQWtCO1FBQzFCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDdEQsQ0FBQztJQUNILENBQUM7SUFHRCxVQUFVLENBQUMsS0FBaUI7UUFDMUIsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUM7WUFDbkMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzVELENBQUM7SUFDSCxDQUFDO0lBR0QsVUFBVSxDQUFDLEtBQWlCO1FBQzFCLElBQUksSUFBSSxDQUFDLFlBQVksQ0FBQyxVQUFVLEVBQUUsRUFBRSxDQUFDO1lBQ25DLElBQUksQ0FBQyxTQUFTLENBQUMsbUJBQW1CLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUM1RCxDQUFDO0lBQ0gsQ0FBQzs4R0FyR1Usb0JBQW9CO2tHQUFwQixvQkFBb0I7OzJGQUFwQixvQkFBb0I7a0JBSmhDLFNBQVM7bUJBQUM7b0JBQ1QsOERBQThEO29CQUM5RCxRQUFRLEVBQUUsZ0JBQWdCO2lCQUMzQjsrRUFJQyxTQUFTO3NCQURSLEtBQUs7Z0JBSU4sWUFBWTtzQkFEWCxLQUFLO2dCQUlOLFNBQVM7c0JBRFIsS0FBSztnQkFJTixZQUFZO3NCQURYLEtBQUs7Z0JBSU4sa0JBQWtCO3NCQURqQixLQUFLO2dCQStDTixRQUFRO3NCQURQLFlBQVk7dUJBQUMsVUFBVSxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVNwQyxJQUFJO3NCQURILFlBQVk7dUJBQUMsTUFBTSxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVFoQyxPQUFPO3NCQUROLFlBQVk7dUJBQUMsU0FBUyxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVFuQyxTQUFTO3NCQURSLFlBQVk7dUJBQUMsV0FBVyxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVFyQyxVQUFVO3NCQURULFlBQVk7dUJBQUMsWUFBWSxFQUFFLENBQUMsUUFBUSxDQUFDO2dCQVF0QyxVQUFVO3NCQURULFlBQVk7dUJBQUMsWUFBWSxFQUFFLENBQUMsUUFBUSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGlyZWN0aXZlLCBFbGVtZW50UmVmLCBIb3N0TGlzdGVuZXIsIElucHV0LCBPbkNoYW5nZXMsIE9uSW5pdCwgU2ltcGxlQ2hhbmdlcyB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRmNDYWxsYmFja3MsIEZjQ29ubmVjdG9yLCBGY0Nvbm5lY3RvclJlY3RJbmZvLCBGY05vZGVSZWN0SW5mbywgRmxvd2NoYXJ0Q29uc3RhbnRzIH0gZnJvbSAnLi9uZ3gtZmxvd2NoYXJ0Lm1vZGVscyc7XG5pbXBvcnQgeyBGY01vZGVsU2VydmljZSB9IGZyb20gJy4vbW9kZWwuc2VydmljZSc7XG5cbkBEaXJlY3RpdmUoe1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQGFuZ3VsYXItZXNsaW50L2RpcmVjdGl2ZS1zZWxlY3RvclxuICBzZWxlY3RvcjogJ1tmYy1jb25uZWN0b3JdJ1xufSlcbmV4cG9ydCBjbGFzcyBGY0Nvbm5lY3RvckRpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25DaGFuZ2VzIHtcblxuICBASW5wdXQoKVxuICBjYWxsYmFja3M6IEZjQ2FsbGJhY2tzO1xuXG4gIEBJbnB1dCgpXG4gIG1vZGVsc2VydmljZTogRmNNb2RlbFNlcnZpY2U7XG5cbiAgQElucHV0KClcbiAgY29ubmVjdG9yOiBGY0Nvbm5lY3RvcjtcblxuICBASW5wdXQoKVxuICBub2RlUmVjdEluZm86IEZjTm9kZVJlY3RJbmZvO1xuXG4gIEBJbnB1dCgpXG4gIG1vdXNlT3ZlckNvbm5lY3RvcjogRmNDb25uZWN0b3I7XG5cbiAgY29uc3RydWN0b3IocHVibGljIGVsZW1lbnRSZWY6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+KSB7XG4gIH1cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICBjb25zdCBlbGVtZW50ID0gJCh0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudCk7XG4gICAgZWxlbWVudC5hZGRDbGFzcyhGbG93Y2hhcnRDb25zdGFudHMuY29ubmVjdG9yQ2xhc3MpO1xuICAgIGlmICh0aGlzLm1vZGVsc2VydmljZS5pc0VkaXRhYmxlKCkpIHtcbiAgICAgIGVsZW1lbnQuYXR0cignZHJhZ2dhYmxlJywgJ3RydWUnKTtcbiAgICAgIHRoaXMudXBkYXRlQ29ubmVjdG9yQ2xhc3MoKTtcbiAgICB9XG4gICAgY29uc3QgY29ubmVjdG9yUmVjdEluZm86IEZjQ29ubmVjdG9yUmVjdEluZm8gPSB7XG4gICAgICB0eXBlOiB0aGlzLmNvbm5lY3Rvci50eXBlLFxuICAgICAgd2lkdGg6IHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50Lm9mZnNldFdpZHRoLFxuICAgICAgaGVpZ2h0OiB0aGlzLmVsZW1lbnRSZWYubmF0aXZlRWxlbWVudC5vZmZzZXRIZWlnaHQsXG4gICAgICBub2RlUmVjdEluZm86IHRoaXMubm9kZVJlY3RJbmZvXG4gICAgfTtcbiAgICB0aGlzLm1vZGVsc2VydmljZS5jb25uZWN0b3JzLnNldENvbm5lY3RvclJlY3RJbmZvKHRoaXMuY29ubmVjdG9yLmlkLCBjb25uZWN0b3JSZWN0SW5mbyk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKTogdm9pZCB7XG4gICAgbGV0IHVwZGF0ZUNvbm5lY3RvciA9IGZhbHNlO1xuICAgIGZvciAoY29uc3QgcHJvcE5hbWUgb2YgT2JqZWN0LmtleXMoY2hhbmdlcykpIHtcbiAgICAgIGNvbnN0IGNoYW5nZSA9IGNoYW5nZXNbcHJvcE5hbWVdO1xuICAgICAgaWYgKCFjaGFuZ2UuZmlyc3RDaGFuZ2UgJiYgY2hhbmdlLmN1cnJlbnRWYWx1ZSAhPT0gY2hhbmdlLnByZXZpb3VzVmFsdWUpIHtcbiAgICAgICAgaWYgKHByb3BOYW1lID09PSAnbW91c2VPdmVyQ29ubmVjdG9yJykge1xuICAgICAgICAgIHVwZGF0ZUNvbm5lY3RvciA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKHVwZGF0ZUNvbm5lY3RvciAmJiB0aGlzLm1vZGVsc2VydmljZS5pc0VkaXRhYmxlKCkpIHtcbiAgICAgIHRoaXMudXBkYXRlQ29ubmVjdG9yQ2xhc3MoKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUNvbm5lY3RvckNsYXNzKCkge1xuICAgIGNvbnN0IGVsZW1lbnQgPSAkKHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50KTtcbiAgICBpZiAodGhpcy5jb25uZWN0b3IgPT09IHRoaXMubW91c2VPdmVyQ29ubmVjdG9yKSB7XG4gICAgICBlbGVtZW50LmFkZENsYXNzKEZsb3djaGFydENvbnN0YW50cy5ob3ZlckNsYXNzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgZWxlbWVudC5yZW1vdmVDbGFzcyhGbG93Y2hhcnRDb25zdGFudHMuaG92ZXJDbGFzcyk7XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZHJhZ292ZXInLCBbJyRldmVudCddKVxuICBkcmFnb3ZlcihldmVudDogRXZlbnQgfCBhbnkpIHtcbiAgICAvLyBTa2lwIC0gY29uZmxpY3Qgd2l0aCBtYWduZXRcbiAgICAvKiBpZiAodGhpcy5tb2RlbHNlcnZpY2UuaXNFZGl0YWJsZSgpKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxsYmFja3MuZWRnZURyYWdvdmVyQ29ubmVjdG9yKGV2ZW50LCB0aGlzLmNvbm5lY3Rvcik7XG4gICAgfSovXG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkcm9wJywgWyckZXZlbnQnXSlcbiAgZHJvcChldmVudDogRXZlbnQgfCBhbnkpIHtcbiAgICBpZiAodGhpcy5tb2RlbHNlcnZpY2UuaXNFZGl0YWJsZSgpKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWxsYmFja3MuZWRnZURyb3AoZXZlbnQsIHRoaXMuY29ubmVjdG9yKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkcmFnZW5kJywgWyckZXZlbnQnXSlcbiAgZHJhZ2VuZChldmVudDogRXZlbnQgfCBhbnkpIHtcbiAgICBpZiAodGhpcy5tb2RlbHNlcnZpY2UuaXNFZGl0YWJsZSgpKSB7XG4gICAgICB0aGlzLmNhbGxiYWNrcy5lZGdlRHJhZ2VuZChldmVudCk7XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZHJhZ3N0YXJ0JywgWyckZXZlbnQnXSlcbiAgZHJhZ3N0YXJ0KGV2ZW50OiBFdmVudCB8IGFueSkge1xuICAgIGlmICh0aGlzLm1vZGVsc2VydmljZS5pc0VkaXRhYmxlKCkpIHtcbiAgICAgIHRoaXMuY2FsbGJhY2tzLmVkZ2VEcmFnc3RhcnQoZXZlbnQsIHRoaXMuY29ubmVjdG9yKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdtb3VzZWVudGVyJywgWyckZXZlbnQnXSlcbiAgbW91c2VlbnRlcihldmVudDogTW91c2VFdmVudCkge1xuICAgIGlmICh0aGlzLm1vZGVsc2VydmljZS5pc0VkaXRhYmxlKCkpIHtcbiAgICAgIHRoaXMuY2FsbGJhY2tzLmNvbm5lY3Rvck1vdXNlRW50ZXIoZXZlbnQsIHRoaXMuY29ubmVjdG9yKTtcbiAgICB9XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdtb3VzZWxlYXZlJywgWyckZXZlbnQnXSlcbiAgbW91c2VsZWF2ZShldmVudDogTW91c2VFdmVudCkge1xuICAgIGlmICh0aGlzLm1vZGVsc2VydmljZS5pc0VkaXRhYmxlKCkpIHtcbiAgICAgIHRoaXMuY2FsbGJhY2tzLmNvbm5lY3Rvck1vdXNlTGVhdmUoZXZlbnQsIHRoaXMuY29ubmVjdG9yKTtcbiAgICB9XG4gIH1cblxufVxuIl19
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/default-node.component.mjs:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { FcNodeComponent } from './node.component';
3 | import * as i0 from "@angular/core";
4 | import * as i1 from "@angular/common";
5 | import * as i2 from "./magnet.directive";
6 | import * as i3 from "./connector.directive";
7 | export class DefaultFcNodeComponent extends FcNodeComponent {
8 | constructor() {
9 | super();
10 | }
11 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DefaultFcNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
12 | static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.6", type: DefaultFcNodeComponent, selector: "fc-default-node", usesInheritance: true, ngImport: i0, template: "
\n
\n
\n
{{ node.name }}
\n\n
\n
\n
\n
\n \n
\n
\n ×\n
\n
\n", styles: [":host .fc-node-overlay{position:absolute;pointer-events:none;inset:0;background-color:#000;opacity:0}:host :host-context(.fc-hover) .fc-node-overlay{opacity:.25;transition:opacity .2s}:host :host-context(.fc-selected) .fc-node-overlay{opacity:.25}:host .innerNode{display:flex;justify-content:center;align-items:center;min-width:100px;border-radius:5px;background-color:#f15b26;color:#fff;font-size:16px;pointer-events:none}:host .innerNode p{padding:0 15px;text-align:center}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.FcMagnetDirective, selector: "[fc-magnet]", inputs: ["callbacks", "connector"] }, { kind: "directive", type: i3.FcConnectorDirective, selector: "[fc-connector]", inputs: ["callbacks", "modelservice", "connector", "nodeRectInfo", "mouseOverConnector"] }] }); }
13 | }
14 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DefaultFcNodeComponent, decorators: [{
15 | type: Component,
16 | args: [{ selector: 'fc-default-node', template: "\n
\n
\n
{{ node.name }}
\n\n
\n
\n
\n
\n \n
\n
\n ×\n
\n
\n", styles: [":host .fc-node-overlay{position:absolute;pointer-events:none;inset:0;background-color:#000;opacity:0}:host :host-context(.fc-hover) .fc-node-overlay{opacity:.25;transition:opacity .2s}:host :host-context(.fc-selected) .fc-node-overlay{opacity:.25}:host .innerNode{display:flex;justify-content:center;align-items:center;min-width:100px;border-radius:5px;background-color:#f15b26;color:#fff;font-size:16px;pointer-events:none}:host .innerNode p{padding:0 15px;text-align:center}\n"] }]
17 | }], ctorParameters: () => [] });
18 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVmYXVsdC1ub2RlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1mbG93Y2hhcnQvc3JjL2xpYi9kZWZhdWx0LW5vZGUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWZsb3djaGFydC9zcmMvbGliL2RlZmF1bHQtbm9kZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQzs7Ozs7QUFRbkQsTUFBTSxPQUFPLHNCQUF1QixTQUFRLGVBQWU7SUFFekQ7UUFDRSxLQUFLLEVBQUUsQ0FBQztJQUNWLENBQUM7OEdBSlUsc0JBQXNCO2tHQUF0QixzQkFBc0IsOEVDVG5DLGduREFrQ0E7OzJGRHpCYSxzQkFBc0I7a0JBTmxDLFNBQVM7K0JBRUUsaUJBQWlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGY05vZGVDb21wb25lbnQgfSBmcm9tICcuL25vZGUuY29tcG9uZW50JztcblxuQENvbXBvbmVudCh7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAYW5ndWxhci1lc2xpbnQvY29tcG9uZW50LXNlbGVjdG9yXG4gIHNlbGVjdG9yOiAnZmMtZGVmYXVsdC1ub2RlJyxcbiAgdGVtcGxhdGVVcmw6ICcuL2RlZmF1bHQtbm9kZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2RlZmF1bHQtbm9kZS5jb21wb25lbnQuc2NzcyddXG59KVxuZXhwb3J0IGNsYXNzIERlZmF1bHRGY05vZGVDb21wb25lbnQgZXh0ZW5kcyBGY05vZGVDb21wb25lbnQge1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIHN1cGVyKCk7XG4gIH1cblxufVxuIiwiPGRpdlxuICAoZGJsY2xpY2spPVwidXNlck5vZGVDYWxsYmFja3MuZG91YmxlQ2xpY2soJGV2ZW50LCBub2RlKVwiPlxuICA8ZGl2IGNsYXNzPVwie3tmbG93Y2hhcnRDb25zdGFudHMubm9kZU92ZXJsYXlDbGFzc319XCI+PC9kaXY+XG4gIDxkaXYgY2xhc3M9XCJpbm5lck5vZGVcIj5cbiAgICA8cD57eyBub2RlLm5hbWUgfX08L3A+XG5cbiAgICA8ZGl2IGNsYXNzPVwie3tmbG93Y2hhcnRDb25zdGFudHMubGVmdENvbm5lY3RvckNsYXNzfX1cIj5cbiAgICAgIDxkaXYgZmMtbWFnbmV0IFtjb25uZWN0b3JdPVwiY29ubmVjdG9yXCIgW2NhbGxiYWNrc109XCJjYWxsYmFja3NcIlxuICAgICAgICAgICAqbmdGb3I9XCJsZXQgY29ubmVjdG9yIG9mIG1vZGVsc2VydmljZS5ub2Rlcy5nZXRDb25uZWN0b3JzQnlUeXBlKG5vZGUsIGZsb3djaGFydENvbnN0YW50cy5sZWZ0Q29ubmVjdG9yVHlwZSlcIj5cbiAgICAgICAgPGRpdiBmYy1jb25uZWN0b3IgW2Nvbm5lY3Rvcl09XCJjb25uZWN0b3JcIlxuICAgICAgICAgICAgIFtub2RlUmVjdEluZm9dPVwibm9kZVJlY3RJbmZvXCJcbiAgICAgICAgICAgICBbbW91c2VPdmVyQ29ubmVjdG9yXT1cIm1vdXNlT3ZlckNvbm5lY3RvclwiXG4gICAgICAgICAgICAgW2NhbGxiYWNrc109XCJjYWxsYmFja3NcIlxuICAgICAgICAgICAgIFttb2RlbHNlcnZpY2VdPVwibW9kZWxzZXJ2aWNlXCI+PC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IGNsYXNzPVwie3tmbG93Y2hhcnRDb25zdGFudHMucmlnaHRDb25uZWN0b3JDbGFzc319XCI+XG4gICAgICA8ZGl2IGZjLW1hZ25ldCBbY29ubmVjdG9yXT1cImNvbm5lY3RvclwiIFtjYWxsYmFja3NdPVwiY2FsbGJhY2tzXCJcbiAgICAgICAgICAgKm5nRm9yPVwibGV0IGNvbm5lY3RvciBvZiBtb2RlbHNlcnZpY2Uubm9kZXMuZ2V0Q29ubmVjdG9yc0J5VHlwZShub2RlLCBmbG93Y2hhcnRDb25zdGFudHMucmlnaHRDb25uZWN0b3JUeXBlKVwiPlxuICAgICAgICA8ZGl2IGZjLWNvbm5lY3RvciBbY29ubmVjdG9yXT1cImNvbm5lY3RvclwiXG4gICAgICAgICAgICAgW25vZGVSZWN0SW5mb109XCJub2RlUmVjdEluZm9cIlxuICAgICAgICAgICAgIFttb3VzZU92ZXJDb25uZWN0b3JdPVwibW91c2VPdmVyQ29ubmVjdG9yXCJcbiAgICAgICAgICAgICBbY2FsbGJhY2tzXT1cImNhbGxiYWNrc1wiXG4gICAgICAgICAgICAgW21vZGVsc2VydmljZV09XCJtb2RlbHNlcnZpY2VcIj48L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPGRpdiAqbmdJZj1cIm1vZGVsc2VydmljZS5pc0VkaXRhYmxlKCkgJiYgIW5vZGUucmVhZG9ubHlcIiBjbGFzcz1cImZjLW5vZGVlZGl0XCIgKGNsaWNrKT1cInVzZXJOb2RlQ2FsbGJhY2tzLm5vZGVFZGl0KCRldmVudCwgbm9kZSlcIj5cbiAgICA8aSBjbGFzcz1cImZhIGZhLXBlbmNpbFwiIGFyaWEtaGlkZGVuPVwidHJ1ZVwiPjwvaT5cbiAgPC9kaXY+XG4gIDxkaXYgKm5nSWY9XCJtb2RlbHNlcnZpY2UuaXNFZGl0YWJsZSgpICYmICFub2RlLnJlYWRvbmx5XCIgY2xhc3M9XCJmYy1ub2RlZGVsZXRlXCIgKGNsaWNrKT1cIm1vZGVsc2VydmljZS5ub2Rlcy5kZWxldGUobm9kZSlcIj5cbiAgICAmdGltZXM7XG4gIDwvZGl2PlxuPC9kaXY+XG4iXX0=
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/edge-drawing.service.mjs:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { FlowchartConstants } from './ngx-flowchart.models';
3 | import * as i0 from "@angular/core";
4 | export class FcEdgeDrawingService {
5 | constructor() {
6 | }
7 | getEdgeDAttribute(pt1, pt2, style) {
8 | let dAddribute = `M ${pt1.x}, ${pt1.y} `;
9 | if (style === FlowchartConstants.curvedStyle) {
10 | const sourceTangent = this.computeEdgeSourceTangent(pt1, pt2);
11 | const destinationTangent = this.computeEdgeDestinationTangent(pt1, pt2);
12 | dAddribute += `C ${sourceTangent.x}, ${sourceTangent.y} ${(destinationTangent.x - 50)}, ${destinationTangent.y} ${pt2.x}, ${pt2.y}`;
13 | }
14 | else {
15 | dAddribute += `L ${pt2.x}, ${pt2.y}`;
16 | }
17 | return dAddribute;
18 | }
19 | getEdgeCenter(pt1, pt2) {
20 | return {
21 | x: (pt1.x + pt2.x) / 2,
22 | y: (pt1.y + pt2.y) / 2
23 | };
24 | }
25 | computeEdgeTangentOffset(pt1, pt2) {
26 | return (pt2.y - pt1.y) / 2;
27 | }
28 | computeEdgeSourceTangent(pt1, pt2) {
29 | return {
30 | x: pt1.x,
31 | y: pt1.y + this.computeEdgeTangentOffset(pt1, pt2)
32 | };
33 | }
34 | computeEdgeDestinationTangent(pt1, pt2) {
35 | return {
36 | x: pt2.x,
37 | y: pt2.y - this.computeEdgeTangentOffset(pt1, pt2)
38 | };
39 | }
40 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcEdgeDrawingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
41 | static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcEdgeDrawingService }); }
42 | }
43 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcEdgeDrawingService, decorators: [{
44 | type: Injectable
45 | }], ctorParameters: () => [] });
46 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWRnZS1kcmF3aW5nLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZmxvd2NoYXJ0L3NyYy9saWIvZWRnZS1kcmF3aW5nLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQVksa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQzs7QUFHdEUsTUFBTSxPQUFPLG9CQUFvQjtJQUUvQjtJQUNBLENBQUM7SUFFTSxpQkFBaUIsQ0FBQyxHQUFhLEVBQUUsR0FBYSxFQUFFLEtBQWE7UUFDbEUsSUFBSSxVQUFVLEdBQUcsS0FBSyxHQUFHLENBQUMsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQztRQUN6QyxJQUFJLEtBQUssS0FBSyxrQkFBa0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUM3QyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQzlELE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxDQUFDLDZCQUE2QixDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQztZQUN4RSxVQUFVLElBQUksS0FBSyxhQUFhLENBQUMsQ0FBQyxLQUFLLGFBQWEsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLEdBQUcsRUFBRSxDQUFDLEtBQUssa0JBQWtCLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3RJLENBQUM7YUFBTSxDQUFDO1lBQ04sVUFBVSxJQUFJLEtBQUssR0FBRyxDQUFDLENBQUMsS0FBSyxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDdkMsQ0FBQztRQUNELE9BQU8sVUFBVSxDQUFDO0lBQ3BCLENBQUM7SUFFTSxhQUFhLENBQUMsR0FBYSxFQUFFLEdBQWE7UUFDL0MsT0FBTztZQUNMLENBQUMsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUM7WUFDdEIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztTQUN2QixDQUFDO0lBQ0osQ0FBQztJQUVPLHdCQUF3QixDQUFDLEdBQWEsRUFBRSxHQUFhO1FBQzNELE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVPLHdCQUF3QixDQUFDLEdBQWEsRUFBRSxHQUFhO1FBQzNELE9BQU87WUFDTCxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDUixDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQztTQUNuRCxDQUFDO0lBQ0osQ0FBQztJQUVPLDZCQUE2QixDQUFDLEdBQWEsRUFBRSxHQUFhO1FBQ2hFLE9BQU87WUFDTCxDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDUixDQUFDLEVBQUUsR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsd0JBQXdCLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQztTQUNuRCxDQUFDO0lBQ0osQ0FBQzs4R0F4Q1Usb0JBQW9CO2tIQUFwQixvQkFBb0I7OzJGQUFwQixvQkFBb0I7a0JBRGhDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGY0Nvb3JkcywgRmxvd2NoYXJ0Q29uc3RhbnRzIH0gZnJvbSAnLi9uZ3gtZmxvd2NoYXJ0Lm1vZGVscyc7XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBGY0VkZ2VEcmF3aW5nU2VydmljZSB7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gIH1cblxuICBwdWJsaWMgZ2V0RWRnZURBdHRyaWJ1dGUocHQxOiBGY0Nvb3JkcywgcHQyOiBGY0Nvb3Jkcywgc3R5bGU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgbGV0IGRBZGRyaWJ1dGUgPSBgTSAke3B0MS54fSwgJHtwdDEueX0gYDtcbiAgICBpZiAoc3R5bGUgPT09IEZsb3djaGFydENvbnN0YW50cy5jdXJ2ZWRTdHlsZSkge1xuICAgICAgY29uc3Qgc291cmNlVGFuZ2VudCA9IHRoaXMuY29tcHV0ZUVkZ2VTb3VyY2VUYW5nZW50KHB0MSwgcHQyKTtcbiAgICAgIGNvbnN0IGRlc3RpbmF0aW9uVGFuZ2VudCA9IHRoaXMuY29tcHV0ZUVkZ2VEZXN0aW5hdGlvblRhbmdlbnQocHQxLCBwdDIpO1xuICAgICAgZEFkZHJpYnV0ZSArPSBgQyAke3NvdXJjZVRhbmdlbnQueH0sICR7c291cmNlVGFuZ2VudC55fSAkeyhkZXN0aW5hdGlvblRhbmdlbnQueCAtIDUwKX0sICR7ZGVzdGluYXRpb25UYW5nZW50Lnl9ICR7cHQyLnh9LCAke3B0Mi55fWA7XG4gICAgfSBlbHNlIHtcbiAgICAgIGRBZGRyaWJ1dGUgKz0gYEwgJHtwdDIueH0sICR7cHQyLnl9YDtcbiAgICB9XG4gICAgcmV0dXJuIGRBZGRyaWJ1dGU7XG4gIH1cblxuICBwdWJsaWMgZ2V0RWRnZUNlbnRlcihwdDE6IEZjQ29vcmRzLCBwdDI6IEZjQ29vcmRzKTogRmNDb29yZHMge1xuICAgIHJldHVybiB7XG4gICAgICB4OiAocHQxLnggKyBwdDIueCkgLyAyLFxuICAgICAgeTogKHB0MS55ICsgcHQyLnkpIC8gMlxuICAgIH07XG4gIH1cblxuICBwcml2YXRlIGNvbXB1dGVFZGdlVGFuZ2VudE9mZnNldChwdDE6IEZjQ29vcmRzLCBwdDI6IEZjQ29vcmRzKTogbnVtYmVyIHtcbiAgICByZXR1cm4gKHB0Mi55IC0gcHQxLnkpIC8gMjtcbiAgfVxuXG4gIHByaXZhdGUgY29tcHV0ZUVkZ2VTb3VyY2VUYW5nZW50KHB0MTogRmNDb29yZHMsIHB0MjogRmNDb29yZHMpOiBGY0Nvb3JkcyB7XG4gICAgcmV0dXJuIHtcbiAgICAgIHg6IHB0MS54LFxuICAgICAgeTogcHQxLnkgKyB0aGlzLmNvbXB1dGVFZGdlVGFuZ2VudE9mZnNldChwdDEsIHB0MilcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjb21wdXRlRWRnZURlc3RpbmF0aW9uVGFuZ2VudChwdDE6IEZjQ29vcmRzLCBwdDI6IEZjQ29vcmRzKTogRmNDb29yZHMge1xuICAgIHJldHVybiB7XG4gICAgICB4OiBwdDIueCxcbiAgICAgIHk6IHB0Mi55IC0gdGhpcy5jb21wdXRlRWRnZVRhbmdlbnRPZmZzZXQocHQxLCBwdDIpXG4gICAgfTtcbiAgfVxuXG59XG4iXX0=
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/magnet.directive.mjs:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, HostListener, Input } from '@angular/core';
2 | import { FlowchartConstants } from './ngx-flowchart.models';
3 | import * as i0 from "@angular/core";
4 | export class FcMagnetDirective {
5 | constructor(elementRef) {
6 | this.elementRef = elementRef;
7 | }
8 | ngOnInit() {
9 | const element = $(this.elementRef.nativeElement);
10 | element.addClass(FlowchartConstants.magnetClass);
11 | }
12 | dragover(event) {
13 | return this.callbacks.edgeDragoverMagnet(event, this.connector);
14 | }
15 | dragleave(event) {
16 | this.callbacks.edgeDragleaveMagnet(event);
17 | }
18 | drop(event) {
19 | return this.callbacks.edgeDrop(event, this.connector);
20 | }
21 | dragend(event) {
22 | this.callbacks.edgeDragend(event);
23 | }
24 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcMagnetDirective, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Directive }); }
25 | static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.6", type: FcMagnetDirective, selector: "[fc-magnet]", inputs: { callbacks: "callbacks", connector: "connector" }, host: { listeners: { "dragover": "dragover($event)", "dragleave": "dragleave($event)", "drop": "drop($event)", "dragend": "dragend($event)" } }, ngImport: i0 }); }
26 | }
27 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: FcMagnetDirective, decorators: [{
28 | type: Directive,
29 | args: [{
30 | // eslint-disable-next-line @angular-eslint/directive-selector
31 | selector: '[fc-magnet]'
32 | }]
33 | }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { callbacks: [{
34 | type: Input
35 | }], connector: [{
36 | type: Input
37 | }], dragover: [{
38 | type: HostListener,
39 | args: ['dragover', ['$event']]
40 | }], dragleave: [{
41 | type: HostListener,
42 | args: ['dragleave', ['$event']]
43 | }], drop: [{
44 | type: HostListener,
45 | args: ['drop', ['$event']]
46 | }], dragend: [{
47 | type: HostListener,
48 | args: ['dragend', ['$event']]
49 | }] } });
50 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFnbmV0LmRpcmVjdGl2ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3Byb2plY3RzL25neC1mbG93Y2hhcnQvc3JjL2xpYi9tYWduZXQuZGlyZWN0aXZlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQVUsTUFBTSxlQUFlLENBQUM7QUFDbkYsT0FBTyxFQUE0QixrQkFBa0IsRUFBRSxNQUFNLHdCQUF3QixDQUFDOztBQU10RixNQUFNLE9BQU8saUJBQWlCO0lBUTVCLFlBQW1CLFVBQW1DO1FBQW5DLGVBQVUsR0FBVixVQUFVLENBQXlCO0lBQ3RELENBQUM7SUFFRCxRQUFRO1FBQ04sTUFBTSxPQUFPLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDakQsT0FBTyxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUNuRCxDQUFDO0lBR0QsUUFBUSxDQUFDLEtBQWtCO1FBQ3pCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFHRCxTQUFTLENBQUMsS0FBa0I7UUFDMUIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUM1QyxDQUFDO0lBR0QsSUFBSSxDQUFDLEtBQWtCO1FBQ3JCLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsS0FBSyxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBR0QsT0FBTyxDQUFDLEtBQWtCO1FBQ3hCLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3BDLENBQUM7OEdBbENVLGlCQUFpQjtrR0FBakIsaUJBQWlCOzsyRkFBakIsaUJBQWlCO2tCQUo3QixTQUFTO21CQUFDO29CQUNULDhEQUE4RDtvQkFDOUQsUUFBUSxFQUFFLGFBQWE7aUJBQ3hCOytFQUlDLFNBQVM7c0JBRFIsS0FBSztnQkFJTixTQUFTO3NCQURSLEtBQUs7Z0JBWU4sUUFBUTtzQkFEUCxZQUFZO3VCQUFDLFVBQVUsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFNcEMsU0FBUztzQkFEUixZQUFZO3VCQUFDLFdBQVcsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFNckMsSUFBSTtzQkFESCxZQUFZO3VCQUFDLE1BQU0sRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFNaEMsT0FBTztzQkFETixZQUFZO3VCQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERpcmVjdGl2ZSwgRWxlbWVudFJlZiwgSG9zdExpc3RlbmVyLCBJbnB1dCwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGY0NhbGxiYWNrcywgRmNDb25uZWN0b3IsIEZsb3djaGFydENvbnN0YW50cyB9IGZyb20gJy4vbmd4LWZsb3djaGFydC5tb2RlbHMnO1xuXG5ARGlyZWN0aXZlKHtcbiAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEBhbmd1bGFyLWVzbGludC9kaXJlY3RpdmUtc2VsZWN0b3JcbiAgc2VsZWN0b3I6ICdbZmMtbWFnbmV0XSdcbn0pXG5leHBvcnQgY2xhc3MgRmNNYWduZXREaXJlY3RpdmUgaW1wbGVtZW50cyBPbkluaXQge1xuXG4gIEBJbnB1dCgpXG4gIGNhbGxiYWNrczogRmNDYWxsYmFja3M7XG5cbiAgQElucHV0KClcbiAgY29ubmVjdG9yOiBGY0Nvbm5lY3RvcjtcblxuICBjb25zdHJ1Y3RvcihwdWJsaWMgZWxlbWVudFJlZjogRWxlbWVudFJlZjxIVE1MRWxlbWVudD4pIHtcbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIGNvbnN0IGVsZW1lbnQgPSAkKHRoaXMuZWxlbWVudFJlZi5uYXRpdmVFbGVtZW50KTtcbiAgICBlbGVtZW50LmFkZENsYXNzKEZsb3djaGFydENvbnN0YW50cy5tYWduZXRDbGFzcyk7XG4gIH1cblxuICBASG9zdExpc3RlbmVyKCdkcmFnb3ZlcicsIFsnJGV2ZW50J10pXG4gIGRyYWdvdmVyKGV2ZW50OiBFdmVudCB8IGFueSkge1xuICAgIHJldHVybiB0aGlzLmNhbGxiYWNrcy5lZGdlRHJhZ292ZXJNYWduZXQoZXZlbnQsIHRoaXMuY29ubmVjdG9yKTtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2RyYWdsZWF2ZScsIFsnJGV2ZW50J10pXG4gIGRyYWdsZWF2ZShldmVudDogRXZlbnQgfCBhbnkpIHtcbiAgICB0aGlzLmNhbGxiYWNrcy5lZGdlRHJhZ2xlYXZlTWFnbmV0KGV2ZW50KTtcbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ2Ryb3AnLCBbJyRldmVudCddKVxuICBkcm9wKGV2ZW50OiBFdmVudCB8IGFueSkge1xuICAgIHJldHVybiB0aGlzLmNhbGxiYWNrcy5lZGdlRHJvcChldmVudCwgdGhpcy5jb25uZWN0b3IpO1xuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcignZHJhZ2VuZCcsIFsnJGV2ZW50J10pXG4gIGRyYWdlbmQoZXZlbnQ6IEV2ZW50IHwgYW55KSB7XG4gICAgdGhpcy5jYWxsYmFja3MuZWRnZURyYWdlbmQoZXZlbnQpO1xuICB9XG5cbn1cbiJdfQ==
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/mouseover.service.mjs:
--------------------------------------------------------------------------------
1 | export class FcMouseOverService {
2 | constructor(applyFunction) {
3 | this.mouseoverscope = {
4 | connector: null,
5 | edge: null,
6 | node: null
7 | };
8 | this.applyFunction = applyFunction;
9 | }
10 | nodeMouseOver(event, node) {
11 | return this.applyFunction(() => {
12 | this.mouseoverscope.node = node;
13 | });
14 | }
15 | nodeMouseOut(event, node) {
16 | return this.applyFunction(() => {
17 | this.mouseoverscope.node = null;
18 | });
19 | }
20 | connectorMouseEnter(event, connector) {
21 | return this.applyFunction(() => {
22 | this.mouseoverscope.connector = connector;
23 | });
24 | }
25 | connectorMouseLeave(event, connector) {
26 | return this.applyFunction(() => {
27 | this.mouseoverscope.connector = null;
28 | });
29 | }
30 | edgeMouseEnter(event, edge) {
31 | this.mouseoverscope.edge = edge;
32 | }
33 | edgeMouseLeave(event, edge) {
34 | this.mouseoverscope.edge = null;
35 | }
36 | }
37 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW91c2VvdmVyLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZmxvd2NoYXJ0L3NyYy9saWIvbW91c2VvdmVyLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRUEsTUFBTSxPQUFPLGtCQUFrQjtJQVU3QixZQUFZLGFBQWtEO1FBUjlELG1CQUFjLEdBQW1CO1lBQy9CLFNBQVMsRUFBRSxJQUFJO1lBQ2YsSUFBSSxFQUFFLElBQUk7WUFDVixJQUFJLEVBQUUsSUFBSTtTQUNYLENBQUM7UUFLQSxJQUFJLENBQUMsYUFBYSxHQUFHLGFBQWEsQ0FBQztJQUNyQyxDQUFDO0lBRU0sYUFBYSxDQUFDLEtBQWlCLEVBQUUsSUFBWTtRQUNsRCxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxFQUFFO1lBQzdCLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztRQUNsQyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxZQUFZLENBQUMsS0FBaUIsRUFBRSxJQUFZO1FBQ2pELE9BQU8sSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEVBQUU7WUFDN0IsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO1FBQ2xDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLG1CQUFtQixDQUFDLEtBQWlCLEVBQUUsU0FBc0I7UUFDbEUsT0FBTyxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRTtZQUM3QixJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsR0FBRyxTQUFTLENBQUM7UUFDNUMsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU0sbUJBQW1CLENBQUMsS0FBaUIsRUFBRSxTQUFzQjtRQUNsRSxPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxFQUFFO1lBQzdCLElBQUksQ0FBQyxjQUFjLENBQUMsU0FBUyxHQUFHLElBQUksQ0FBQztRQUN2QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxjQUFjLENBQUMsS0FBaUIsRUFBRSxJQUFZO1FBQ25ELElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNsQyxDQUFDO0lBRU0sY0FBYyxDQUFDLEtBQWlCLEVBQUUsSUFBWTtRQUNuRCxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7SUFDbEMsQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRmNDb25uZWN0b3IsIEZjRWRnZSwgRmNOb2RlIH0gZnJvbSAnLi9uZ3gtZmxvd2NoYXJ0Lm1vZGVscyc7XG5cbmV4cG9ydCBjbGFzcyBGY01vdXNlT3ZlclNlcnZpY2Uge1xuXG4gIG1vdXNlb3ZlcnNjb3BlOiBNb3VzZU92ZXJTY29wZSA9IHtcbiAgICBjb25uZWN0b3I6IG51bGwsXG4gICAgZWRnZTogbnVsbCxcbiAgICBub2RlOiBudWxsXG4gIH07XG5cbiAgcHJpdmF0ZSByZWFkb25seSBhcHBseUZ1bmN0aW9uOiA8VD4oZm46ICguLi5hcmdzOiBhbnlbXSkgPT4gVCkgPT4gVDtcblxuICBjb25zdHJ1Y3RvcihhcHBseUZ1bmN0aW9uOiA8VD4oZm46ICguLi5hcmdzOiBhbnlbXSkgPT4gVCkgPT4gVCkge1xuICAgIHRoaXMuYXBwbHlGdW5jdGlvbiA9IGFwcGx5RnVuY3Rpb247XG4gIH1cblxuICBwdWJsaWMgbm9kZU1vdXNlT3ZlcihldmVudDogTW91c2VFdmVudCwgbm9kZTogRmNOb2RlKSB7XG4gICAgcmV0dXJuIHRoaXMuYXBwbHlGdW5jdGlvbigoKSA9PiB7XG4gICAgICB0aGlzLm1vdXNlb3ZlcnNjb3BlLm5vZGUgPSBub2RlO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIG5vZGVNb3VzZU91dChldmVudDogTW91c2VFdmVudCwgbm9kZTogRmNOb2RlKSB7XG4gICAgcmV0dXJuIHRoaXMuYXBwbHlGdW5jdGlvbigoKSA9PiB7XG4gICAgICB0aGlzLm1vdXNlb3ZlcnNjb3BlLm5vZGUgPSBudWxsO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGNvbm5lY3Rvck1vdXNlRW50ZXIoZXZlbnQ6IE1vdXNlRXZlbnQsIGNvbm5lY3RvcjogRmNDb25uZWN0b3IpIHtcbiAgICByZXR1cm4gdGhpcy5hcHBseUZ1bmN0aW9uKCgpID0+IHtcbiAgICAgIHRoaXMubW91c2VvdmVyc2NvcGUuY29ubmVjdG9yID0gY29ubmVjdG9yO1xuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGNvbm5lY3Rvck1vdXNlTGVhdmUoZXZlbnQ6IE1vdXNlRXZlbnQsIGNvbm5lY3RvcjogRmNDb25uZWN0b3IpIHtcbiAgICByZXR1cm4gdGhpcy5hcHBseUZ1bmN0aW9uKCgpID0+IHtcbiAgICAgIHRoaXMubW91c2VvdmVyc2NvcGUuY29ubmVjdG9yID0gbnVsbDtcbiAgICB9KTtcbiAgfVxuXG4gIHB1YmxpYyBlZGdlTW91c2VFbnRlcihldmVudDogTW91c2VFdmVudCwgZWRnZTogRmNFZGdlKSB7XG4gICAgdGhpcy5tb3VzZW92ZXJzY29wZS5lZGdlID0gZWRnZTtcbiAgfVxuXG4gIHB1YmxpYyBlZGdlTW91c2VMZWF2ZShldmVudDogTW91c2VFdmVudCwgZWRnZTogRmNFZGdlKSB7XG4gICAgdGhpcy5tb3VzZW92ZXJzY29wZS5lZGdlID0gbnVsbDtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIE1vdXNlT3ZlclNjb3BlIHtcbiAgY29ubmVjdG9yOiBGY0Nvbm5lY3RvcjtcbiAgZWRnZTogRmNFZGdlO1xuICBub2RlOiBGY05vZGU7XG59XG4iXX0=
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/ngx-flowchart.module.mjs:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { NgxFlowchartComponent } from './ngx-flowchart.component';
3 | import { FcModelValidationService } from './modelvalidation.service';
4 | import { FcEdgeDrawingService } from './edge-drawing.service';
5 | import { CommonModule } from '@angular/common';
6 | import { FcMagnetDirective } from './magnet.directive';
7 | import { FcConnectorDirective } from './connector.directive';
8 | import { FcNodeContainerComponent } from './node.component';
9 | import { FC_NODE_COMPONENT_CONFIG } from './ngx-flowchart.models';
10 | import { DefaultFcNodeComponent } from './default-node.component';
11 | import * as i0 from "@angular/core";
12 | export class NgxFlowchartModule {
13 | static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: NgxFlowchartModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
14 | static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.6", ngImport: i0, type: NgxFlowchartModule, declarations: [NgxFlowchartComponent,
15 | FcMagnetDirective,
16 | FcConnectorDirective,
17 | FcNodeContainerComponent,
18 | DefaultFcNodeComponent], imports: [CommonModule], exports: [NgxFlowchartComponent,
19 | FcMagnetDirective,
20 | FcConnectorDirective,
21 | DefaultFcNodeComponent] }); }
22 | static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: NgxFlowchartModule, providers: [
23 | FcModelValidationService,
24 | FcEdgeDrawingService,
25 | {
26 | provide: FC_NODE_COMPONENT_CONFIG,
27 | useValue: {
28 | nodeComponentType: DefaultFcNodeComponent
29 | }
30 | }
31 | ], imports: [CommonModule] }); }
32 | }
33 | i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: NgxFlowchartModule, decorators: [{
34 | type: NgModule,
35 | args: [{
36 | declarations: [NgxFlowchartComponent,
37 | FcMagnetDirective,
38 | FcConnectorDirective,
39 | FcNodeContainerComponent,
40 | DefaultFcNodeComponent],
41 | providers: [
42 | FcModelValidationService,
43 | FcEdgeDrawingService,
44 | {
45 | provide: FC_NODE_COMPONENT_CONFIG,
46 | useValue: {
47 | nodeComponentType: DefaultFcNodeComponent
48 | }
49 | }
50 | ],
51 | imports: [
52 | CommonModule
53 | ],
54 | exports: [NgxFlowchartComponent,
55 | FcMagnetDirective,
56 | FcConnectorDirective,
57 | DefaultFcNodeComponent]
58 | }]
59 | }] });
60 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWZsb3djaGFydC5tb2R1bGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtZmxvd2NoYXJ0L3NyYy9saWIvbmd4LWZsb3djaGFydC5tb2R1bGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNsRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUNyRSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUM5RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDL0MsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDdkQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDN0QsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFDNUQsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDbEUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sMEJBQTBCLENBQUM7O0FBMEJsRSxNQUFNLE9BQU8sa0JBQWtCOzhHQUFsQixrQkFBa0I7K0dBQWxCLGtCQUFrQixpQkF2QloscUJBQXFCO1lBQ2hDLGlCQUFpQjtZQUNqQixvQkFBb0I7WUFDcEIsd0JBQXdCO1lBQ3hCLHNCQUFzQixhQVl0QixZQUFZLGFBRU4scUJBQXFCO1lBQzNCLGlCQUFpQjtZQUNqQixvQkFBb0I7WUFDcEIsc0JBQXNCOytHQUVqQixrQkFBa0IsYUFsQmhCO1lBQ1Asd0JBQXdCO1lBQ3hCLG9CQUFvQjtZQUNwQjtnQkFDSSxPQUFPLEVBQUUsd0JBQXdCO2dCQUNqQyxRQUFRLEVBQUU7b0JBQ04saUJBQWlCLEVBQUUsc0JBQXNCO2lCQUM1QzthQUNKO1NBQ0osWUFFRyxZQUFZOzsyRkFPUCxrQkFBa0I7a0JBeEI5QixRQUFRO21CQUFDO29CQUNOLFlBQVksRUFBRSxDQUFDLHFCQUFxQjt3QkFDaEMsaUJBQWlCO3dCQUNqQixvQkFBb0I7d0JBQ3BCLHdCQUF3Qjt3QkFDeEIsc0JBQXNCLENBQUM7b0JBQzNCLFNBQVMsRUFBRTt3QkFDUCx3QkFBd0I7d0JBQ3hCLG9CQUFvQjt3QkFDcEI7NEJBQ0ksT0FBTyxFQUFFLHdCQUF3Qjs0QkFDakMsUUFBUSxFQUFFO2dDQUNOLGlCQUFpQixFQUFFLHNCQUFzQjs2QkFDNUM7eUJBQ0o7cUJBQ0o7b0JBQ0QsT0FBTyxFQUFFO3dCQUNMLFlBQVk7cUJBQ2Y7b0JBQ0QsT0FBTyxFQUFFLENBQUMscUJBQXFCO3dCQUMzQixpQkFBaUI7d0JBQ2pCLG9CQUFvQjt3QkFDcEIsc0JBQXNCLENBQUM7aUJBQzlCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgTmdNb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IE5neEZsb3djaGFydENvbXBvbmVudCB9IGZyb20gJy4vbmd4LWZsb3djaGFydC5jb21wb25lbnQnO1xuaW1wb3J0IHsgRmNNb2RlbFZhbGlkYXRpb25TZXJ2aWNlIH0gZnJvbSAnLi9tb2RlbHZhbGlkYXRpb24uc2VydmljZSc7XG5pbXBvcnQgeyBGY0VkZ2VEcmF3aW5nU2VydmljZSB9IGZyb20gJy4vZWRnZS1kcmF3aW5nLnNlcnZpY2UnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEZjTWFnbmV0RGlyZWN0aXZlIH0gZnJvbSAnLi9tYWduZXQuZGlyZWN0aXZlJztcbmltcG9ydCB7IEZjQ29ubmVjdG9yRGlyZWN0aXZlIH0gZnJvbSAnLi9jb25uZWN0b3IuZGlyZWN0aXZlJztcbmltcG9ydCB7IEZjTm9kZUNvbnRhaW5lckNvbXBvbmVudCB9IGZyb20gJy4vbm9kZS5jb21wb25lbnQnO1xuaW1wb3J0IHsgRkNfTk9ERV9DT01QT05FTlRfQ09ORklHIH0gZnJvbSAnLi9uZ3gtZmxvd2NoYXJ0Lm1vZGVscyc7XG5pbXBvcnQgeyBEZWZhdWx0RmNOb2RlQ29tcG9uZW50IH0gZnJvbSAnLi9kZWZhdWx0LW5vZGUuY29tcG9uZW50JztcblxuQE5nTW9kdWxlKHtcbiAgICBkZWNsYXJhdGlvbnM6IFtOZ3hGbG93Y2hhcnRDb21wb25lbnQsXG4gICAgICAgIEZjTWFnbmV0RGlyZWN0aXZlLFxuICAgICAgICBGY0Nvbm5lY3RvckRpcmVjdGl2ZSxcbiAgICAgICAgRmNOb2RlQ29udGFpbmVyQ29tcG9uZW50LFxuICAgICAgICBEZWZhdWx0RmNOb2RlQ29tcG9uZW50XSxcbiAgICBwcm92aWRlcnM6IFtcbiAgICAgICAgRmNNb2RlbFZhbGlkYXRpb25TZXJ2aWNlLFxuICAgICAgICBGY0VkZ2VEcmF3aW5nU2VydmljZSxcbiAgICAgICAge1xuICAgICAgICAgICAgcHJvdmlkZTogRkNfTk9ERV9DT01QT05FTlRfQ09ORklHLFxuICAgICAgICAgICAgdXNlVmFsdWU6IHtcbiAgICAgICAgICAgICAgICBub2RlQ29tcG9uZW50VHlwZTogRGVmYXVsdEZjTm9kZUNvbXBvbmVudFxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXSxcbiAgICBpbXBvcnRzOiBbXG4gICAgICAgIENvbW1vbk1vZHVsZVxuICAgIF0sXG4gICAgZXhwb3J0czogW05neEZsb3djaGFydENvbXBvbmVudCxcbiAgICAgICAgRmNNYWduZXREaXJlY3RpdmUsXG4gICAgICAgIEZjQ29ubmVjdG9yRGlyZWN0aXZlLFxuICAgICAgICBEZWZhdWx0RmNOb2RlQ29tcG9uZW50XVxufSlcbmV4cG9ydCBjbGFzcyBOZ3hGbG93Y2hhcnRNb2R1bGUgeyB9XG4iXX0=
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/lib/scrollparent.mjs:
--------------------------------------------------------------------------------
1 | const regex = /(auto|scroll)/;
2 | const style = (node, prop) => getComputedStyle(node, null).getPropertyValue(prop);
3 | const scroll = (node) => regex.test(style(node, 'overflow') +
4 | style(node, 'overflow-y') +
5 | style(node, 'overflow-x'));
6 | const scrollparent = (node) => !node || node === document.body
7 | ? document.body
8 | : scroll(node)
9 | ? node
10 | : scrollparent(node.parentNode);
11 | export default scrollparent;
12 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nyb2xscGFyZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LWZsb3djaGFydC9zcmMvbGliL3Njcm9sbHBhcmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLEtBQUssR0FBRyxlQUFlLENBQUM7QUFFOUIsTUFBTSxLQUFLLEdBQUcsQ0FBQyxJQUFhLEVBQUUsSUFBWSxFQUFVLEVBQUUsQ0FDcEQsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxDQUFDO0FBRXRELE1BQU0sTUFBTSxHQUFHLENBQUMsSUFBYSxFQUFFLEVBQUUsQ0FDL0IsS0FBSyxDQUFDLElBQUksQ0FDUixLQUFLLENBQUMsSUFBSSxFQUFFLFVBQVUsQ0FBQztJQUN2QixLQUFLLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQztJQUN6QixLQUFLLENBQUMsSUFBSSxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7QUFFL0IsTUFBTSxZQUFZLEdBQUcsQ0FBQyxJQUFpQixFQUFlLEVBQUUsQ0FDdEQsQ0FBQyxJQUFJLElBQUksSUFBSSxLQUFLLFFBQVEsQ0FBQyxJQUFJO0lBQzdCLENBQUMsQ0FBQyxRQUFRLENBQUMsSUFBSTtJQUNmLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDO1FBQ2QsQ0FBQyxDQUFDLElBQUk7UUFDTixDQUFDLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxVQUF5QixDQUFDLENBQUM7QUFFbkQsZUFBZSxZQUFZLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJjb25zdCByZWdleCA9IC8oYXV0b3xzY3JvbGwpLztcblxuY29uc3Qgc3R5bGUgPSAobm9kZTogRWxlbWVudCwgcHJvcDogc3RyaW5nKTogc3RyaW5nID0+XG4gIGdldENvbXB1dGVkU3R5bGUobm9kZSwgbnVsbCkuZ2V0UHJvcGVydHlWYWx1ZShwcm9wKTtcblxuY29uc3Qgc2Nyb2xsID0gKG5vZGU6IEVsZW1lbnQpID0+XG4gIHJlZ2V4LnRlc3QoXG4gICAgc3R5bGUobm9kZSwgJ292ZXJmbG93JykgK1xuICAgIHN0eWxlKG5vZGUsICdvdmVyZmxvdy15JykgK1xuICAgIHN0eWxlKG5vZGUsICdvdmVyZmxvdy14JykpO1xuXG5jb25zdCBzY3JvbGxwYXJlbnQgPSAobm9kZTogSFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudCA9PlxuICAhbm9kZSB8fCBub2RlID09PSBkb2N1bWVudC5ib2R5XG4gICAgPyBkb2N1bWVudC5ib2R5XG4gICAgOiBzY3JvbGwobm9kZSlcbiAgICA/IG5vZGVcbiAgICA6IHNjcm9sbHBhcmVudChub2RlLnBhcmVudE5vZGUgYXMgSFRNTEVsZW1lbnQpO1xuXG5leHBvcnQgZGVmYXVsdCBzY3JvbGxwYXJlbnQ7XG4iXX0=
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/ngx-flowchart.mjs:
--------------------------------------------------------------------------------
1 | /**
2 | * Generated bundle index. Do not edit.
3 | */
4 | export * from './public-api';
5 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWZsb3djaGFydC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25neC1mbG93Y2hhcnQvc3JjL25neC1mbG93Y2hhcnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLGNBQWMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogR2VuZXJhdGVkIGJ1bmRsZSBpbmRleC4gRG8gbm90IGVkaXQuXG4gKi9cblxuZXhwb3J0ICogZnJvbSAnLi9wdWJsaWMtYXBpJztcbiJdfQ==
--------------------------------------------------------------------------------
/dist/ngx-flowchart/esm2022/public-api.mjs:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of ngx-flowchart
3 | */
4 | export * from './lib/ngx-flowchart.component';
5 | export * from './lib/ngx-flowchart.module';
6 | export * from './lib/ngx-flowchart.models';
7 | export { FcNodeComponent } from './lib/node.component';
8 | export { FcMagnetDirective } from './lib/magnet.directive';
9 | export { FcConnectorDirective } from './lib/connector.directive';
10 | export { DefaultFcNodeComponent } from './lib/default-node.component';
11 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL25neC1mbG93Y2hhcnQvc3JjL3B1YmxpYy1hcGkudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0dBRUc7QUFFSCxjQUFjLCtCQUErQixDQUFDO0FBQzlDLGNBQWMsNEJBQTRCLENBQUM7QUFDM0MsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDdkQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDM0QsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDakUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sOEJBQThCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKlxuICogUHVibGljIEFQSSBTdXJmYWNlIG9mIG5neC1mbG93Y2hhcnRcbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2xpYi9uZ3gtZmxvd2NoYXJ0LmNvbXBvbmVudCc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9uZ3gtZmxvd2NoYXJ0Lm1vZHVsZSc7XG5leHBvcnQgKiBmcm9tICcuL2xpYi9uZ3gtZmxvd2NoYXJ0Lm1vZGVscyc7XG5leHBvcnQgeyBGY05vZGVDb21wb25lbnQgfSBmcm9tICcuL2xpYi9ub2RlLmNvbXBvbmVudCc7XG5leHBvcnQgeyBGY01hZ25ldERpcmVjdGl2ZSB9IGZyb20gJy4vbGliL21hZ25ldC5kaXJlY3RpdmUnO1xuZXhwb3J0IHsgRmNDb25uZWN0b3JEaXJlY3RpdmUgfSBmcm9tICcuL2xpYi9jb25uZWN0b3IuZGlyZWN0aXZlJztcbmV4cG9ydCB7IERlZmF1bHRGY05vZGVDb21wb25lbnQgfSBmcm9tICcuL2xpYi9kZWZhdWx0LW5vZGUuY29tcG9uZW50JztcbiJdfQ==
--------------------------------------------------------------------------------
/dist/ngx-flowchart/index.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Generated bundle index. Do not edit.
3 | */
4 | ///
5 | export * from './public-api';
6 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/connector.directive.d.ts:
--------------------------------------------------------------------------------
1 | import { ElementRef, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2 | import { FcCallbacks, FcConnector, FcNodeRectInfo } from './ngx-flowchart.models';
3 | import { FcModelService } from './model.service';
4 | import * as i0 from "@angular/core";
5 | export declare class FcConnectorDirective implements OnInit, OnChanges {
6 | elementRef: ElementRef;
7 | callbacks: FcCallbacks;
8 | modelservice: FcModelService;
9 | connector: FcConnector;
10 | nodeRectInfo: FcNodeRectInfo;
11 | mouseOverConnector: FcConnector;
12 | constructor(elementRef: ElementRef);
13 | ngOnInit(): void;
14 | ngOnChanges(changes: SimpleChanges): void;
15 | private updateConnectorClass;
16 | dragover(event: Event | any): void;
17 | drop(event: Event | any): boolean;
18 | dragend(event: Event | any): void;
19 | dragstart(event: Event | any): void;
20 | mouseenter(event: MouseEvent): void;
21 | mouseleave(event: MouseEvent): void;
22 | static ɵfac: i0.ɵɵFactoryDeclaration;
23 | static ɵdir: i0.ɵɵDirectiveDeclaration;
24 | }
25 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/default-node.component.d.ts:
--------------------------------------------------------------------------------
1 | import { FcNodeComponent } from './node.component';
2 | import * as i0 from "@angular/core";
3 | export declare class DefaultFcNodeComponent extends FcNodeComponent {
4 | constructor();
5 | static ɵfac: i0.ɵɵFactoryDeclaration;
6 | static ɵcmp: i0.ɵɵComponentDeclaration;
7 | }
8 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/edge-dragging.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcModelService } from './model.service';
2 | import { FcConnector, FcCoords, FcEdge, FcModel } from './ngx-flowchart.models';
3 | import { FcEdgeDrawingService } from './edge-drawing.service';
4 | import { FcModelValidationService } from './modelvalidation.service';
5 | export declare class FcEdgeDraggingService {
6 | edgeDragging: EdgeDragging;
7 | private draggedEdgeSource;
8 | private dragOffset;
9 | private destinationHtmlElement;
10 | private oldDisplayStyle;
11 | private readonly modelValidation;
12 | private readonly edgeDrawingService;
13 | private readonly modelService;
14 | private readonly model;
15 | private readonly isValidEdgeCallback;
16 | private readonly applyFunction;
17 | private readonly dragAnimation;
18 | private readonly edgeStyle;
19 | constructor(modelValidation: FcModelValidationService, edgeDrawingService: FcEdgeDrawingService, modelService: FcModelService, model: FcModel, isValidEdgeCallback: (source: FcConnector, destination: FcConnector) => boolean, applyFunction: (fn: (...args: any[]) => T) => T, dragAnimation: string, edgeStyle: string);
20 | dragstart(event: Event | any, connector: FcConnector): void;
21 | dragover(event: Event | any): void;
22 | dragoverConnector(event: Event | any, connector: FcConnector): boolean;
23 | dragleaveMagnet(event: Event | any): void;
24 | dragoverMagnet(event: Event | any, connector: FcConnector): boolean;
25 | dragend(event: Event | any): void;
26 | drop(event: Event | any, targetConnector: FcConnector): boolean;
27 | }
28 | export interface EdgeDragging {
29 | isDragging: boolean;
30 | shadowDragStarted: boolean;
31 | dragPoint1: FcCoords;
32 | dragPoint2: FcCoords;
33 | dragLabel?: string;
34 | prevEdge?: FcEdge;
35 | magnetActive?: boolean;
36 | gElement?: JQuery;
37 | pathElement?: JQuery;
38 | circleElement?: JQuery;
39 | }
40 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/edge-drawing.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcCoords } from './ngx-flowchart.models';
2 | import * as i0 from "@angular/core";
3 | export declare class FcEdgeDrawingService {
4 | constructor();
5 | getEdgeDAttribute(pt1: FcCoords, pt2: FcCoords, style: string): string;
6 | getEdgeCenter(pt1: FcCoords, pt2: FcCoords): FcCoords;
7 | private computeEdgeTangentOffset;
8 | private computeEdgeSourceTangent;
9 | private computeEdgeDestinationTangent;
10 | static ɵfac: i0.ɵɵFactoryDeclaration;
11 | static ɵprov: i0.ɵɵInjectableDeclaration;
12 | }
13 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/magnet.directive.d.ts:
--------------------------------------------------------------------------------
1 | import { ElementRef, OnInit } from '@angular/core';
2 | import { FcCallbacks, FcConnector } from './ngx-flowchart.models';
3 | import * as i0 from "@angular/core";
4 | export declare class FcMagnetDirective implements OnInit {
5 | elementRef: ElementRef;
6 | callbacks: FcCallbacks;
7 | connector: FcConnector;
8 | constructor(elementRef: ElementRef);
9 | ngOnInit(): void;
10 | dragover(event: Event | any): boolean;
11 | dragleave(event: Event | any): void;
12 | drop(event: Event | any): boolean;
13 | dragend(event: Event | any): void;
14 | static ɵfac: i0.ɵɵFactoryDeclaration;
15 | static ɵdir: i0.ɵɵDirectiveDeclaration;
16 | }
17 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/model.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcModelValidationService } from './modelvalidation.service';
2 | import { FcConnector, FcConnectorRectInfo, FcCoords, FcEdge, FcItemInfo, FcModel, FcNode, FcRectBox } from './ngx-flowchart.models';
3 | import { Observable, Subject } from 'rxjs';
4 | import { EventEmitter } from '@angular/core';
5 | interface HtmlElementMap {
6 | [id: string]: HTMLElement;
7 | }
8 | interface ConnectorRectInfoMap {
9 | [id: string]: FcConnectorRectInfo;
10 | }
11 | declare abstract class AbstractFcModel {
12 | modelService: FcModelService;
13 | protected constructor(modelService: FcModelService);
14 | select(object: T): void;
15 | deselect(object: T): void;
16 | toggleSelected(object: T): void;
17 | isSelected(object: T): boolean;
18 | isEdit(object: T): boolean;
19 | }
20 | declare class ConnectorsModel extends AbstractFcModel {
21 | constructor(modelService: FcModelService);
22 | getConnector(connectorId: string): FcConnector;
23 | getConnectorRectInfo(connectorId: string): FcConnectorRectInfo;
24 | setConnectorRectInfo(connectorId: string, connectorRectInfo: FcConnectorRectInfo): void;
25 | private _getCoords;
26 | getCoords(connectorId: string): FcCoords;
27 | getCenteredCoord(connectorId: string): FcCoords;
28 | }
29 | declare class NodesModel extends AbstractFcModel {
30 | constructor(modelService: FcModelService);
31 | getConnectorsByType(node: FcNode, type: string): Array;
32 | private _addConnector;
33 | delete(node: FcNode): void;
34 | getSelectedNodes(): Array;
35 | handleClicked(node: FcNode, ctrlKey?: boolean): void;
36 | private _addNode;
37 | getConnectorIds(node: FcNode): Array;
38 | getNodeByConnectorId(connectorId: string): FcNode;
39 | getHtmlElement(nodeId: string): HTMLElement;
40 | setHtmlElement(nodeId: string, element: HTMLElement): void;
41 | }
42 | declare class EdgesModel extends AbstractFcModel {
43 | constructor(modelService: FcModelService);
44 | sourceCoord(edge: FcEdge): FcCoords;
45 | destCoord(edge: FcEdge): FcCoords;
46 | delete(edge: FcEdge): void;
47 | getSelectedEdges(): Array;
48 | handleEdgeMouseClick(edge: FcEdge, ctrlKey?: boolean): void;
49 | putEdge(edge: FcEdge): void;
50 | _addEdge(event: Event, sourceConnector: FcConnector, destConnector: FcConnector, label: string): void;
51 | }
52 | export declare class FcModelService {
53 | modelValidation: FcModelValidationService;
54 | model: FcModel;
55 | private readonly detectChangesSubject;
56 | selectedObjects: any[];
57 | connectorsRectInfos: ConnectorRectInfoMap;
58 | nodesHtmlElements: HtmlElementMap;
59 | canvasHtmlElement: HTMLElement;
60 | dragImage: HTMLImageElement;
61 | svgHtmlElement: SVGElement;
62 | dropNode: (event: Event, node: FcNode) => void;
63 | createEdge: (event: Event, edge: FcEdge) => Observable;
64 | edgeAddedCallback: (edge: FcEdge) => void;
65 | nodeRemovedCallback: (node: FcNode) => void;
66 | edgeRemovedCallback: (edge: FcEdge) => void;
67 | dropTargetId: string;
68 | private readonly modelChanged;
69 | private readonly debouncer;
70 | connectors: ConnectorsModel;
71 | nodes: NodesModel;
72 | edges: EdgesModel;
73 | constructor(modelValidation: FcModelValidationService, model: FcModel, modelChanged: EventEmitter, detectChangesSubject: Subject, selectedObjects: any[], dropNode: (event: Event, node: FcNode) => void, createEdge: (event: Event, edge: FcEdge) => Observable, edgeAddedCallback: (edge: FcEdge) => void, nodeRemovedCallback: (node: FcNode) => void, edgeRemovedCallback: (edge: FcEdge) => void, canvasHtmlElement: HTMLElement, svgHtmlElement: SVGElement);
74 | notifyModelChanged(): void;
75 | detectChanges(): void;
76 | selectObject(object: any): void;
77 | deselectObject(object: any): void;
78 | toggleSelectedObject(object: any): void;
79 | isSelectedObject(object: any): boolean;
80 | selectAll(): void;
81 | deselectAll(): void;
82 | isEditObject(object: any): boolean;
83 | private inRectBox;
84 | getItemInfoAtPoint(x: number, y: number): FcItemInfo;
85 | getNodeAtPoint(x: number, y: number): FcNode;
86 | getEdgeAtPoint(x: number, y: number): FcEdge;
87 | selectAllInRect(rectBox: FcRectBox): void;
88 | deleteSelected(): void;
89 | isEditable(): boolean;
90 | isDropSource(): boolean;
91 | getDragImage(): HTMLImageElement;
92 | }
93 | export {};
94 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/modelvalidation.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcConnector, FcEdge, FcModel, FcNode } from './ngx-flowchart.models';
2 | import * as i0 from "@angular/core";
3 | export declare class FcModelValidationService {
4 | constructor();
5 | validateModel(model: FcModel): FcModel;
6 | validateNodes(nodes: Array): Array;
7 | validateNode(node: FcNode): FcNode;
8 | private _validateEdges;
9 | validateEdges(edges: Array, nodes: Array): Array;
10 | private _validateEdge;
11 | validateEdge(edge: FcEdge, nodes: Array): FcEdge;
12 | validateConnector(connector: FcConnector): FcConnector;
13 | static ɵfac: i0.ɵɵFactoryDeclaration;
14 | static ɵprov: i0.ɵɵInjectableDeclaration;
15 | }
16 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/mouseover.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcConnector, FcEdge, FcNode } from './ngx-flowchart.models';
2 | export declare class FcMouseOverService {
3 | mouseoverscope: MouseOverScope;
4 | private readonly applyFunction;
5 | constructor(applyFunction: (fn: (...args: any[]) => T) => T);
6 | nodeMouseOver(event: MouseEvent, node: FcNode): void;
7 | nodeMouseOut(event: MouseEvent, node: FcNode): void;
8 | connectorMouseEnter(event: MouseEvent, connector: FcConnector): void;
9 | connectorMouseLeave(event: MouseEvent, connector: FcConnector): void;
10 | edgeMouseEnter(event: MouseEvent, edge: FcEdge): void;
11 | edgeMouseLeave(event: MouseEvent, edge: FcEdge): void;
12 | }
13 | export interface MouseOverScope {
14 | connector: FcConnector;
15 | edge: FcEdge;
16 | node: FcNode;
17 | }
18 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/ngx-flowchart.component.d.ts:
--------------------------------------------------------------------------------
1 | import { ChangeDetectorRef, DoCheck, ElementRef, EventEmitter, IterableDiffers, NgZone, OnInit } from '@angular/core';
2 | import { FcCallbacks, FcEdge, FcModel, UserCallbacks, UserNodeCallbacks } from './ngx-flowchart.models';
3 | import { FcModelService } from './model.service';
4 | import { FcModelValidationService } from './modelvalidation.service';
5 | import { FcNodeDraggingService } from './node-dragging.service';
6 | import { FcEdgeDrawingService } from './edge-drawing.service';
7 | import { FcEdgeDraggingService } from './edge-dragging.service';
8 | import { FcMouseOverService } from './mouseover.service';
9 | import { FcRectangleSelectService } from './rectangleselect.service';
10 | import * as i0 from "@angular/core";
11 | export declare class NgxFlowchartComponent implements OnInit, DoCheck {
12 | private elementRef;
13 | private differs;
14 | private modelValidation;
15 | edgeDrawingService: FcEdgeDrawingService;
16 | private cd;
17 | private zone;
18 | get canvasClass(): string;
19 | model: FcModel;
20 | selectedObjects: any[];
21 | edgeStyle: string;
22 | userCallbacks: UserCallbacks;
23 | automaticResize: boolean;
24 | dragAnimation: string;
25 | nodeWidth: number;
26 | nodeHeight: number;
27 | dropTargetId: string;
28 | modelChanged: EventEmitter;
29 | private fitModelSizeByDefaultValue;
30 | get fitModelSizeByDefault(): boolean;
31 | set fitModelSizeByDefault(value: boolean);
32 | callbacks: FcCallbacks;
33 | userNodeCallbacks: UserNodeCallbacks;
34 | modelService: FcModelService;
35 | nodeDraggingService: FcNodeDraggingService;
36 | edgeDraggingService: FcEdgeDraggingService;
37 | mouseoverService: FcMouseOverService;
38 | rectangleSelectService: FcRectangleSelectService;
39 | arrowDefId: string;
40 | arrowDefIdSelected: string;
41 | flowchartConstants: {
42 | htmlPrefix: string;
43 | leftConnectorType: string;
44 | rightConnectorType: string;
45 | curvedStyle: string;
46 | lineStyle: string;
47 | dragAnimationRepaint: string;
48 | dragAnimationShadow: string;
49 | canvasClass: string;
50 | selectedClass: string;
51 | editClass: string;
52 | activeClass: string;
53 | hoverClass: string;
54 | draggingClass: string;
55 | edgeClass: string;
56 | edgeLabelClass: string;
57 | connectorClass: string;
58 | magnetClass: string;
59 | nodeClass: string;
60 | nodeOverlayClass: string;
61 | leftConnectorClass: string;
62 | rightConnectorClass: string;
63 | canvasResizeThreshold: number;
64 | canvasResizeStep: number;
65 | };
66 | private nodesDiffer;
67 | private edgesDiffer;
68 | private readonly detectChangesSubject;
69 | constructor(elementRef: ElementRef, differs: IterableDiffers, modelValidation: FcModelValidationService, edgeDrawingService: FcEdgeDrawingService, cd: ChangeDetectorRef, zone: NgZone);
70 | ngOnInit(): void;
71 | ngDoCheck(): void;
72 | getEdgeDAttribute(edge: FcEdge): string;
73 | adjustCanvasSize(fit?: boolean): void;
74 | canvasClick(event: MouseEvent): void;
75 | edgeMouseDown(event: MouseEvent, edge: FcEdge): void;
76 | edgeClick(event: MouseEvent, edge: FcEdge): void;
77 | edgeRemove(event: Event, edge: FcEdge): void;
78 | edgeEdit(event: Event, edge: FcEdge): void;
79 | edgeDoubleClick(event: MouseEvent, edge: FcEdge): void;
80 | edgeMouseOver(event: MouseEvent, edge: FcEdge): void;
81 | edgeMouseEnter(event: MouseEvent, edge: FcEdge): void;
82 | edgeMouseLeave(event: MouseEvent, edge: FcEdge): void;
83 | dragover(event: Event | any): void;
84 | drop(event: Event | any): void;
85 | mousedown(event: MouseEvent): void;
86 | mousemove(event: MouseEvent): void;
87 | mouseup(event: MouseEvent): void;
88 | static ɵfac: i0.ɵɵFactoryDeclaration;
89 | static ɵcmp: i0.ɵɵComponentDeclaration;
90 | }
91 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/ngx-flowchart.models.d.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { InjectionToken, Type } from '@angular/core';
3 | import { FcNodeComponent } from './node.component';
4 | export declare const FC_NODE_COMPONENT_CONFIG: InjectionToken;
5 | export interface FcNodeComponentConfig {
6 | nodeComponentType: Type;
7 | }
8 | export declare const FlowchartConstants: {
9 | htmlPrefix: string;
10 | leftConnectorType: string;
11 | rightConnectorType: string;
12 | curvedStyle: string;
13 | lineStyle: string;
14 | dragAnimationRepaint: string;
15 | dragAnimationShadow: string;
16 | canvasClass: string;
17 | selectedClass: string;
18 | editClass: string;
19 | activeClass: string;
20 | hoverClass: string;
21 | draggingClass: string;
22 | edgeClass: string;
23 | edgeLabelClass: string;
24 | connectorClass: string;
25 | magnetClass: string;
26 | nodeClass: string;
27 | nodeOverlayClass: string;
28 | leftConnectorClass: string;
29 | rightConnectorClass: string;
30 | canvasResizeThreshold: number;
31 | canvasResizeStep: number;
32 | };
33 | export interface FcCoords {
34 | x?: number;
35 | y?: number;
36 | }
37 | export interface FcRectBox {
38 | top: number;
39 | left: number;
40 | right: number;
41 | bottom: number;
42 | }
43 | export interface FcConnector {
44 | id: string;
45 | type: string;
46 | }
47 | export interface FcNode extends FcCoords {
48 | id: string;
49 | name: string;
50 | connectors: Array;
51 | readonly?: boolean;
52 | [key: string]: any;
53 | }
54 | export interface FcNodeRectInfo {
55 | width(): number;
56 | height(): number;
57 | top(): number;
58 | left(): number;
59 | right(): number;
60 | bottom(): number;
61 | }
62 | export interface FcConnectorRectInfo {
63 | type: string;
64 | width: number;
65 | height: number;
66 | nodeRectInfo: FcNodeRectInfo;
67 | }
68 | export interface FcEdge {
69 | label?: string;
70 | source?: string;
71 | destination?: string;
72 | active?: boolean;
73 | }
74 | export interface FcItemInfo {
75 | node?: FcNode;
76 | edge?: FcEdge;
77 | }
78 | export interface FcModel {
79 | nodes: Array;
80 | edges: Array;
81 | }
82 | export interface UserCallbacks {
83 | dropNode?: (event: Event, node: FcNode) => void;
84 | createEdge?: (event: Event, edge: FcEdge) => Observable;
85 | edgeAdded?: (edge: FcEdge) => void;
86 | nodeRemoved?: (node: FcNode) => void;
87 | edgeRemoved?: (edge: FcEdge) => void;
88 | edgeDoubleClick?: (event: MouseEvent, edge: FcEdge) => void;
89 | edgeMouseOver?: (event: MouseEvent, edge: FcEdge) => void;
90 | isValidEdge?: (source: FcConnector, destination: FcConnector) => boolean;
91 | edgeEdit?: (event: Event, edge: FcEdge) => void;
92 | nodeCallbacks?: UserNodeCallbacks;
93 | }
94 | export interface UserNodeCallbacks {
95 | nodeEdit?: (event: MouseEvent, node: FcNode) => void;
96 | doubleClick?: (event: MouseEvent, node: FcNode) => void;
97 | mouseDown?: (event: MouseEvent, node: FcNode) => void;
98 | mouseEnter?: (event: MouseEvent, node: FcNode) => void;
99 | mouseLeave?: (event: MouseEvent, node: FcNode) => void;
100 | }
101 | export interface FcCallbacks {
102 | nodeDragstart: (event: Event | any, node: FcNode) => void;
103 | nodeDragend: (event: Event | any) => void;
104 | edgeDragstart: (event: Event | any, connector: FcConnector) => void;
105 | edgeDragend: (event: Event | any) => void;
106 | edgeDrop: (event: Event | any, targetConnector: FcConnector) => boolean;
107 | edgeDragoverConnector: (event: Event | any, connector: FcConnector) => boolean;
108 | edgeDragoverMagnet: (event: Event | any, connector: FcConnector) => boolean;
109 | edgeDragleaveMagnet: (event: Event | any) => void;
110 | nodeMouseOver: (event: MouseEvent, node: FcNode) => void;
111 | nodeMouseOut: (event: MouseEvent, node: FcNode) => void;
112 | connectorMouseEnter: (event: MouseEvent, connector: FcConnector) => void;
113 | connectorMouseLeave: (event: MouseEvent, connector: FcConnector) => void;
114 | nodeClicked: (event: MouseEvent, node: FcNode) => void;
115 | }
116 | export interface FcAdjacentList {
117 | [id: string]: {
118 | incoming: number;
119 | outgoing: Array;
120 | };
121 | }
122 | declare class BaseError {
123 | constructor();
124 | }
125 | export declare class ModelvalidationError extends BaseError {
126 | message: string;
127 | constructor(message: string);
128 | }
129 | export declare const fcTopSort: (graph: FcModel) => Array | null;
130 | export {};
131 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/ngx-flowchart.module.d.ts:
--------------------------------------------------------------------------------
1 | import * as i0 from "@angular/core";
2 | import * as i1 from "./ngx-flowchart.component";
3 | import * as i2 from "./magnet.directive";
4 | import * as i3 from "./connector.directive";
5 | import * as i4 from "./node.component";
6 | import * as i5 from "./default-node.component";
7 | import * as i6 from "@angular/common";
8 | export declare class NgxFlowchartModule {
9 | static ɵfac: i0.ɵɵFactoryDeclaration;
10 | static ɵmod: i0.ɵɵNgModuleDeclaration;
11 | static ɵinj: i0.ɵɵInjectorDeclaration;
12 | }
13 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/node-dragging.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcModelService } from './model.service';
2 | import { FcNode } from './ngx-flowchart.models';
3 | export declare class FcNodeDraggingService {
4 | nodeDraggingScope: NodeDraggingScope;
5 | private dragOffsets;
6 | private draggedElements;
7 | private destinationHtmlElements;
8 | private oldDisplayStyles;
9 | private readonly modelService;
10 | private readonly automaticResize;
11 | private readonly dragAnimation;
12 | private readonly applyFunction;
13 | constructor(modelService: FcModelService, applyFunction: (fn: (...args: any[]) => T) => T, automaticResize: boolean, dragAnimation: string);
14 | private getCoordinate;
15 | private getXCoordinate;
16 | private getYCoordinate;
17 | private resizeCanvas;
18 | isDraggingNode(node: FcNode): boolean;
19 | dragstart(event: Event | any, node: FcNode): void;
20 | drop(event: Event | any): boolean;
21 | dragover(event: Event | any): boolean;
22 | dragend(event: Event | any): void;
23 | }
24 | export interface NodeDraggingScope {
25 | draggedNodes: Array;
26 | shadowElements: Array>;
27 | shadowDragStarted: boolean;
28 | dropElement: HTMLElement;
29 | }
30 | export interface NodeDropElement extends HTMLElement {
31 | offsetInfo?: {
32 | offsetX: number;
33 | offsetY: number;
34 | };
35 | }
36 | export interface NodeDropScope {
37 | dropElement: NodeDropElement;
38 | }
39 | export interface DropNodeInfo {
40 | node: FcNode;
41 | dropTargetId: string;
42 | offsetX: number;
43 | offsetY: number;
44 | }
45 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/node.component.d.ts:
--------------------------------------------------------------------------------
1 | import { AfterViewInit, ComponentFactoryResolver, ElementRef, OnChanges, OnInit, SimpleChanges, ViewContainerRef } from '@angular/core';
2 | import { FcCallbacks, FcConnector, FcNode, FcNodeComponentConfig, FcNodeRectInfo, UserNodeCallbacks } from './ngx-flowchart.models';
3 | import { FcModelService } from './model.service';
4 | import * as i0 from "@angular/core";
5 | export declare class FcNodeContainerComponent implements OnInit, AfterViewInit, OnChanges {
6 | private nodeComponentConfig;
7 | private elementRef;
8 | private componentFactoryResolver;
9 | callbacks: FcCallbacks;
10 | userNodeCallbacks: UserNodeCallbacks;
11 | node: FcNode;
12 | selected: boolean;
13 | edit: boolean;
14 | underMouse: boolean;
15 | mouseOverConnector: FcConnector;
16 | modelservice: FcModelService;
17 | dragging: boolean;
18 | get nodeId(): string;
19 | get top(): string;
20 | get left(): string;
21 | nodeComponent: FcNodeComponent;
22 | nodeContentContainer: ViewContainerRef;
23 | constructor(nodeComponentConfig: FcNodeComponentConfig, elementRef: ElementRef, componentFactoryResolver: ComponentFactoryResolver);
24 | ngOnInit(): void;
25 | ngAfterViewInit(): void;
26 | ngOnChanges(changes: SimpleChanges): void;
27 | private updateNodeClass;
28 | private updateNodeComponent;
29 | private toggleClass;
30 | mousedown(event: MouseEvent): void;
31 | dragstart(event: Event | any): void;
32 | dragend(event: Event | any): void;
33 | click(event: MouseEvent): void;
34 | mouseover(event: MouseEvent): void;
35 | mouseout(event: MouseEvent): void;
36 | static ɵfac: i0.ɵɵFactoryDeclaration;
37 | static ɵcmp: i0.ɵɵComponentDeclaration;
38 | }
39 | export declare abstract class FcNodeComponent implements OnInit {
40 | callbacks: FcCallbacks;
41 | userNodeCallbacks: UserNodeCallbacks;
42 | node: FcNode;
43 | selected: boolean;
44 | edit: boolean;
45 | underMouse: boolean;
46 | mouseOverConnector: FcConnector;
47 | modelservice: FcModelService;
48 | dragging: boolean;
49 | flowchartConstants: {
50 | htmlPrefix: string;
51 | leftConnectorType: string;
52 | rightConnectorType: string;
53 | curvedStyle: string;
54 | lineStyle: string;
55 | dragAnimationRepaint: string;
56 | dragAnimationShadow: string;
57 | canvasClass: string;
58 | selectedClass: string;
59 | editClass: string;
60 | activeClass: string;
61 | hoverClass: string;
62 | draggingClass: string;
63 | edgeClass: string;
64 | edgeLabelClass: string;
65 | connectorClass: string;
66 | magnetClass: string;
67 | nodeClass: string;
68 | nodeOverlayClass: string;
69 | leftConnectorClass: string;
70 | rightConnectorClass: string;
71 | canvasResizeThreshold: number;
72 | canvasResizeStep: number;
73 | };
74 | width: number;
75 | height: number;
76 | nodeRectInfo: FcNodeRectInfo;
77 | ngOnInit(): void;
78 | static ɵfac: i0.ɵɵFactoryDeclaration;
79 | static ɵdir: i0.ɵɵDirectiveDeclaration;
80 | }
81 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/rectangleselect.service.d.ts:
--------------------------------------------------------------------------------
1 | import { FcModelService } from './model.service';
2 | export declare class FcRectangleSelectService {
3 | private readonly selectRect;
4 | private readonly modelService;
5 | private readonly selectElement;
6 | private readonly $canvasElement;
7 | private readonly $scrollParent;
8 | private readonly applyFunction;
9 | constructor(modelService: FcModelService, selectElement: HTMLElement, applyFunction: (fn: (...args: any[]) => T) => T);
10 | mousedown(e: MouseEvent): void;
11 | mousemove(e: MouseEvent): void;
12 | private updateScroll;
13 | mouseup(e: MouseEvent): void;
14 | private updateSelectRect;
15 | private selectObjects;
16 | }
17 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/lib/scrollparent.d.ts:
--------------------------------------------------------------------------------
1 | declare const scrollparent: (node: HTMLElement) => HTMLElement;
2 | export default scrollparent;
3 |
--------------------------------------------------------------------------------
/dist/ngx-flowchart/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-flowchart",
3 | "version": "2.0.0",
4 | "peerDependencies": {
5 | "@angular/common": "^18.2.6",
6 | "@angular/core": "^18.2.6",
7 | "jquery": "^3.7.1"
8 | },
9 | "module": "fesm2022/ngx-flowchart.mjs",
10 | "typings": "index.d.ts",
11 | "exports": {
12 | "./package.json": {
13 | "default": "./package.json"
14 | },
15 | ".": {
16 | "types": "./index.d.ts",
17 | "esm2022": "./esm2022/ngx-flowchart.mjs",
18 | "esm": "./esm2022/ngx-flowchart.mjs",
19 | "default": "./fesm2022/ngx-flowchart.mjs"
20 | }
21 | },
22 | "sideEffects": false,
23 | "dependencies": {
24 | "tslib": "^2.3.0"
25 | }
26 | }
--------------------------------------------------------------------------------
/dist/ngx-flowchart/public-api.d.ts:
--------------------------------------------------------------------------------
1 | export * from './lib/ngx-flowchart.component';
2 | export * from './lib/ngx-flowchart.module';
3 | export * from './lib/ngx-flowchart.models';
4 | export { FcNodeComponent } from './lib/node.component';
5 | export { FcMagnetDirective } from './lib/magnet.directive';
6 | export { FcConnectorDirective } from './lib/connector.directive';
7 | export { DefaultFcNodeComponent } from './lib/default-node.component';
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-flowchart-demo",
3 | "version": "3.0.0",
4 | "scripts": {
5 | "ng": "ng",
6 | "start": "ng serve --host 0.0.0.0 --open --port 4300",
7 | "build": "ng build ngx-flowchart --configuration production",
8 | "lint": "ng lint"
9 | },
10 | "private": true,
11 | "peerDependencies": {
12 | "jquery": "^3.7.1"
13 | },
14 | "devDependencies": {
15 | "@angular-devkit/build-angular": "18.2.6",
16 | "@angular-devkit/core": "18.2.6",
17 | "@angular-devkit/schematics": "18.2.6",
18 | "@angular-eslint/builder": "18.3.1",
19 | "@angular-eslint/eslint-plugin": "18.3.1",
20 | "@angular-eslint/eslint-plugin-template": "18.3.1",
21 | "@angular-eslint/schematics": "18.3.1",
22 | "@angular-eslint/template-parser": "18.3.1",
23 | "@angular/animations": "^18.2.6",
24 | "@angular/cdk": "^18.2.6",
25 | "@angular/cli": "^18.2.6",
26 | "@angular/common": "^18.2.6",
27 | "@angular/compiler": "^18.2.6",
28 | "@angular/compiler-cli": "^18.2.6",
29 | "@angular/core": "^18.2.6",
30 | "@angular/forms": "^18.2.6",
31 | "@angular/platform-browser": "^18.2.6",
32 | "@angular/platform-browser-dynamic": "^18.2.6",
33 | "@angular/router": "^18.2.6",
34 | "@types/jquery": "^3.5.31",
35 | "@types/node": "~20.16.9",
36 | "@typescript-eslint/eslint-plugin": "^8.7.0",
37 | "@typescript-eslint/parser": "^8.7.0",
38 | "@typescript-eslint/utils": "8.7.0",
39 | "eslint": "^9.11.1",
40 | "eslint-plugin-import": "latest",
41 | "eslint-plugin-jsdoc": "latest",
42 | "eslint-plugin-prefer-arrow": "latest",
43 | "jquery": "^3.7.1",
44 | "ng-packagr": "~18.2.1",
45 | "rxjs": "~7.8.1",
46 | "ts-node": "^10.9.2",
47 | "typescript": "~5.5.4",
48 | "zone.js": "~0.14.10"
49 | },
50 | "dependencies": {
51 | "tslib": "^2.7.0"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../.eslintrc.json",
3 | "ignorePatterns": [
4 | "!**/*"
5 | ],
6 | "overrides": [
7 | {
8 | "files": [
9 | "*.ts"
10 | ],
11 | "parserOptions": {
12 | "project": [
13 | "projects/ngx-flowchart/tsconfig.lib.json"
14 | ],
15 | "createDefaultProgram": true
16 | },
17 | "rules": {
18 | "@angular-eslint/directive-selector": [
19 | "error",
20 | {
21 | "type": "attribute",
22 | "prefix": "lib",
23 | "style": "camelCase"
24 | }
25 | ],
26 | "@angular-eslint/component-selector": [
27 | "error",
28 | {
29 | "type": "element",
30 | "prefix": "lib",
31 | "style": "kebab-case"
32 | }
33 | ],
34 | "no-underscore-dangle": "off"
35 | }
36 | },
37 | {
38 | "files": [
39 | "*.html"
40 | ],
41 | "rules": {}
42 | }
43 | ]
44 | }
45 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/README.md:
--------------------------------------------------------------------------------
1 | # NgxFlowchart
2 |
3 | This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 14.2.0.
4 |
5 | ## Code scaffolding
6 |
7 | Run `ng generate component component-name --project ngx-flowchart` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project ngx-flowchart`.
8 | > Note: Don't forget to add `--project ngx-flowchart` or else it will be added to the default project in your `angular.json` file.
9 |
10 | ## Build
11 |
12 | Run `ng build ngx-flowchart` to build the project. The build artifacts will be stored in the `dist/` directory.
13 |
14 | ## Publishing
15 |
16 | After building your library with `ng build ngx-flowchart`, go to the dist folder `cd dist/ngx-flowchart` and run `npm publish`.
17 |
18 | ## Further help
19 |
20 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
21 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/ng-package.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
3 | "dest": "../../dist/ngx-flowchart",
4 | "deleteDestPath": false,
5 | "lib": {
6 | "entryFile": "src/public-api.ts"
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-flowchart",
3 | "version": "3.0.0",
4 | "peerDependencies": {
5 | "@angular/common": "^18.2.6",
6 | "@angular/core": "^18.2.6",
7 | "jquery": "^3.7.1"
8 | },
9 | "devDependencies": {
10 | "@types/jquery": "^3.5.31"
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/connector.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, HostListener, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2 | import { FcCallbacks, FcConnector, FcConnectorRectInfo, FcNodeRectInfo, FlowchartConstants } from './ngx-flowchart.models';
3 | import { FcModelService } from './model.service';
4 |
5 | @Directive({
6 | // eslint-disable-next-line @angular-eslint/directive-selector
7 | selector: '[fc-connector]'
8 | })
9 | export class FcConnectorDirective implements OnInit, OnChanges {
10 |
11 | @Input()
12 | callbacks: FcCallbacks;
13 |
14 | @Input()
15 | modelservice: FcModelService;
16 |
17 | @Input()
18 | connector: FcConnector;
19 |
20 | @Input()
21 | nodeRectInfo: FcNodeRectInfo;
22 |
23 | @Input()
24 | mouseOverConnector: FcConnector;
25 |
26 | constructor(public elementRef: ElementRef) {
27 | }
28 |
29 | ngOnInit(): void {
30 | const element = $(this.elementRef.nativeElement);
31 | element.addClass(FlowchartConstants.connectorClass);
32 | if (this.modelservice.isEditable()) {
33 | element.attr('draggable', 'true');
34 | this.updateConnectorClass();
35 | }
36 | const connectorRectInfo: FcConnectorRectInfo = {
37 | type: this.connector.type,
38 | width: this.elementRef.nativeElement.offsetWidth,
39 | height: this.elementRef.nativeElement.offsetHeight,
40 | nodeRectInfo: this.nodeRectInfo
41 | };
42 | this.modelservice.connectors.setConnectorRectInfo(this.connector.id, connectorRectInfo);
43 | }
44 |
45 | ngOnChanges(changes: SimpleChanges): void {
46 | let updateConnector = false;
47 | for (const propName of Object.keys(changes)) {
48 | const change = changes[propName];
49 | if (!change.firstChange && change.currentValue !== change.previousValue) {
50 | if (propName === 'mouseOverConnector') {
51 | updateConnector = true;
52 | }
53 | }
54 | }
55 | if (updateConnector && this.modelservice.isEditable()) {
56 | this.updateConnectorClass();
57 | }
58 | }
59 |
60 | private updateConnectorClass() {
61 | const element = $(this.elementRef.nativeElement);
62 | if (this.connector === this.mouseOverConnector) {
63 | element.addClass(FlowchartConstants.hoverClass);
64 | } else {
65 | element.removeClass(FlowchartConstants.hoverClass);
66 | }
67 | }
68 |
69 | @HostListener('dragover', ['$event'])
70 | dragover(event: Event | any) {
71 | // Skip - conflict with magnet
72 | /* if (this.modelservice.isEditable()) {
73 | return this.callbacks.edgeDragoverConnector(event, this.connector);
74 | }*/
75 | }
76 |
77 | @HostListener('drop', ['$event'])
78 | drop(event: Event | any) {
79 | if (this.modelservice.isEditable()) {
80 | return this.callbacks.edgeDrop(event, this.connector);
81 | }
82 | }
83 |
84 | @HostListener('dragend', ['$event'])
85 | dragend(event: Event | any) {
86 | if (this.modelservice.isEditable()) {
87 | this.callbacks.edgeDragend(event);
88 | }
89 | }
90 |
91 | @HostListener('dragstart', ['$event'])
92 | dragstart(event: Event | any) {
93 | if (this.modelservice.isEditable()) {
94 | this.callbacks.edgeDragstart(event, this.connector);
95 | }
96 | }
97 |
98 | @HostListener('mouseenter', ['$event'])
99 | mouseenter(event: MouseEvent) {
100 | if (this.modelservice.isEditable()) {
101 | this.callbacks.connectorMouseEnter(event, this.connector);
102 | }
103 | }
104 |
105 | @HostListener('mouseleave', ['$event'])
106 | mouseleave(event: MouseEvent) {
107 | if (this.modelservice.isEditable()) {
108 | this.callbacks.connectorMouseLeave(event, this.connector);
109 | }
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/default-node.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
{{ node.name }}
6 |
7 |
17 |
27 |
28 |
29 |
30 |
31 |
32 | ×
33 |
34 |
35 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/default-node.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 |
3 | .fc-node-overlay {
4 | position: absolute;
5 | pointer-events: none;
6 | left: 0;
7 | top: 0;
8 | right: 0;
9 | bottom: 0;
10 | background-color: #000;
11 | opacity: 0;
12 | }
13 |
14 | :host-context(.fc-hover) .fc-node-overlay {
15 | opacity: 0.25;
16 | transition: opacity .2s;
17 | }
18 |
19 | :host-context(.fc-selected) .fc-node-overlay {
20 | opacity: 0.25;
21 | }
22 |
23 | .innerNode {
24 | display: flex;
25 | justify-content: center;
26 | align-items: center;
27 | min-width: 100px;
28 | border-radius: 5px;
29 |
30 | background-color: #F15B26;
31 | color: #fff;
32 | font-size: 16px;
33 | pointer-events: none;
34 |
35 | p {
36 | padding: 0 15px;
37 | text-align: center;
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/default-node.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { FcNodeComponent } from './node.component';
3 |
4 | @Component({
5 | // eslint-disable-next-line @angular-eslint/component-selector
6 | selector: 'fc-default-node',
7 | templateUrl: './default-node.component.html',
8 | styleUrls: ['./default-node.component.scss']
9 | })
10 | export class DefaultFcNodeComponent extends FcNodeComponent {
11 |
12 | constructor() {
13 | super();
14 | }
15 |
16 | }
17 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/edge-dragging.service.ts:
--------------------------------------------------------------------------------
1 | import { FcModelService } from './model.service';
2 | import { FcConnector, FcCoords, FcEdge, FcModel, FlowchartConstants, ModelvalidationError } from './ngx-flowchart.models';
3 | import { FcEdgeDrawingService } from './edge-drawing.service';
4 | import { FcModelValidationService } from './modelvalidation.service';
5 |
6 | export class FcEdgeDraggingService {
7 |
8 | edgeDragging: EdgeDragging = {
9 | isDragging: false,
10 | dragPoint1: null,
11 | dragPoint2: null,
12 | shadowDragStarted: false
13 | };
14 |
15 | private draggedEdgeSource: FcConnector = null;
16 | private dragOffset: FcCoords = {};
17 | private destinationHtmlElement: HTMLElement = null;
18 | private oldDisplayStyle = '';
19 |
20 | private readonly modelValidation: FcModelValidationService;
21 | private readonly edgeDrawingService: FcEdgeDrawingService;
22 | private readonly modelService: FcModelService;
23 | private readonly model: FcModel;
24 | private readonly isValidEdgeCallback: (source: FcConnector, destination: FcConnector) => boolean;
25 | private readonly applyFunction: (fn: (...args: any[]) => T) => T;
26 | private readonly dragAnimation: string;
27 | private readonly edgeStyle: string;
28 |
29 | constructor(modelValidation: FcModelValidationService,
30 | edgeDrawingService: FcEdgeDrawingService,
31 | modelService: FcModelService,
32 | model: FcModel,
33 | isValidEdgeCallback: (source: FcConnector, destination: FcConnector) => boolean,
34 | applyFunction: (fn: (...args: any[]) => T) => T,
35 | dragAnimation: string,
36 | edgeStyle: string) {
37 | this.modelValidation = modelValidation;
38 | this.edgeDrawingService = edgeDrawingService;
39 | this.modelService = modelService;
40 | this.model = model;
41 | this.isValidEdgeCallback = isValidEdgeCallback || (() => true);
42 | this.applyFunction = applyFunction;
43 | this.dragAnimation = dragAnimation;
44 | this.edgeStyle = edgeStyle;
45 | }
46 |
47 | public dragstart(event: Event | any, connector: FcConnector) {
48 | let swapConnector: FcConnector;
49 | let dragLabel: string;
50 | let prevEdge: FcEdge;
51 | if (connector.type === FlowchartConstants.leftConnectorType) {
52 | for (const edge of this.model.edges) {
53 | if (edge.destination === connector.id) {
54 | swapConnector = this.modelService.connectors.getConnector(edge.source);
55 | dragLabel = edge.label;
56 | prevEdge = edge;
57 | this.applyFunction(() => {
58 | this.modelService.edges.delete(edge);
59 | });
60 | break;
61 | }
62 | }
63 | }
64 | this.edgeDragging.isDragging = true;
65 | if (swapConnector !== undefined) {
66 | this.draggedEdgeSource = swapConnector;
67 | this.edgeDragging.dragPoint1 = this.modelService.connectors.getCenteredCoord(swapConnector.id);
68 | this.edgeDragging.dragLabel = dragLabel;
69 | this.edgeDragging.prevEdge = prevEdge;
70 | } else {
71 | this.draggedEdgeSource = connector;
72 | this.edgeDragging.dragPoint1 = this.modelService.connectors.getCenteredCoord(connector.id);
73 | }
74 | const canvas = this.modelService.canvasHtmlElement;
75 | if (!canvas) {
76 | throw new Error('No canvas while edgedraggingService found.');
77 | }
78 | this.dragOffset.x = -canvas.getBoundingClientRect().left;
79 | this.dragOffset.y = -canvas.getBoundingClientRect().top;
80 |
81 | this.edgeDragging.dragPoint2 = {
82 | x: event.clientX + this.dragOffset.x,
83 | y: event.clientY + this.dragOffset.y
84 | };
85 | const originalEvent: Event | any = (event as any).originalEvent || event;
86 |
87 | originalEvent.dataTransfer.setData('Text', 'Just to support firefox');
88 | if (originalEvent.dataTransfer.setDragImage) {
89 | originalEvent.dataTransfer.setDragImage(this.modelService.getDragImage(), 0, 0);
90 | } else {
91 | this.destinationHtmlElement = event.target as HTMLElement;
92 | this.oldDisplayStyle = this.destinationHtmlElement.style.display;
93 | this.destinationHtmlElement.style.display = 'none';
94 | if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
95 | this.edgeDragging.shadowDragStarted = true;
96 | }
97 | }
98 | if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
99 | if (this.edgeDragging.gElement === undefined) {
100 | this.edgeDragging.gElement = $(document.querySelectorAll('.shadow-svg-class'));
101 | this.edgeDragging.pathElement = $(document.querySelectorAll('.shadow-svg-class')).find('path');
102 | this.edgeDragging.circleElement = $(document.querySelectorAll('.shadow-svg-class')).find('circle');
103 | }
104 |
105 | this.edgeDragging.gElement.css('display', 'block');
106 | this.edgeDragging.pathElement.attr('d',
107 | this.edgeDrawingService.getEdgeDAttribute(this.edgeDragging.dragPoint1, this.edgeDragging.dragPoint2, this.edgeStyle));
108 | this.edgeDragging.circleElement.attr('cx', this.edgeDragging.dragPoint2.x);
109 | this.edgeDragging.circleElement.attr('cy', this.edgeDragging.dragPoint2.y);
110 | }
111 | event.stopPropagation();
112 | }
113 |
114 | public dragover(event: Event | any) {
115 | if (this.edgeDragging.isDragging) {
116 | if (!this.edgeDragging.magnetActive && this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
117 | if (this.destinationHtmlElement !== null) {
118 | this.destinationHtmlElement.style.display = this.oldDisplayStyle;
119 | }
120 |
121 | if (this.edgeDragging.shadowDragStarted) {
122 | this.applyFunction(() => {
123 | this.edgeDragging.shadowDragStarted = false;
124 | });
125 | }
126 |
127 | this.edgeDragging.dragPoint2 = {
128 | x: event.clientX + this.dragOffset.x,
129 | y: event.clientY + this.dragOffset.y
130 | };
131 |
132 | this.edgeDragging.pathElement.attr('d',
133 | this.edgeDrawingService.getEdgeDAttribute(this.edgeDragging.dragPoint1, this.edgeDragging.dragPoint2, this.edgeStyle));
134 | this.edgeDragging.circleElement.attr('cx', this.edgeDragging.dragPoint2.x);
135 | this.edgeDragging.circleElement.attr('cy', this.edgeDragging.dragPoint2.y);
136 |
137 | } else if (this.dragAnimation === FlowchartConstants.dragAnimationRepaint) {
138 | return this.applyFunction(() => {
139 | if (this.destinationHtmlElement !== null) {
140 | this.destinationHtmlElement.style.display = this.oldDisplayStyle;
141 | }
142 |
143 | this.edgeDragging.dragPoint2 = {
144 | x: event.clientX + this.dragOffset.x,
145 | y: event.clientY + this.dragOffset.y
146 | };
147 | });
148 | }
149 | }
150 | }
151 |
152 | public dragoverConnector(event: Event | any, connector: FcConnector): boolean {
153 | if (this.edgeDragging.isDragging) {
154 | this.dragover(event);
155 | try {
156 | this.modelValidation.validateEdges(this.model.edges.concat([{
157 | source: this.draggedEdgeSource.id,
158 | destination: connector.id
159 | }]), this.model.nodes);
160 | } catch (error) {
161 | if (error instanceof ModelvalidationError) {
162 | return true;
163 | } else {
164 | throw error;
165 | }
166 | }
167 | if (this.isValidEdgeCallback(this.draggedEdgeSource, connector)) {
168 | event.preventDefault();
169 | event.stopPropagation();
170 | return false;
171 | }
172 | }
173 | }
174 |
175 | public dragleaveMagnet(event: Event | any) {
176 | this.edgeDragging.magnetActive = false;
177 | }
178 |
179 | public dragoverMagnet(event: Event | any, connector: FcConnector): boolean {
180 | if (this.edgeDragging.isDragging) {
181 | this.dragover(event);
182 | try {
183 | this.modelValidation.validateEdges(this.model.edges.concat([{
184 | source: this.draggedEdgeSource.id,
185 | destination: connector.id
186 | }]), this.model.nodes);
187 | } catch (error) {
188 | if (error instanceof ModelvalidationError) {
189 | return true;
190 | } else {
191 | throw error;
192 | }
193 | }
194 | if (this.isValidEdgeCallback(this.draggedEdgeSource, connector)) {
195 | if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
196 |
197 | this.edgeDragging.magnetActive = true;
198 |
199 | this.edgeDragging.dragPoint2 = this.modelService.connectors.getCenteredCoord(connector.id);
200 | this.edgeDragging.pathElement.attr('d',
201 | this.edgeDrawingService.getEdgeDAttribute(this.edgeDragging.dragPoint1, this.edgeDragging.dragPoint2, this.edgeStyle));
202 | this.edgeDragging.circleElement.attr('cx', this.edgeDragging.dragPoint2.x);
203 | this.edgeDragging.circleElement.attr('cy', this.edgeDragging.dragPoint2.y);
204 |
205 | event.preventDefault();
206 | event.stopPropagation();
207 | return false;
208 | } else if (this.dragAnimation === FlowchartConstants.dragAnimationRepaint) {
209 | return this.applyFunction(() => {
210 | this.edgeDragging.dragPoint2 = this.modelService.connectors.getCenteredCoord(connector.id);
211 | event.preventDefault();
212 | event.stopPropagation();
213 | return false;
214 | });
215 | }
216 | }
217 | }
218 | }
219 |
220 | public dragend(event: Event | any) {
221 | if (this.edgeDragging.isDragging) {
222 | this.edgeDragging.isDragging = false;
223 | this.edgeDragging.dragPoint1 = null;
224 | this.edgeDragging.dragPoint2 = null;
225 | this.edgeDragging.dragLabel = null;
226 | event.stopPropagation();
227 |
228 | if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
229 | this.edgeDragging.gElement.css('display', 'none');
230 | }
231 | if (this.edgeDragging.prevEdge) {
232 | const edge = this.edgeDragging.prevEdge;
233 | this.edgeDragging.prevEdge = null;
234 | this.applyFunction(() => {
235 | this.modelService.edges.putEdge(edge);
236 | });
237 | }
238 | }
239 | }
240 |
241 | public drop(event: Event | any, targetConnector: FcConnector): boolean {
242 | if (this.edgeDragging.isDragging) {
243 | try {
244 | this.modelValidation.validateEdges(this.model.edges.concat([{
245 | source: this.draggedEdgeSource.id,
246 | destination: targetConnector.id
247 | }]), this.model.nodes);
248 | } catch (error) {
249 | if (error instanceof ModelvalidationError) {
250 | return true;
251 | } else {
252 | throw error;
253 | }
254 | }
255 |
256 | if (this.isValidEdgeCallback(this.draggedEdgeSource, targetConnector)) {
257 | this.edgeDragging.prevEdge = null;
258 | this.modelService.edges._addEdge(event, this.draggedEdgeSource, targetConnector, this.edgeDragging.dragLabel);
259 | event.stopPropagation();
260 | event.preventDefault();
261 | return false;
262 | }
263 | }
264 | }
265 | }
266 |
267 | export interface EdgeDragging {
268 | isDragging: boolean;
269 | shadowDragStarted: boolean;
270 | dragPoint1: FcCoords;
271 | dragPoint2: FcCoords;
272 | dragLabel?: string;
273 | prevEdge?: FcEdge;
274 | magnetActive?: boolean;
275 | gElement?: JQuery;
276 | pathElement?: JQuery;
277 | circleElement?: JQuery;
278 | }
279 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/edge-drawing.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { FcCoords, FlowchartConstants } from './ngx-flowchart.models';
3 |
4 | @Injectable()
5 | export class FcEdgeDrawingService {
6 |
7 | constructor() {
8 | }
9 |
10 | public getEdgeDAttribute(pt1: FcCoords, pt2: FcCoords, style: string): string {
11 | let dAddribute = `M ${pt1.x}, ${pt1.y} `;
12 | if (style === FlowchartConstants.curvedStyle) {
13 | const sourceTangent = this.computeEdgeSourceTangent(pt1, pt2);
14 | const destinationTangent = this.computeEdgeDestinationTangent(pt1, pt2);
15 | dAddribute += `C ${sourceTangent.x}, ${sourceTangent.y} ${(destinationTangent.x - 50)}, ${destinationTangent.y} ${pt2.x}, ${pt2.y}`;
16 | } else {
17 | dAddribute += `L ${pt2.x}, ${pt2.y}`;
18 | }
19 | return dAddribute;
20 | }
21 |
22 | public getEdgeCenter(pt1: FcCoords, pt2: FcCoords): FcCoords {
23 | return {
24 | x: (pt1.x + pt2.x) / 2,
25 | y: (pt1.y + pt2.y) / 2
26 | };
27 | }
28 |
29 | private computeEdgeTangentOffset(pt1: FcCoords, pt2: FcCoords): number {
30 | return (pt2.y - pt1.y) / 2;
31 | }
32 |
33 | private computeEdgeSourceTangent(pt1: FcCoords, pt2: FcCoords): FcCoords {
34 | return {
35 | x: pt1.x,
36 | y: pt1.y + this.computeEdgeTangentOffset(pt1, pt2)
37 | };
38 | }
39 |
40 | private computeEdgeDestinationTangent(pt1: FcCoords, pt2: FcCoords): FcCoords {
41 | return {
42 | x: pt2.x,
43 | y: pt2.y - this.computeEdgeTangentOffset(pt1, pt2)
44 | };
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/magnet.directive.ts:
--------------------------------------------------------------------------------
1 | import { Directive, ElementRef, HostListener, Input, OnInit } from '@angular/core';
2 | import { FcCallbacks, FcConnector, FlowchartConstants } from './ngx-flowchart.models';
3 |
4 | @Directive({
5 | // eslint-disable-next-line @angular-eslint/directive-selector
6 | selector: '[fc-magnet]'
7 | })
8 | export class FcMagnetDirective implements OnInit {
9 |
10 | @Input()
11 | callbacks: FcCallbacks;
12 |
13 | @Input()
14 | connector: FcConnector;
15 |
16 | constructor(public elementRef: ElementRef) {
17 | }
18 |
19 | ngOnInit(): void {
20 | const element = $(this.elementRef.nativeElement);
21 | element.addClass(FlowchartConstants.magnetClass);
22 | }
23 |
24 | @HostListener('dragover', ['$event'])
25 | dragover(event: Event | any) {
26 | return this.callbacks.edgeDragoverMagnet(event, this.connector);
27 | }
28 |
29 | @HostListener('dragleave', ['$event'])
30 | dragleave(event: Event | any) {
31 | this.callbacks.edgeDragleaveMagnet(event);
32 | }
33 |
34 | @HostListener('drop', ['$event'])
35 | drop(event: Event | any) {
36 | return this.callbacks.edgeDrop(event, this.connector);
37 | }
38 |
39 | @HostListener('dragend', ['$event'])
40 | dragend(event: Event | any) {
41 | this.callbacks.edgeDragend(event);
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/modelvalidation.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@angular/core';
2 | import { FcConnector, FcEdge, FcModel, FcNode, fcTopSort, ModelvalidationError } from './ngx-flowchart.models';
3 |
4 | @Injectable()
5 | export class FcModelValidationService {
6 |
7 | constructor() { }
8 |
9 | public validateModel(model: FcModel): FcModel {
10 | this.validateNodes(model.nodes);
11 | this._validateEdges(model.edges, model.nodes);
12 | return model;
13 | }
14 |
15 | public validateNodes(nodes: Array): Array {
16 | const ids: string[] = [];
17 | nodes.forEach((node) => {
18 | this.validateNode(node);
19 | if (ids.indexOf(node.id) !== -1) {
20 | throw new ModelvalidationError('Id not unique.');
21 | }
22 | ids.push(node.id);
23 | });
24 | const connectorIds: string[] = [];
25 | nodes.forEach((node) => {
26 | node.connectors.forEach((connector) => {
27 | if (connectorIds.indexOf(connector.id) !== -1) {
28 | throw new ModelvalidationError('Id not unique.');
29 | }
30 | connectorIds.push(connector.id);
31 | });
32 | });
33 | return nodes;
34 | }
35 |
36 | public validateNode(node: FcNode): FcNode {
37 | if (node.id === undefined) {
38 | throw new ModelvalidationError('Id not valid.');
39 | }
40 | if (typeof node.name !== 'string') {
41 | throw new ModelvalidationError('Name not valid.');
42 | }
43 | if (typeof node.x !== 'number' || node.x < 0 || Math.round(node.x) !== node.x) {
44 | throw new ModelvalidationError('Coordinates not valid.');
45 | }
46 | if (typeof node.y !== 'number' || node.y < 0 || Math.round(node.y) !== node.y) {
47 | throw new ModelvalidationError('Coordinates not valid.');
48 | }
49 | if (!Array.isArray(node.connectors)) {
50 | throw new ModelvalidationError('Connectors not valid.');
51 | }
52 | node.connectors.forEach((connector) => {
53 | this.validateConnector(connector);
54 | });
55 | return node;
56 | }
57 |
58 | private _validateEdges(edges: Array, nodes: Array): Array {
59 | edges.forEach((edge) => {
60 | this._validateEdge(edge, nodes);
61 | });
62 | edges.forEach((edge1, index1) => {
63 | edges.forEach((edge2, index2) => {
64 | if (index1 !== index2) {
65 | if ((edge1.source === edge2.source && edge1.destination === edge2.destination) ||
66 | (edge1.source === edge2.destination && edge1.destination === edge2.source)) {
67 | throw new ModelvalidationError('Duplicated edge.');
68 | }
69 | }
70 | });
71 | });
72 | if (fcTopSort({nodes, edges}) === null) {
73 | throw new ModelvalidationError('Graph has a circle.');
74 | }
75 | return edges;
76 | }
77 |
78 | public validateEdges(edges: Array, nodes: Array): Array {
79 | this.validateNodes(nodes);
80 | return this._validateEdges(edges, nodes);
81 | }
82 |
83 | private _validateEdge(edge: FcEdge, nodes: Array): FcEdge {
84 | if (edge.source === undefined) {
85 | throw new ModelvalidationError('Source not valid.');
86 | }
87 | if (edge.destination === undefined) {
88 | throw new ModelvalidationError('Destination not valid.');
89 | }
90 | if (edge.source === edge.destination) {
91 | throw new ModelvalidationError('Edge with same source and destination connectors.');
92 | }
93 | const sourceNode = nodes.filter((node) => node.connectors.some((connector) => connector.id === edge.source))[0];
94 | if (sourceNode === undefined) {
95 | throw new ModelvalidationError('Source not valid.');
96 | }
97 | const destinationNode = nodes.filter((node) => node.connectors.some((connector) => connector.id === edge.destination))[0];
98 | if (destinationNode === undefined) {
99 | throw new ModelvalidationError('Destination not valid.');
100 | }
101 | if (sourceNode === destinationNode) {
102 | throw new ModelvalidationError('Edge with same source and destination nodes.');
103 | }
104 | return edge;
105 | }
106 |
107 | public validateEdge(edge: FcEdge, nodes: Array): FcEdge {
108 | this.validateNodes(nodes);
109 | return this._validateEdge(edge, nodes);
110 | }
111 |
112 | public validateConnector(connector: FcConnector): FcConnector {
113 | if (connector.id === undefined) {
114 | throw new ModelvalidationError('Id not valid.');
115 | }
116 | if (connector.type === undefined || connector.type === null || typeof connector.type !== 'string') {
117 | throw new ModelvalidationError('Type not valid.');
118 | }
119 | return connector;
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/mouseover.service.ts:
--------------------------------------------------------------------------------
1 | import { FcConnector, FcEdge, FcNode } from './ngx-flowchart.models';
2 |
3 | export class FcMouseOverService {
4 |
5 | mouseoverscope: MouseOverScope = {
6 | connector: null,
7 | edge: null,
8 | node: null
9 | };
10 |
11 | private readonly applyFunction: (fn: (...args: any[]) => T) => T;
12 |
13 | constructor(applyFunction: (fn: (...args: any[]) => T) => T) {
14 | this.applyFunction = applyFunction;
15 | }
16 |
17 | public nodeMouseOver(event: MouseEvent, node: FcNode) {
18 | return this.applyFunction(() => {
19 | this.mouseoverscope.node = node;
20 | });
21 | }
22 |
23 | public nodeMouseOut(event: MouseEvent, node: FcNode) {
24 | return this.applyFunction(() => {
25 | this.mouseoverscope.node = null;
26 | });
27 | }
28 |
29 | public connectorMouseEnter(event: MouseEvent, connector: FcConnector) {
30 | return this.applyFunction(() => {
31 | this.mouseoverscope.connector = connector;
32 | });
33 | }
34 |
35 | public connectorMouseLeave(event: MouseEvent, connector: FcConnector) {
36 | return this.applyFunction(() => {
37 | this.mouseoverscope.connector = null;
38 | });
39 | }
40 |
41 | public edgeMouseEnter(event: MouseEvent, edge: FcEdge) {
42 | this.mouseoverscope.edge = edge;
43 | }
44 |
45 | public edgeMouseLeave(event: MouseEvent, edge: FcEdge) {
46 | this.mouseoverscope.edge = null;
47 | }
48 | }
49 |
50 | export interface MouseOverScope {
51 | connector: FcConnector;
52 | edge: FcEdge;
53 | node: FcNode;
54 | }
55 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/ngx-flowchart.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
26 |
27 |
28 |
29 |
31 |
34 |
35 |
36 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
55 |
56 |
62 |
63 | {{edgeDraggingService.edgeDragging.dragLabel}}
64 |
65 |
66 |
83 |
84 |
85 |
86 |
87 |
88 | ×
89 |
90 |
{{edge.label}}
91 |
92 |
93 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/ngx-flowchart.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: block;
3 | position: relative;
4 | width: 100%;
5 | height: 100%;
6 | background-size: 25px 25px;
7 | background-image: linear-gradient(to right, rgba(0, 0, 0, .1) 1px, transparent 1px), linear-gradient(to bottom, rgba(0, 0, 0, .1) 1px, transparent 1px);
8 | background-color: transparent;
9 | min-width: 100%;
10 | min-height: 100%;
11 | -webkit-touch-callout: none;
12 | -webkit-user-select: none;
13 | -khtml-user-select: none;
14 | -moz-user-select: none;
15 | -ms-user-select: none;
16 | user-select: none;
17 |
18 | .fc-canvas-container {
19 | display: block;
20 | position: relative;
21 | width: 100%;
22 | height: 100%;
23 | svg.fc-canvas-svg {
24 | display: block;
25 | position: relative;
26 | width: 100%;
27 | height: 100%;
28 | }
29 | }
30 |
31 | .fc-edge {
32 | stroke: gray;
33 | stroke-width: 4;
34 | transition: stroke-width .2s;
35 | fill: transparent;
36 | &.fc-hover {
37 | stroke: gray;
38 | stroke-width: 6;
39 | fill: transparent;
40 | }
41 | &.fc-selected {
42 | stroke: red;
43 | stroke-width: 4;
44 | fill: transparent;
45 | }
46 | &.fc-active {
47 | animation: dash 3s linear infinite;
48 | stroke-dasharray: 20;
49 | }
50 | &.fc-dragging {
51 | pointer-events: none;
52 | }
53 | }
54 |
55 | .fc-arrow-marker polygon {
56 | stroke: gray;
57 | fill: gray;
58 | }
59 |
60 | .fc-arrow-marker-selected polygon {
61 | stroke: red;
62 | fill: red;
63 | }
64 |
65 | .edge-endpoint {
66 | fill: gray;
67 | }
68 |
69 | .fc-noselect {
70 | -webkit-touch-callout: none; /* iOS Safari */
71 | -webkit-user-select: none; /* Safari */
72 | -khtml-user-select: none; /* Konqueror HTML */
73 | -moz-user-select: none; /* Firefox */
74 | -ms-user-select: none; /* Internet Explorer/Edge */
75 | user-select: none; /* Non-prefixed version, currently
76 | supported by Chrome and Opera */
77 | }
78 |
79 | .fc-edge-label {
80 | position: absolute;
81 | opacity: 0.8;
82 | transition: transform .2s;
83 | transform-origin: bottom left;
84 | margin: 0 auto;
85 | .fc-edge-label-text {
86 | position: absolute;
87 | -webkit-transform: translate(-50%, -50%);
88 | transform: translate(-50%, -50%);
89 | white-space: nowrap;
90 | text-align: center;
91 | font-size: 16px;
92 | span {
93 | cursor: default;
94 | border: solid #ff3d00;
95 | border-radius: 10px;
96 | color: #ff3d00;
97 | background-color: #fff;
98 | padding: 3px 5px;
99 | }
100 | }
101 | .fc-nodeedit {
102 | top: -30px;
103 | right: 14px;
104 | }
105 | .fc-nodedelete {
106 | top: -30px;
107 | right: -13px;
108 | }
109 | &.fc-hover {
110 | transform: scale(1.25);
111 | }
112 | &.fc-selected,
113 | &.fc-edit {
114 | .fc-edge-label-text {
115 | span {
116 | border: solid red;
117 | color: #fff;
118 | font-weight: 600;
119 | background-color: red;
120 | }
121 | }
122 | }
123 | }
124 |
125 | .fc-select-rectangle {
126 | border: 2px dashed #5262ff;
127 | position: absolute;
128 | background: rgba(20,125,255,0.1);
129 | z-index: 2;
130 | }
131 | }
132 |
133 | @keyframes dash {
134 | from {
135 | stroke-dashoffset: 500;
136 | }
137 | }
138 |
139 | :host ::ng-deep {
140 |
141 | .fc-nodeedit {
142 | display: none;
143 | font-size: 15px;
144 | }
145 |
146 | .fc-nodedelete {
147 | display: none;
148 | font-size: 18px;
149 | }
150 |
151 | .fc-edit {
152 | .fc-nodeedit,
153 | .fc-nodedelete {
154 | display: block;
155 | position: absolute;
156 | border: solid 2px #eee;
157 |
158 | border-radius: 50%;
159 | font-weight: 600;
160 | line-height: 20px;
161 |
162 | height: 20px;
163 | padding-top: 2px;
164 | width: 22px;
165 |
166 | background: #494949;
167 | color: #fff;
168 | text-align: center;
169 | vertical-align: bottom;
170 |
171 | cursor: pointer;
172 | }
173 | .fc-nodeedit {
174 | top: -24px;
175 | right: 16px;
176 | }
177 | .fc-nodedelete {
178 | top: -24px;
179 | right: -13px;
180 | }
181 | }
182 | }
183 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/ngx-flowchart.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ChangeDetectionStrategy,
3 | ChangeDetectorRef,
4 | Component,
5 | DoCheck,
6 | ElementRef,
7 | EventEmitter,
8 | HostBinding,
9 | HostListener,
10 | Input,
11 | IterableDiffer,
12 | IterableDiffers,
13 | NgZone,
14 | OnInit,
15 | Output
16 | } from '@angular/core';
17 | import { FcCallbacks, FcEdge, FcModel, FcNode, FlowchartConstants, UserCallbacks, UserNodeCallbacks } from './ngx-flowchart.models';
18 | import { FcModelService } from './model.service';
19 | import { FcModelValidationService } from './modelvalidation.service';
20 | import { FcNodeDraggingService } from './node-dragging.service';
21 | import { FcEdgeDrawingService } from './edge-drawing.service';
22 | import { FcEdgeDraggingService } from './edge-dragging.service';
23 | import { FcMouseOverService } from './mouseover.service';
24 | import { FcRectangleSelectService } from './rectangleselect.service';
25 | import { coerceBooleanProperty } from '@angular/cdk/coercion';
26 | import { Subject } from 'rxjs';
27 | import { debounceTime } from 'rxjs/operators';
28 |
29 | @Component({
30 | // eslint-disable-next-line @angular-eslint/component-selector
31 | selector: 'fc-canvas',
32 | templateUrl: './ngx-flowchart.component.html',
33 | styleUrls: ['./ngx-flowchart.component.scss'],
34 | changeDetection: ChangeDetectionStrategy.OnPush
35 | })
36 | export class NgxFlowchartComponent implements OnInit, DoCheck {
37 |
38 | @HostBinding('attr.class')
39 | get canvasClass(): string {
40 | return FlowchartConstants.canvasClass;
41 | }
42 |
43 | @Input()
44 | model: FcModel;
45 |
46 | @Input()
47 | selectedObjects: any[];
48 |
49 | @Input()
50 | edgeStyle: string;
51 |
52 | @Input()
53 | userCallbacks: UserCallbacks;
54 |
55 | @Input()
56 | automaticResize: boolean;
57 |
58 | @Input()
59 | dragAnimation: string;
60 |
61 | @Input()
62 | nodeWidth: number;
63 |
64 | @Input()
65 | nodeHeight: number;
66 |
67 | @Input()
68 | dropTargetId: string;
69 |
70 | @Output()
71 | modelChanged = new EventEmitter();
72 |
73 | private fitModelSizeByDefaultValue = true;
74 | get fitModelSizeByDefault(): boolean {
75 | return this.fitModelSizeByDefaultValue;
76 | }
77 | @Input()
78 | set fitModelSizeByDefault(value: boolean) {
79 | this.fitModelSizeByDefaultValue = coerceBooleanProperty(value);
80 | }
81 |
82 | callbacks: FcCallbacks;
83 |
84 | userNodeCallbacks: UserNodeCallbacks;
85 |
86 | modelService: FcModelService;
87 | nodeDraggingService: FcNodeDraggingService;
88 | edgeDraggingService: FcEdgeDraggingService;
89 | mouseoverService: FcMouseOverService;
90 | rectangleSelectService: FcRectangleSelectService;
91 |
92 | arrowDefId: string;
93 | arrowDefIdSelected: string;
94 |
95 | flowchartConstants = FlowchartConstants;
96 |
97 | private nodesDiffer: IterableDiffer = this.differs.find([]).create((index, item) => item);
98 |
99 | private edgesDiffer: IterableDiffer = this.differs.find([]).create((index, item) => item);
100 |
101 | private readonly detectChangesSubject = new Subject();
102 |
103 | constructor(private elementRef: ElementRef,
104 | private differs: IterableDiffers,
105 | private modelValidation: FcModelValidationService,
106 | public edgeDrawingService: FcEdgeDrawingService,
107 | private cd: ChangeDetectorRef,
108 | private zone: NgZone) {
109 | this.arrowDefId = 'arrow-' + Math.random();
110 | this.arrowDefIdSelected = this.arrowDefId + '-selected';
111 | this.detectChangesSubject
112 | .pipe(debounceTime(50))
113 | .subscribe(() => this.cd.detectChanges());
114 | }
115 |
116 | ngOnInit() {
117 | if (!this.dropTargetId && this.edgeStyle !== FlowchartConstants.curvedStyle && this.edgeStyle !== FlowchartConstants.lineStyle) {
118 | throw new Error('edgeStyle not supported.');
119 | }
120 | this.nodeHeight = this.nodeHeight || 200;
121 | this.nodeWidth = this.nodeWidth || 200;
122 | this.dragAnimation = this.dragAnimation || FlowchartConstants.dragAnimationRepaint;
123 | this.userCallbacks = this.userCallbacks || {};
124 | this.automaticResize = this.automaticResize || false;
125 |
126 | for (const key of Object.keys(this.userCallbacks)) {
127 | const callback = this.userCallbacks[key];
128 | if (typeof callback !== 'function' && key !== 'nodeCallbacks') {
129 | throw new Error('All callbacks should be functions.');
130 | }
131 | }
132 |
133 | this.userNodeCallbacks = this.userCallbacks.nodeCallbacks;
134 |
135 | const element = $(this.elementRef.nativeElement);
136 |
137 | this.modelService = new FcModelService(this.modelValidation, this.model, this.modelChanged,
138 | this.detectChangesSubject, this.selectedObjects,
139 | this.userCallbacks.dropNode, this.userCallbacks.createEdge, this.userCallbacks.edgeAdded, this.userCallbacks.nodeRemoved,
140 | this.userCallbacks.edgeRemoved, element[0], element[0].querySelector('svg'));
141 |
142 | if (this.dropTargetId) {
143 | this.modelService.dropTargetId = this.dropTargetId;
144 | }
145 |
146 | const applyFunction = this.zone.run.bind(this.zone);
147 |
148 | this.nodeDraggingService = new FcNodeDraggingService(this.modelService, applyFunction,
149 | this.automaticResize, this.dragAnimation);
150 |
151 | this.edgeDraggingService = new FcEdgeDraggingService(this.modelValidation, this.edgeDrawingService, this.modelService,
152 | this.model, this.userCallbacks.isValidEdge || null, applyFunction,
153 | this.dragAnimation, this.edgeStyle);
154 |
155 | this.mouseoverService = new FcMouseOverService(applyFunction);
156 |
157 | this.rectangleSelectService = new FcRectangleSelectService(this.modelService,
158 | element[0].querySelector('#select-rectangle'), applyFunction);
159 |
160 | this.callbacks = {
161 | nodeDragstart: this.nodeDraggingService.dragstart.bind(this.nodeDraggingService),
162 | nodeDragend: this.nodeDraggingService.dragend.bind(this.nodeDraggingService),
163 | edgeDragstart: this.edgeDraggingService.dragstart.bind(this.edgeDraggingService),
164 | edgeDragend: this.edgeDraggingService.dragend.bind(this.edgeDraggingService),
165 | edgeDrop: this.edgeDraggingService.drop.bind(this.edgeDraggingService),
166 | edgeDragoverConnector: this.edgeDraggingService.dragoverConnector.bind(this.edgeDraggingService),
167 | edgeDragoverMagnet: this.edgeDraggingService.dragoverMagnet.bind(this.edgeDraggingService),
168 | edgeDragleaveMagnet: this.edgeDraggingService.dragleaveMagnet.bind(this.edgeDraggingService),
169 | nodeMouseOver: this.mouseoverService.nodeMouseOver.bind(this.mouseoverService),
170 | nodeMouseOut: this.mouseoverService.nodeMouseOut.bind(this.mouseoverService),
171 | connectorMouseEnter: this.mouseoverService.connectorMouseEnter.bind(this.mouseoverService),
172 | connectorMouseLeave: this.mouseoverService.connectorMouseLeave.bind(this.mouseoverService),
173 | nodeClicked: (event, node) => {
174 | this.modelService.nodes.handleClicked(node, event.ctrlKey);
175 | event.stopPropagation();
176 | event.preventDefault();
177 | }
178 | };
179 | this.adjustCanvasSize(this.fitModelSizeByDefault);
180 | }
181 |
182 | ngDoCheck(): void {
183 | if (this.model) {
184 | const nodesChange = this.nodesDiffer.diff(this.model.nodes);
185 | const edgesChange = this.edgesDiffer.diff(this.model.edges);
186 | let nodesChanged = false;
187 | let edgesChanged = false;
188 | if (nodesChange !== null) {
189 | nodesChange.forEachAddedItem(() => {
190 | nodesChanged = true;
191 | });
192 | nodesChange.forEachRemovedItem(() => {
193 | nodesChanged = true;
194 | });
195 | }
196 | if (edgesChange !== null) {
197 | edgesChange.forEachAddedItem(() => {
198 | edgesChanged = true;
199 | });
200 | edgesChange.forEachRemovedItem(() => {
201 | edgesChanged = true;
202 | });
203 | }
204 | if (nodesChanged) {
205 | this.adjustCanvasSize(this.fitModelSizeByDefault);
206 | }
207 | if (nodesChanged || edgesChanged) {
208 | this.detectChangesSubject.next(null);
209 | }
210 | }
211 | }
212 |
213 | getEdgeDAttribute(edge: FcEdge): string {
214 | return this.edgeDrawingService.getEdgeDAttribute(this.modelService.edges.sourceCoord(edge),
215 | this.modelService.edges.destCoord(edge), this.edgeStyle);
216 | }
217 |
218 | public adjustCanvasSize(fit?: boolean) {
219 | let maxX = 0;
220 | let maxY = 0;
221 | const element = $(this.elementRef.nativeElement);
222 | this.model.nodes.forEach((node) => {
223 | maxX = Math.max(node.x + this.nodeWidth, maxX);
224 | maxY = Math.max(node.y + this.nodeHeight, maxY);
225 | });
226 | let width;
227 | let height;
228 | if (fit) {
229 | width = maxX;
230 | height = maxY;
231 | } else {
232 | width = Math.max(maxX, element.prop('offsetWidth'));
233 | height = Math.max(maxY, element.prop('offsetHeight'));
234 | }
235 | element.css('width', width + 'px');
236 | element.css('height', height + 'px');
237 | }
238 |
239 | canvasClick(event: MouseEvent) {}
240 |
241 | edgeMouseDown(event: MouseEvent, edge: FcEdge) {
242 | event.stopPropagation();
243 | }
244 |
245 | edgeClick(event: MouseEvent, edge: FcEdge) {
246 | this.modelService.edges.handleEdgeMouseClick(edge, event.ctrlKey);
247 | event.stopPropagation();
248 | event.preventDefault();
249 | }
250 |
251 | edgeRemove(event: Event, edge: FcEdge) {
252 | this.modelService.edges.delete(edge);
253 | event.stopPropagation();
254 | event.preventDefault();
255 | }
256 |
257 | edgeEdit(event: Event, edge: FcEdge) {
258 | if (this.userCallbacks.edgeEdit) {
259 | this.userCallbacks.edgeEdit(event, edge);
260 | }
261 | }
262 |
263 | edgeDoubleClick(event: MouseEvent, edge: FcEdge) {
264 | if (this.userCallbacks.edgeDoubleClick) {
265 | this.userCallbacks.edgeDoubleClick(event, edge);
266 | }
267 | }
268 |
269 | edgeMouseOver(event: MouseEvent, edge: FcEdge) {
270 | if (this.userCallbacks.edgeMouseOver) {
271 | this.userCallbacks.edgeMouseOver(event, edge);
272 | }
273 | }
274 |
275 | edgeMouseEnter(event: MouseEvent, edge: FcEdge) {
276 | this.mouseoverService.edgeMouseEnter(event, edge);
277 | }
278 |
279 | edgeMouseLeave(event: MouseEvent, edge: FcEdge) {
280 | this.mouseoverService.edgeMouseLeave(event, edge);
281 | }
282 |
283 | @HostListener('dragover', ['$event'])
284 | dragover(event: Event | any) {
285 | this.nodeDraggingService.dragover(event);
286 | this.edgeDraggingService.dragover(event);
287 | }
288 |
289 | @HostListener('drop', ['$event'])
290 | drop(event: Event | any) {
291 | if (event.preventDefault) {
292 | event.preventDefault();
293 | }
294 | if (event.stopPropagation) {
295 | event.stopPropagation();
296 | }
297 | this.nodeDraggingService.drop(event);
298 | }
299 |
300 | @HostListener('mousedown', ['$event'])
301 | mousedown(event: MouseEvent) {
302 | this.rectangleSelectService.mousedown(event);
303 | }
304 |
305 | @HostListener('mousemove', ['$event'])
306 | mousemove(event: MouseEvent) {
307 | this.rectangleSelectService.mousemove(event);
308 | }
309 |
310 | @HostListener('mouseup', ['$event'])
311 | mouseup(event: MouseEvent) {
312 | this.rectangleSelectService.mouseup(event);
313 | }
314 |
315 | }
316 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/ngx-flowchart.models.ts:
--------------------------------------------------------------------------------
1 | import { Observable } from 'rxjs';
2 | import { InjectionToken, Type } from '@angular/core';
3 | import { FcNodeComponent } from './node.component';
4 |
5 | export const FC_NODE_COMPONENT_CONFIG = new InjectionToken('fc-node.component.config');
6 |
7 | export interface FcNodeComponentConfig {
8 | nodeComponentType: Type;
9 | }
10 |
11 | const htmlPrefix = 'fc';
12 | const leftConnectorType = 'leftConnector';
13 | const rightConnectorType = 'rightConnector';
14 |
15 | // eslint-disable-next-line @typescript-eslint/naming-convention
16 | export const FlowchartConstants = {
17 | htmlPrefix,
18 | leftConnectorType,
19 | rightConnectorType,
20 | curvedStyle: 'curved',
21 | lineStyle: 'line',
22 | dragAnimationRepaint: 'repaint',
23 | dragAnimationShadow: 'shadow',
24 | canvasClass: htmlPrefix + '-canvas',
25 | selectedClass: htmlPrefix + '-selected',
26 | editClass: htmlPrefix + '-edit',
27 | activeClass: htmlPrefix + '-active',
28 | hoverClass: htmlPrefix + '-hover',
29 | draggingClass: htmlPrefix + '-dragging',
30 | edgeClass: htmlPrefix + '-edge',
31 | edgeLabelClass: htmlPrefix + '-edge-label',
32 | connectorClass: htmlPrefix + '-connector',
33 | magnetClass: htmlPrefix + '-magnet',
34 | nodeClass: htmlPrefix + '-node',
35 | nodeOverlayClass: htmlPrefix + '-node-overlay',
36 | leftConnectorClass: htmlPrefix + '-' + leftConnectorType + 's',
37 | rightConnectorClass: htmlPrefix + '-' + rightConnectorType + 's',
38 | canvasResizeThreshold: 200,
39 | canvasResizeStep: 200
40 | };
41 |
42 |
43 | export interface FcCoords {
44 | x?: number;
45 | y?: number;
46 | }
47 |
48 | export interface FcRectBox {
49 | top: number;
50 | left: number;
51 | right: number;
52 | bottom: number;
53 | }
54 |
55 | export interface FcConnector {
56 | id: string;
57 | type: string;
58 | }
59 |
60 | export interface FcNode extends FcCoords {
61 | id: string;
62 | name: string;
63 | connectors: Array;
64 | readonly?: boolean;
65 | [key: string]: any;
66 | }
67 |
68 | export interface FcNodeRectInfo {
69 | width(): number;
70 | height(): number;
71 | top(): number;
72 | left(): number;
73 | right(): number;
74 | bottom(): number;
75 | }
76 |
77 | export interface FcConnectorRectInfo {
78 | type: string;
79 | width: number;
80 | height: number;
81 | nodeRectInfo: FcNodeRectInfo;
82 | }
83 |
84 | export interface FcEdge {
85 | label?: string;
86 | source?: string;
87 | destination?: string;
88 | active?: boolean;
89 | }
90 |
91 | export interface FcItemInfo {
92 | node?: FcNode;
93 | edge?: FcEdge;
94 | }
95 |
96 | export interface FcModel {
97 | nodes: Array;
98 | edges: Array;
99 | }
100 |
101 | export interface UserCallbacks {
102 | dropNode?: (event: Event, node: FcNode) => void;
103 | createEdge?: (event: Event, edge: FcEdge) => Observable;
104 | edgeAdded?: (edge: FcEdge) => void;
105 | nodeRemoved?: (node: FcNode) => void;
106 | edgeRemoved?: (edge: FcEdge) => void;
107 | edgeDoubleClick?: (event: MouseEvent, edge: FcEdge) => void;
108 | edgeMouseOver?: (event: MouseEvent, edge: FcEdge) => void;
109 | isValidEdge?: (source: FcConnector, destination: FcConnector) => boolean;
110 | edgeEdit?: (event: Event, edge: FcEdge) => void;
111 | nodeCallbacks?: UserNodeCallbacks;
112 | }
113 |
114 | export interface UserNodeCallbacks {
115 | nodeEdit?: (event: MouseEvent, node: FcNode) => void;
116 | doubleClick?: (event: MouseEvent, node: FcNode) => void;
117 | mouseDown?: (event: MouseEvent, node: FcNode) => void;
118 | mouseEnter?: (event: MouseEvent, node: FcNode) => void;
119 | mouseLeave?: (event: MouseEvent, node: FcNode) => void;
120 | }
121 |
122 | export interface FcCallbacks {
123 | nodeDragstart: (event: Event | any, node: FcNode) => void;
124 | nodeDragend: (event: Event | any) => void;
125 | edgeDragstart: (event: Event | any, connector: FcConnector) => void;
126 | edgeDragend: (event: Event | any) => void;
127 | edgeDrop: (event: Event | any, targetConnector: FcConnector) => boolean;
128 | edgeDragoverConnector: (event: Event | any, connector: FcConnector) => boolean;
129 | edgeDragoverMagnet: (event: Event | any, connector: FcConnector) => boolean;
130 | edgeDragleaveMagnet: (event: Event | any) => void;
131 | nodeMouseOver: (event: MouseEvent, node: FcNode) => void;
132 | nodeMouseOut: (event: MouseEvent, node: FcNode) => void;
133 | connectorMouseEnter: (event: MouseEvent, connector: FcConnector) => void;
134 | connectorMouseLeave: (event: MouseEvent, connector: FcConnector) => void;
135 | nodeClicked: (event: MouseEvent, node: FcNode) => void;
136 | }
137 |
138 | export interface FcAdjacentList {
139 | [id: string]: {
140 | incoming: number;
141 | outgoing: Array;
142 | };
143 | }
144 |
145 | class BaseError {
146 | constructor() {
147 | Error.apply(this, arguments);
148 | }
149 | }
150 |
151 | Object.defineProperty(BaseError, 'prototype', new Error());
152 |
153 | export class ModelvalidationError extends BaseError {
154 | constructor(public message: string) {
155 | super();
156 | }
157 | }
158 |
159 | export const fcTopSort = (graph: FcModel): Array | null => {
160 | const adjacentList: FcAdjacentList = {};
161 | graph.nodes.forEach((node) => {
162 | adjacentList[node.id] = {incoming: 0, outgoing: []};
163 | });
164 | graph.edges.forEach((edge) => {
165 | const sourceNode = graph.nodes.filter((node) => node.connectors.some((connector) => connector.id === edge.source))[0];
166 | const destinationNode = graph.nodes.filter((node) => node.connectors.some((connector) => connector.id === edge.destination))[0];
167 | adjacentList[sourceNode.id].outgoing.push(destinationNode.id);
168 | adjacentList[destinationNode.id].incoming++;
169 | });
170 | const orderedNodes: string[] = [];
171 | const sourceNodes: string[] = [];
172 | for (const node of Object.keys(adjacentList)) {
173 | const edges = adjacentList[node];
174 | if (edges.incoming === 0) {
175 | sourceNodes.push(node);
176 | }
177 | }
178 | while (sourceNodes.length !== 0) {
179 | const sourceNode = sourceNodes.pop();
180 | for (let i = 0; i < adjacentList[sourceNode].outgoing.length; i++) {
181 | const destinationNode = adjacentList[sourceNode].outgoing[i];
182 | adjacentList[destinationNode].incoming--;
183 | if (adjacentList[destinationNode].incoming === 0) {
184 | sourceNodes.push(destinationNode);
185 | }
186 | adjacentList[sourceNode].outgoing.splice(i, 1);
187 | i--;
188 | }
189 | orderedNodes.push(sourceNode);
190 | }
191 | let hasEdges = false;
192 | for (const node of Object.keys(adjacentList)) {
193 | const edges = adjacentList[node];
194 | if (edges.incoming !== 0) {
195 | hasEdges = true;
196 | }
197 | }
198 | if (hasEdges) {
199 | return null;
200 | } else {
201 | return orderedNodes;
202 | }
203 | };
204 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/ngx-flowchart.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { NgxFlowchartComponent } from './ngx-flowchart.component';
3 | import { FcModelValidationService } from './modelvalidation.service';
4 | import { FcEdgeDrawingService } from './edge-drawing.service';
5 | import { CommonModule } from '@angular/common';
6 | import { FcMagnetDirective } from './magnet.directive';
7 | import { FcConnectorDirective } from './connector.directive';
8 | import { FcNodeContainerComponent } from './node.component';
9 | import { FC_NODE_COMPONENT_CONFIG } from './ngx-flowchart.models';
10 | import { DefaultFcNodeComponent } from './default-node.component';
11 |
12 | @NgModule({
13 | declarations: [NgxFlowchartComponent,
14 | FcMagnetDirective,
15 | FcConnectorDirective,
16 | FcNodeContainerComponent,
17 | DefaultFcNodeComponent],
18 | providers: [
19 | FcModelValidationService,
20 | FcEdgeDrawingService,
21 | {
22 | provide: FC_NODE_COMPONENT_CONFIG,
23 | useValue: {
24 | nodeComponentType: DefaultFcNodeComponent
25 | }
26 | }
27 | ],
28 | imports: [
29 | CommonModule
30 | ],
31 | exports: [NgxFlowchartComponent,
32 | FcMagnetDirective,
33 | FcConnectorDirective,
34 | DefaultFcNodeComponent]
35 | })
36 | export class NgxFlowchartModule { }
37 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/node-dragging.service.ts:
--------------------------------------------------------------------------------
1 | import { FcModelService } from './model.service';
2 | import { FcCoords, FcNode, FlowchartConstants } from './ngx-flowchart.models';
3 |
4 | const nodeDropScope: NodeDropScope = {
5 | dropElement: null
6 | };
7 |
8 | export class FcNodeDraggingService {
9 |
10 | nodeDraggingScope: NodeDraggingScope = {
11 | shadowDragStarted: false,
12 | dropElement: null,
13 | draggedNodes: [],
14 | shadowElements: []
15 | };
16 |
17 | private dragOffsets: FcCoords[] = [];
18 | private draggedElements: HTMLElement[] = [];
19 |
20 | private destinationHtmlElements: HTMLElement[] = [];
21 | private oldDisplayStyles: string[] = [];
22 |
23 | private readonly modelService: FcModelService;
24 | private readonly automaticResize: boolean;
25 | private readonly dragAnimation: string;
26 | private readonly applyFunction: (fn: (...args: any[]) => T) => T;
27 |
28 | constructor(modelService: FcModelService,
29 | applyFunction: (fn: (...args: any[]) => T) => T,
30 | automaticResize: boolean, dragAnimation: string) {
31 | this.modelService = modelService;
32 | this.automaticResize = automaticResize;
33 | this.dragAnimation = dragAnimation;
34 | this.applyFunction = applyFunction;
35 | }
36 |
37 | private getCoordinate(coordinate: number, max: number): number {
38 | coordinate = Math.max(coordinate, 0);
39 | coordinate = Math.min(coordinate, max);
40 | return coordinate;
41 | }
42 |
43 | private getXCoordinate(x: number): number {
44 | return this.getCoordinate(x, this.modelService.canvasHtmlElement.offsetWidth);
45 | }
46 |
47 | private getYCoordinate(y: number): number {
48 | return this.getCoordinate(y, this.modelService.canvasHtmlElement.offsetHeight);
49 | }
50 |
51 | private resizeCanvas(draggedNode: FcNode, nodeElement: HTMLElement) {
52 | if (this.automaticResize && !this.modelService.isDropSource()) {
53 | const canvasElement = this.modelService.canvasHtmlElement;
54 | if (canvasElement.offsetWidth < draggedNode.x + nodeElement.offsetWidth + FlowchartConstants.canvasResizeThreshold) {
55 | canvasElement.style.width = canvasElement.offsetWidth + FlowchartConstants.canvasResizeStep + 'px';
56 | }
57 | if (canvasElement.offsetHeight < draggedNode.y + nodeElement.offsetHeight + FlowchartConstants.canvasResizeThreshold) {
58 | canvasElement.style.height = canvasElement.offsetHeight + FlowchartConstants.canvasResizeStep + 'px';
59 | }
60 | }
61 | }
62 |
63 | public isDraggingNode(node: FcNode): boolean {
64 | return this.nodeDraggingScope.draggedNodes.includes(node);
65 | }
66 |
67 | public dragstart(event: Event | any, node: FcNode) {
68 | if (node.readonly) {
69 | return;
70 | }
71 | this.dragOffsets.length = 0;
72 | this.draggedElements.length = 0;
73 | this.nodeDraggingScope.draggedNodes.length = 0;
74 | this.nodeDraggingScope.shadowElements.length = 0;
75 | this.destinationHtmlElements.length = 0;
76 | this.oldDisplayStyles.length = 0;
77 | const elements: Array> = [];
78 | const nodes: Array = [];
79 | if (this.modelService.nodes.isSelected(node)) {
80 | const selectedNodes = this.modelService.nodes.getSelectedNodes();
81 | for (const selectedNode of selectedNodes) {
82 | const element = $(this.modelService.nodes.getHtmlElement(selectedNode.id));
83 | elements.push(element);
84 | nodes.push(selectedNode);
85 | }
86 | } else {
87 | elements.push($(event.target as HTMLElement));
88 | nodes.push(node);
89 | }
90 | const offsetsX: number[] = [];
91 | const offsetsY: number[] = [];
92 | for (const element of elements) {
93 | offsetsX.push(parseInt(element.css('left'), 10) - event.clientX);
94 | offsetsY.push(parseInt(element.css('top'), 10) - event.clientY);
95 | }
96 | const originalEvent: Event | any = (event as any).originalEvent || event;
97 | if (this.modelService.isDropSource()) {
98 | if (nodeDropScope.dropElement) {
99 | nodeDropScope.dropElement.parentNode.removeChild(nodeDropScope.dropElement);
100 | nodeDropScope.dropElement = null;
101 | }
102 | nodeDropScope.dropElement = elements[0][0].cloneNode(true) as NodeDropElement;
103 | const offset = $(this.modelService.canvasHtmlElement).offset();
104 | nodeDropScope.dropElement.offsetInfo = {
105 | offsetX: Math.round(offsetsX[0] + offset.left),
106 | offsetY: Math.round(offsetsY[0] + offset.top)
107 | };
108 | nodeDropScope.dropElement.style.position = 'absolute';
109 | nodeDropScope.dropElement.style.pointerEvents = 'none';
110 | nodeDropScope.dropElement.style.zIndex = '9999';
111 |
112 | document.body.appendChild(nodeDropScope.dropElement);
113 | const dropNodeInfo: DropNodeInfo = {
114 | node,
115 | dropTargetId: this.modelService.dropTargetId,
116 | offsetX: Math.round(offsetsX[0] + offset.left),
117 | offsetY: Math.round(offsetsY[0] + offset.top)
118 | };
119 | originalEvent.dataTransfer.setData('text', JSON.stringify(dropNodeInfo));
120 |
121 | if (originalEvent.dataTransfer.setDragImage) {
122 | originalEvent.dataTransfer.setDragImage(this.modelService.getDragImage(), 0, 0);
123 | } else {
124 | const target: HTMLElement = event.target as HTMLElement;
125 | const cloneNode = target.cloneNode(true);
126 | target.parentNode.insertBefore(cloneNode, target);
127 | target.style.visibility = 'collapse';
128 | setTimeout(() => {
129 | target.parentNode.removeChild(cloneNode);
130 | target.style.visibility = 'visible';
131 | }, 0);
132 | }
133 | return;
134 | }
135 | this.nodeDraggingScope.draggedNodes = nodes;
136 | for (let i = 0; i < elements.length; i++) {
137 | this.draggedElements.push(elements[i][0]);
138 | this.dragOffsets.push(
139 | {
140 | x: offsetsX[i],
141 | y: offsetsY[i]
142 | }
143 | );
144 | }
145 |
146 | if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
147 | for (let i = 0; i < this.draggedElements.length; i++) {
148 | const dragOffset = this.dragOffsets[i];
149 | const draggedNode = this.nodeDraggingScope.draggedNodes[i];
150 | const shadowElement = $(``);
154 | const targetInnerNode = $(this.draggedElements[i]).children()[0];
155 | shadowElement.children()[0].style.backgroundColor = targetInnerNode.style.backgroundColor;
156 | this.nodeDraggingScope.shadowElements.push(shadowElement);
157 | this.modelService.canvasHtmlElement.appendChild(this.nodeDraggingScope.shadowElements[i][0]);
158 | }
159 | }
160 | originalEvent.dataTransfer.setData('text', 'Just to support firefox');
161 | if (originalEvent.dataTransfer.setDragImage) {
162 | originalEvent.dataTransfer.setDragImage(this.modelService.getDragImage(), 0, 0);
163 | } else {
164 | this.draggedElements.forEach((draggedElement) => {
165 | const cloneNode = draggedElement.cloneNode(true);
166 | draggedElement.parentNode.insertBefore(cloneNode, draggedElement);
167 | draggedElement.style.visibility = 'collapse';
168 | setTimeout(() => {
169 | draggedElement.parentNode.removeChild(cloneNode);
170 | draggedElement.style.visibility = 'visible';
171 | }, 0);
172 | });
173 | if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
174 | for (let i = 0; i < this.draggedElements.length; i++) {
175 | this.destinationHtmlElements.push(this.draggedElements[i]);
176 | this.oldDisplayStyles.push(this.destinationHtmlElements[i].style.display);
177 | this.destinationHtmlElements[i].style.display = 'none';
178 | }
179 | this.nodeDraggingScope.shadowDragStarted = true;
180 | }
181 | }
182 | }
183 |
184 | public drop(event: Event | any): boolean {
185 | if (this.modelService.isDropSource()) {
186 | event.preventDefault();
187 | return false;
188 | }
189 | let dropNode: FcNode = null;
190 | const originalEvent: Event | any = (event as any).originalEvent || event;
191 | const infoText = originalEvent.dataTransfer.getData('text');
192 | if (infoText) {
193 | let dropNodeInfo: DropNodeInfo = null;
194 | try {
195 | dropNodeInfo = JSON.parse(infoText);
196 | } catch (e) {}
197 | if (dropNodeInfo && dropNodeInfo.dropTargetId) {
198 | if (this.modelService.canvasHtmlElement.id &&
199 | this.modelService.canvasHtmlElement.id === dropNodeInfo.dropTargetId) {
200 | dropNode = dropNodeInfo.node;
201 | const offset = $(this.modelService.canvasHtmlElement).offset();
202 | const x = event.clientX - offset.left;
203 | const y = event.clientY - offset.top;
204 | dropNode.x = Math.round(this.getXCoordinate(dropNodeInfo.offsetX + x));
205 | dropNode.y = Math.round(this.getYCoordinate(dropNodeInfo.offsetY + y));
206 | }
207 | }
208 | }
209 | if (dropNode) {
210 | this.modelService.dropNode(event, dropNode);
211 | event.preventDefault();
212 | return false;
213 | } else if (this.nodeDraggingScope.draggedNodes.length) {
214 | return this.applyFunction(() => {
215 | for (let i = 0; i < this.nodeDraggingScope.draggedNodes.length; i++) {
216 | const draggedNode = this.nodeDraggingScope.draggedNodes[i];
217 | const dragOffset = this.dragOffsets[i];
218 | draggedNode.x = Math.round(this.getXCoordinate(dragOffset.x + event.clientX));
219 | draggedNode.y = Math.round(this.getYCoordinate(dragOffset.y + event.clientY));
220 | }
221 | event.preventDefault();
222 | this.modelService.notifyModelChanged();
223 | return false;
224 | });
225 | }
226 | }
227 |
228 | public dragover(event: Event | any) {
229 | if (nodeDropScope.dropElement) {
230 | const offsetInfo = nodeDropScope.dropElement.offsetInfo;
231 | nodeDropScope.dropElement.style.left = (offsetInfo.offsetX + event.clientX) + 'px';
232 | nodeDropScope.dropElement.style.top = (offsetInfo.offsetY + event.clientY) + 'px';
233 | if (this.nodeDraggingScope.shadowDragStarted) {
234 | this.applyFunction(() => {
235 | this.destinationHtmlElements[0].style.display = this.oldDisplayStyles[0];
236 | this.nodeDraggingScope.shadowDragStarted = false;
237 | });
238 | }
239 | event.preventDefault();
240 | return;
241 | }
242 | if (this.modelService.isDropSource()) {
243 | event.preventDefault();
244 | return;
245 | }
246 | if (!this.nodeDraggingScope.draggedNodes.length) {
247 | event.preventDefault();
248 | return;
249 | }
250 | if (this.dragAnimation === FlowchartConstants.dragAnimationRepaint) {
251 | if (this.nodeDraggingScope.draggedNodes.length) {
252 | return this.applyFunction(() => {
253 | for (let i = 0; i < this.nodeDraggingScope.draggedNodes.length; i++) {
254 | const draggedNode = this.nodeDraggingScope.draggedNodes[i];
255 | const dragOffset = this.dragOffsets[i];
256 | draggedNode.x = this.getXCoordinate(dragOffset.x + event.clientX);
257 | draggedNode.y = this.getYCoordinate(dragOffset.y + event.clientY);
258 | this.resizeCanvas(draggedNode, this.draggedElements[i]);
259 | }
260 | event.preventDefault();
261 | this.modelService.notifyModelChanged();
262 | return false;
263 | });
264 | }
265 | } else if (this.dragAnimation === FlowchartConstants.dragAnimationShadow) {
266 | if (this.nodeDraggingScope.draggedNodes.length) {
267 | if (this.nodeDraggingScope.shadowDragStarted) {
268 | this.applyFunction(() => {
269 | for (let i = 0; i < this.nodeDraggingScope.draggedNodes.length; i++) {
270 | this.destinationHtmlElements[i].style.display = this.oldDisplayStyles[i];
271 | }
272 | this.nodeDraggingScope.shadowDragStarted = false;
273 | });
274 | }
275 | for (let i = 0; i < this.nodeDraggingScope.draggedNodes.length; i++) {
276 | const draggedNode = this.nodeDraggingScope.draggedNodes[i];
277 | const dragOffset = this.dragOffsets[i];
278 | this.nodeDraggingScope.shadowElements[i].css('left', this.getXCoordinate(dragOffset.x + event.clientX) + 'px');
279 | this.nodeDraggingScope.shadowElements[i].css('top', this.getYCoordinate(dragOffset.y + event.clientY) + 'px');
280 | this.resizeCanvas(draggedNode, this.draggedElements[i]);
281 | }
282 | event.preventDefault();
283 | }
284 | }
285 | }
286 |
287 | public dragend(event: Event | any) {
288 | this.applyFunction(() => {
289 | if (nodeDropScope.dropElement) {
290 | nodeDropScope.dropElement.parentNode.removeChild(nodeDropScope.dropElement);
291 | nodeDropScope.dropElement = null;
292 | }
293 | if (this.modelService.isDropSource()) {
294 | return;
295 | }
296 | if (this.nodeDraggingScope.shadowElements.length) {
297 | for (let i = 0; i < this.nodeDraggingScope.draggedNodes.length; i++) {
298 | const draggedNode = this.nodeDraggingScope.draggedNodes[i];
299 | const shadowElement = this.nodeDraggingScope.shadowElements[i];
300 | draggedNode.x = parseInt(shadowElement.css('left').replace('px', ''), 10);
301 | draggedNode.y = parseInt(shadowElement.css('top').replace('px', ''), 10);
302 | this.modelService.canvasHtmlElement.removeChild(shadowElement[0]);
303 | }
304 | this.nodeDraggingScope.shadowElements.length = 0;
305 | this.modelService.notifyModelChanged();
306 | }
307 |
308 | if (this.nodeDraggingScope.draggedNodes.length) {
309 | this.nodeDraggingScope.draggedNodes.length = 0;
310 | this.draggedElements.length = 0;
311 | this.dragOffsets.length = 0;
312 | }
313 | });
314 | }
315 |
316 | }
317 |
318 | export interface NodeDraggingScope {
319 | draggedNodes: Array;
320 | shadowElements: Array>;
321 | shadowDragStarted: boolean;
322 | dropElement: HTMLElement;
323 | }
324 |
325 | export interface NodeDropElement extends HTMLElement {
326 | offsetInfo?: {
327 | offsetX: number;
328 | offsetY: number;
329 | };
330 | }
331 |
332 | export interface NodeDropScope {
333 | dropElement: NodeDropElement;
334 | }
335 |
336 | export interface DropNodeInfo {
337 | node: FcNode;
338 | dropTargetId: string;
339 | offsetX: number;
340 | offsetY: number;
341 | }
342 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/node.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | position: absolute;
3 | z-index: 1;
4 | &.fc-dragging {
5 | z-index: 10;
6 | }
7 | }
8 |
9 | :host ::ng-deep {
10 | .fc-leftConnectors, .fc-rightConnectors {
11 | position: absolute;
12 | top: 0;
13 | height: 100%;
14 |
15 | display: flex;
16 | flex-direction: column;
17 |
18 | z-index: -10;
19 | .fc-magnet {
20 | align-items: center;
21 | }
22 | }
23 |
24 | .fc-leftConnectors {
25 | left: -20px;
26 | }
27 |
28 | .fc-rightConnectors {
29 | right: -20px;
30 | }
31 |
32 | .fc-magnet {
33 | display: flex;
34 | flex-grow: 1;
35 | height: 60px;
36 |
37 | justify-content: center;
38 | }
39 |
40 | .fc-connector {
41 | width: 18px;
42 | height: 18px;
43 |
44 | border: 10px solid transparent;
45 | -moz-background-clip: padding; /* Firefox 3.6 */
46 | -webkit-background-clip: padding; /* Safari 4? Chrome 6? */
47 | background-clip: padding-box;
48 | border-radius: 50% 50%;
49 | background-color: #F7A789;
50 | color: #fff;
51 | pointer-events: all;
52 |
53 | &.fc-hover {
54 | background-color: #000;
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/node.component.ts:
--------------------------------------------------------------------------------
1 | import {
2 | AfterViewInit,
3 | Component,
4 | ComponentFactoryResolver,
5 | Directive,
6 | ElementRef,
7 | HostBinding,
8 | HostListener,
9 | Inject,
10 | Input,
11 | OnChanges,
12 | OnInit,
13 | SimpleChanges,
14 | ViewChild,
15 | ViewContainerRef
16 | } from '@angular/core';
17 | import {
18 | FC_NODE_COMPONENT_CONFIG,
19 | FcCallbacks,
20 | FcConnector,
21 | FcNode,
22 | FcNodeComponentConfig,
23 | FcNodeRectInfo,
24 | FlowchartConstants,
25 | UserNodeCallbacks
26 | } from './ngx-flowchart.models';
27 | import { FcModelService } from './model.service';
28 |
29 | @Component({
30 | // eslint-disable-next-line @angular-eslint/component-selector
31 | selector: 'fc-node',
32 | template: ' ',
33 | styleUrls: ['./node.component.scss']
34 | })
35 | export class FcNodeContainerComponent implements OnInit, AfterViewInit, OnChanges {
36 |
37 | @Input()
38 | callbacks: FcCallbacks;
39 |
40 | @Input()
41 | userNodeCallbacks: UserNodeCallbacks;
42 |
43 | @Input()
44 | node: FcNode;
45 |
46 | @Input()
47 | selected: boolean;
48 |
49 | @Input()
50 | edit: boolean;
51 |
52 | @Input()
53 | underMouse: boolean;
54 |
55 | @Input()
56 | mouseOverConnector: FcConnector;
57 |
58 | @Input()
59 | modelservice: FcModelService;
60 |
61 | @Input()
62 | dragging: boolean;
63 |
64 | @HostBinding('attr.id')
65 | get nodeId(): string {
66 | return this.node.id;
67 | }
68 |
69 | @HostBinding('style.top')
70 | get top(): string {
71 | return this.node.y + 'px';
72 | }
73 |
74 | @HostBinding('style.left')
75 | get left(): string {
76 | return this.node.x + 'px';
77 | }
78 |
79 | nodeComponent: FcNodeComponent;
80 |
81 | @ViewChild('nodeContent', {read: ViewContainerRef, static: true}) nodeContentContainer: ViewContainerRef;
82 |
83 | constructor(@Inject(FC_NODE_COMPONENT_CONFIG) private nodeComponentConfig: FcNodeComponentConfig,
84 | private elementRef: ElementRef,
85 | private componentFactoryResolver: ComponentFactoryResolver) {
86 | }
87 |
88 | ngOnInit(): void {
89 | if (!this.userNodeCallbacks) {
90 | this.userNodeCallbacks = {};
91 | }
92 | this.userNodeCallbacks.nodeEdit = this.userNodeCallbacks.nodeEdit || (() => {});
93 | this.userNodeCallbacks.doubleClick = this.userNodeCallbacks.doubleClick || (() => {});
94 | this.userNodeCallbacks.mouseDown = this.userNodeCallbacks.mouseDown || (() => {});
95 | this.userNodeCallbacks.mouseEnter = this.userNodeCallbacks.mouseEnter || (() => {});
96 | this.userNodeCallbacks.mouseLeave = this.userNodeCallbacks.mouseLeave || (() => {});
97 |
98 | const element = $(this.elementRef.nativeElement);
99 | element.addClass(FlowchartConstants.nodeClass);
100 | if (!this.node.readonly) {
101 | element.attr('draggable', 'true');
102 | }
103 | this.updateNodeClass();
104 | this.modelservice.nodes.setHtmlElement(this.node.id, element[0]);
105 | this.nodeContentContainer.clear();
106 | const componentFactory = this.componentFactoryResolver.resolveComponentFactory(this.nodeComponentConfig.nodeComponentType);
107 | const componentRef = this.nodeContentContainer.createComponent(componentFactory);
108 | this.nodeComponent = componentRef.instance;
109 | this.nodeComponent.callbacks = this.callbacks;
110 | this.nodeComponent.userNodeCallbacks = this.userNodeCallbacks;
111 | this.nodeComponent.node = this.node;
112 | this.nodeComponent.modelservice = this.modelservice;
113 | this.updateNodeComponent();
114 | this.nodeComponent.width = this.elementRef.nativeElement.offsetWidth;
115 | this.nodeComponent.height = this.elementRef.nativeElement.offsetHeight;
116 | }
117 |
118 | ngAfterViewInit(): void {
119 | this.nodeComponent.width = this.elementRef.nativeElement.offsetWidth;
120 | this.nodeComponent.height = this.elementRef.nativeElement.offsetHeight;
121 | }
122 |
123 | ngOnChanges(changes: SimpleChanges): void {
124 | let updateNode = false;
125 | for (const propName of Object.keys(changes)) {
126 | const change = changes[propName];
127 | if (!change.firstChange && change.currentValue !== change.previousValue) {
128 | if (['selected', 'edit', 'underMouse', 'mouseOverConnector', 'dragging'].includes(propName)) {
129 | updateNode = true;
130 | }
131 | }
132 | }
133 | if (updateNode) {
134 | this.updateNodeClass();
135 | this.updateNodeComponent();
136 | }
137 | }
138 |
139 | private updateNodeClass() {
140 | const element = $(this.elementRef.nativeElement);
141 | this.toggleClass(element, FlowchartConstants.selectedClass, this.selected);
142 | this.toggleClass(element, FlowchartConstants.editClass, this.edit);
143 | this.toggleClass(element, FlowchartConstants.hoverClass, this.underMouse);
144 | this.toggleClass(element, FlowchartConstants.draggingClass, this.dragging);
145 | }
146 |
147 | private updateNodeComponent() {
148 | this.nodeComponent.selected = this.selected;
149 | this.nodeComponent.edit = this.edit;
150 | this.nodeComponent.underMouse = this.underMouse;
151 | this.nodeComponent.mouseOverConnector = this.mouseOverConnector;
152 | this.nodeComponent.dragging = this.dragging;
153 | }
154 |
155 | private toggleClass(element: JQuery, clazz: string, set: boolean) {
156 | if (set) {
157 | element.addClass(clazz);
158 | } else {
159 | element.removeClass(clazz);
160 | }
161 | }
162 |
163 | @HostListener('mousedown', ['$event'])
164 | mousedown(event: MouseEvent) {
165 | event.stopPropagation();
166 | }
167 |
168 | @HostListener('dragstart', ['$event'])
169 | dragstart(event: Event | any) {
170 | if (!this.node.readonly) {
171 | this.callbacks.nodeDragstart(event, this.node);
172 | }
173 | }
174 |
175 | @HostListener('dragend', ['$event'])
176 | dragend(event: Event | any) {
177 | if (!this.node.readonly) {
178 | this.callbacks.nodeDragend(event);
179 | }
180 | }
181 |
182 | @HostListener('click', ['$event'])
183 | click(event: MouseEvent) {
184 | if (!this.node.readonly) {
185 | this.callbacks.nodeClicked(event, this.node);
186 | }
187 | }
188 |
189 | @HostListener('mouseover', ['$event'])
190 | mouseover(event: MouseEvent) {
191 | if (!this.node.readonly) {
192 | this.callbacks.nodeMouseOver(event, this.node);
193 | }
194 | }
195 |
196 | @HostListener('mouseout', ['$event'])
197 | mouseout(event: MouseEvent) {
198 | if (!this.node.readonly) {
199 | this.callbacks.nodeMouseOut(event, this.node);
200 | }
201 | }
202 |
203 | }
204 |
205 | @Directive()
206 | // tslint:disable-next-line:directive-class-suffix
207 | export abstract class FcNodeComponent implements OnInit {
208 |
209 | @Input()
210 | callbacks: FcCallbacks;
211 |
212 | @Input()
213 | userNodeCallbacks: UserNodeCallbacks;
214 |
215 | @Input()
216 | node: FcNode;
217 |
218 | @Input()
219 | selected: boolean;
220 |
221 | @Input()
222 | edit: boolean;
223 |
224 | @Input()
225 | underMouse: boolean;
226 |
227 | @Input()
228 | mouseOverConnector: FcConnector;
229 |
230 | @Input()
231 | modelservice: FcModelService;
232 |
233 | @Input()
234 | dragging: boolean;
235 |
236 | flowchartConstants = FlowchartConstants;
237 |
238 | width: number;
239 |
240 | height: number;
241 |
242 | nodeRectInfo: FcNodeRectInfo = {
243 | top: () => this.node.y,
244 |
245 | left: () => this.node.x,
246 |
247 | bottom: () => this.node.y + this.height,
248 |
249 | right: () => this.node.x + this.width,
250 |
251 | width: () => this.width,
252 |
253 | height: () => this.height
254 | };
255 |
256 | ngOnInit(): void {
257 | }
258 |
259 | }
260 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/rectangleselect.service.ts:
--------------------------------------------------------------------------------
1 | import { FcModelService } from './model.service';
2 | import { FcRectBox } from './ngx-flowchart.models';
3 | import scrollparent from './scrollparent';
4 |
5 | interface Rectangle {
6 | x1: number;
7 | x2: number;
8 | y1: number;
9 | y2: number;
10 | }
11 |
12 | export class FcRectangleSelectService {
13 |
14 | private readonly selectRect: Rectangle = {
15 | x1: 0,
16 | x2: 0,
17 | y1: 0,
18 | y2: 0
19 | };
20 |
21 | private readonly modelService: FcModelService;
22 | private readonly selectElement: HTMLElement;
23 | private readonly $canvasElement: JQuery;
24 | private readonly $scrollParent: JQuery;
25 | private readonly applyFunction: (fn: (...args: any[]) => T) => T;
26 |
27 | constructor(modelService: FcModelService,
28 | selectElement: HTMLElement,
29 | applyFunction: (fn: (...args: any[]) => T) => T) {
30 | this.modelService = modelService;
31 | this.selectElement = selectElement;
32 | this.$canvasElement = $(this.modelService.canvasHtmlElement);
33 | this.$scrollParent = $(scrollparent(this.modelService.canvasHtmlElement));
34 | this.applyFunction = applyFunction;
35 | }
36 |
37 | public mousedown(e: MouseEvent) {
38 | if (this.modelService.isEditable() && !e.ctrlKey && !e.metaKey && e.button === 0
39 | && this.selectElement.hidden) {
40 | this.selectElement.hidden = false;
41 | const offset = this.$canvasElement.offset();
42 | this.selectRect.x1 = Math.round(e.pageX - offset.left);
43 | this.selectRect.y1 = Math.round(e.pageY - offset.top);
44 | this.selectRect.x2 = this.selectRect.x1;
45 | this.selectRect.y2 = this.selectRect.y1;
46 | this.updateSelectRect();
47 | }
48 | }
49 |
50 | public mousemove(e: MouseEvent) {
51 | if (this.modelService.isEditable() && !e.ctrlKey && !e.metaKey && e.button === 0
52 | && !this.selectElement.hidden) {
53 | const offset = this.$canvasElement.offset();
54 | this.selectRect.x2 = Math.round(e.pageX - offset.left);
55 | this.selectRect.y2 = Math.round(e.pageY - offset.top);
56 | this.updateScroll(offset);
57 | this.updateSelectRect();
58 | }
59 | }
60 |
61 | private updateScroll(offset: JQuery.Coordinates) {
62 | const rect = this.$scrollParent[0].getBoundingClientRect();
63 | const bottom = rect.bottom - offset.top;
64 | const right = rect.right - offset.left;
65 | const top = rect.top - offset.top;
66 | const left = rect.left - offset.left;
67 | if (this.selectRect.y2 - top < 25) {
68 | const topScroll = 25 - (this.selectRect.y2 - top);
69 | const scroll = this.$scrollParent.scrollTop();
70 | this.$scrollParent.scrollTop(scroll - topScroll);
71 | } else if (bottom - this.selectRect.y2 < 40) {
72 | const bottomScroll = 40 - (bottom - this.selectRect.y2);
73 | const scroll = this.$scrollParent.scrollTop();
74 | this.$scrollParent.scrollTop(scroll + bottomScroll);
75 | }
76 | if (this.selectRect.x2 - left < 25) {
77 | const leftScroll = 25 - (this.selectRect.x2 - left);
78 | const scroll = this.$scrollParent.scrollLeft();
79 | this.$scrollParent.scrollLeft(scroll - leftScroll);
80 | } else if (right - this.selectRect.x2 < 40) {
81 | const rightScroll = 40 - (right - this.selectRect.x2);
82 | const scroll = this.$scrollParent.scrollLeft();
83 | this.$scrollParent.scrollLeft(scroll + rightScroll);
84 | }
85 | }
86 |
87 | public mouseup(e: MouseEvent) {
88 | if (this.modelService.isEditable() && !e.ctrlKey && !e.metaKey && e.button === 0
89 | && !this.selectElement.hidden) {
90 | const rectBox = this.selectElement.getBoundingClientRect() as FcRectBox;
91 | this.selectElement.hidden = true;
92 | this.selectObjects(rectBox);
93 | }
94 | }
95 |
96 | private updateSelectRect() {
97 | const x3 = Math.min(this.selectRect.x1, this.selectRect.x2);
98 | const x4 = Math.max(this.selectRect.x1, this.selectRect.x2);
99 | const y3 = Math.min(this.selectRect.y1, this.selectRect.y2);
100 | const y4 = Math.max(this.selectRect.y1, this.selectRect.y2);
101 | this.selectElement.style.left = x3 + 'px';
102 | this.selectElement.style.top = y3 + 'px';
103 | this.selectElement.style.width = x4 - x3 + 'px';
104 | this.selectElement.style.height = y4 - y3 + 'px';
105 | }
106 |
107 | private selectObjects(rectBox: FcRectBox) {
108 | this.applyFunction(() => {
109 | this.modelService.selectAllInRect(rectBox);
110 | });
111 | }
112 |
113 | }
114 |
115 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/lib/scrollparent.ts:
--------------------------------------------------------------------------------
1 | const regex = /(auto|scroll)/;
2 |
3 | const style = (node: Element, prop: string): string =>
4 | getComputedStyle(node, null).getPropertyValue(prop);
5 |
6 | const scroll = (node: Element) =>
7 | regex.test(
8 | style(node, 'overflow') +
9 | style(node, 'overflow-y') +
10 | style(node, 'overflow-x'));
11 |
12 | const scrollparent = (node: HTMLElement): HTMLElement =>
13 | !node || node === document.body
14 | ? document.body
15 | : scroll(node)
16 | ? node
17 | : scrollparent(node.parentNode as HTMLElement);
18 |
19 | export default scrollparent;
20 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/src/public-api.ts:
--------------------------------------------------------------------------------
1 | /*
2 | * Public API Surface of ngx-flowchart
3 | */
4 |
5 | export * from './lib/ngx-flowchart.component';
6 | export * from './lib/ngx-flowchart.module';
7 | export * from './lib/ngx-flowchart.models';
8 | export { FcNodeComponent } from './lib/node.component';
9 | export { FcMagnetDirective } from './lib/magnet.directive';
10 | export { FcConnectorDirective } from './lib/connector.directive';
11 | export { DefaultFcNodeComponent } from './lib/default-node.component';
12 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/tsconfig.lib.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "../../tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "../../out-tsc/lib",
5 | "declaration": true,
6 | "declarationMap": true,
7 | "inlineSources": true,
8 | "types": ["jquery"]
9 | },
10 | "exclude": [
11 | "**/*.spec.ts"
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/projects/ngx-flowchart/tsconfig.lib.prod.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.lib.json",
3 | "compilerOptions": {
4 | "declarationMap": false
5 | },
6 | "angularCompilerOptions": {
7 | "compilationMode": "partial"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | Add Node
13 | Delete Selected
17 |
18 | Activate Workflow
19 |
20 |
21 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/app/app.component.scss:
--------------------------------------------------------------------------------
1 | :host {
2 | display: flex;
3 | flex: 1;
4 | overflow: hidden;
5 | outline: none;
6 |
7 | .fc-container {
8 | display: flex;
9 | flex: 1;
10 | flex-direction: row;
11 | overflow: hidden;
12 | }
13 |
14 | .fc-left-pane {
15 | flex: 0.15;
16 | overflow: auto;
17 | }
18 |
19 | .fc-divider {
20 | flex: 0.01;
21 | }
22 |
23 | .fc-right-pane {
24 | flex: 0.84;
25 | overflow: auto;
26 | }
27 |
28 | .button-overlay {
29 | position: absolute;
30 | top: 40px;
31 | z-index: 10;
32 | }
33 |
34 | .button-overlay button {
35 | display: block;
36 | padding: 10px;
37 | margin-bottom: 15px;
38 | border-radius: 10px;
39 | border: none;
40 | box-shadow: none;
41 | color: #fff;
42 | font-size: 20px;
43 | background-color: #F15B26;
44 | user-select: none;
45 | }
46 |
47 | .button-overlay button:hover:not(:disabled) {
48 | border: 4px solid #b03911;
49 | border-radius: 5px;
50 | margin: -4px;
51 | margin-bottom: 11px;
52 | }
53 |
54 | .button-overlay button:disabled {
55 | -webkit-filter: brightness(70%);
56 | filter: brightness(70%);
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { AfterViewInit, Component, HostBinding, HostListener, ViewChild } from '@angular/core';
2 | import { FcModel, FcNode, FlowchartConstants, NgxFlowchartComponent, UserCallbacks } from 'ngx-flowchart-dev';
3 | import { of } from 'rxjs';
4 | import { DELETE } from '@angular/cdk/keycodes';
5 |
6 | @Component({
7 | selector: 'app-root',
8 | templateUrl: './app.component.html',
9 | styleUrls: ['./app.component.scss']
10 | })
11 | export class AppComponent implements AfterViewInit {
12 |
13 | @HostBinding('attr.tabindex')
14 | get tabindex(): string {
15 | return '0';
16 | }
17 |
18 | flowchartConstants = FlowchartConstants;
19 |
20 | nodeTypesFlowchartselected = [];
21 | nodeTypesModel: FcModel = {
22 | nodes: [],
23 | edges: []
24 | };
25 |
26 | flowchartselected = [];
27 | model: FcModel = {
28 | nodes: [],
29 | edges: []
30 | };
31 | nextNodeID = 10;
32 | nextConnectorID = 20;
33 |
34 | callbacks: UserCallbacks = {
35 | edgeDoubleClick: (event, edge) => {
36 | console.log('Edge double clicked.');
37 | },
38 | edgeEdit: (event, edge) => {
39 | const label = prompt('Enter a link label:', edge.label);
40 | if (label) {
41 | edge.label = label;
42 | }
43 | },
44 | edgeMouseOver: event => {
45 | console.log('mouserover');
46 | },
47 | isValidEdge: (source, destination) =>
48 | source.type === FlowchartConstants.rightConnectorType && destination.type === FlowchartConstants.leftConnectorType
49 | ,
50 | createEdge: (event, edge) => {
51 | if (!edge.label) {
52 | const label = prompt('Enter a link label:', 'New label');
53 | edge.label = label;
54 | }
55 | return of(edge);
56 | },
57 | dropNode: (event, node) => {
58 | const name = prompt('Enter a node name:', node.name);
59 | if (name) {
60 | node.name = name;
61 | node.id = (this.nextNodeID++) + '';
62 | node.connectors = [
63 | {
64 | id: (this.nextConnectorID++) + '',
65 | type: FlowchartConstants.leftConnectorType
66 | },
67 | {
68 | id: (this.nextConnectorID++) + '',
69 | type: FlowchartConstants.rightConnectorType
70 | }
71 | ];
72 | this.model.nodes.push(node);
73 | }
74 | },
75 | edgeAdded: edge => {
76 | console.log('edge added');
77 | console.log(edge);
78 | },
79 | nodeRemoved: node => {
80 | console.log('node removed');
81 | console.log(node);
82 | },
83 | edgeRemoved: edge => {
84 | console.log('edge removed');
85 | console.log(edge);
86 | },
87 | nodeCallbacks: {
88 | doubleClick: event => {
89 | console.log('Node was doubleclicked.');
90 | },
91 | nodeEdit: (event, node) => {
92 | const name = prompt('Enter a node name:', node.name);
93 | if (name) {
94 | node.name = name;
95 | }
96 | }
97 | }
98 | };
99 |
100 | @ViewChild('fcCanvas', {static: true}) fcCanvas: NgxFlowchartComponent;
101 |
102 | constructor() {
103 | this.initData();
104 | }
105 |
106 | ngAfterViewInit(): void {
107 | console.log(this.fcCanvas.modelService);
108 | }
109 |
110 | private initData() {
111 | for (let i = 0; i < 10; i++) {
112 | const node: FcNode = {
113 | name: 'type' + i,
114 | id: (i + 1) + '',
115 | x: 50,
116 | y: 100 * (i + 1),
117 | connectors: [
118 | {
119 | type: FlowchartConstants.leftConnectorType,
120 | id: (i * 2 + 1) + ''
121 | },
122 | {
123 | type: FlowchartConstants.rightConnectorType,
124 | id: (i * 2 + 2) + ''
125 | }
126 | ]
127 | };
128 | this.nodeTypesModel.nodes.push(node);
129 | }
130 | this.model.nodes.push(...
131 | [
132 | {
133 | name: 'ngxFlowchart',
134 | readonly: true,
135 | id: '2',
136 | x: 300,
137 | y: 100,
138 | color: '#000',
139 | borderColor: '#000',
140 | connectors: [
141 | {
142 | type: FlowchartConstants.leftConnectorType,
143 | id: '1'
144 | },
145 | {
146 | type: FlowchartConstants.rightConnectorType,
147 | id: '2'
148 | }
149 | ]
150 | },
151 | {
152 | name: 'Implemented with Angular',
153 | id: '3',
154 | x: 600,
155 | y: 100,
156 | color: '#F15B26',
157 | connectors: [
158 | {
159 | type: FlowchartConstants.leftConnectorType,
160 | id: '3'
161 | },
162 | {
163 | type: FlowchartConstants.rightConnectorType,
164 | id: '4'
165 | }
166 | ]
167 | },
168 | {
169 | name: 'Easy Integration',
170 | id: '4',
171 | x: 1000,
172 | y: 100,
173 | color: '#000',
174 | borderColor: '#000',
175 | connectors: [
176 | {
177 | type: FlowchartConstants.leftConnectorType,
178 | id: '5'
179 | },
180 | {
181 | type: FlowchartConstants.rightConnectorType,
182 | id: '6'
183 | }
184 | ]
185 | },
186 | {
187 | name: 'Customizable templates',
188 | id: '5',
189 | x: 1300,
190 | y: 100,
191 | color: '#000',
192 | borderColor: '#000',
193 | connectors: [
194 | {
195 | type: FlowchartConstants.leftConnectorType,
196 | id: '7'
197 | },
198 | {
199 | type: FlowchartConstants.rightConnectorType,
200 | id: '8'
201 | }
202 | ]
203 | }
204 | ]
205 | );
206 | this.model.edges.push(...
207 | [
208 | {
209 | source: '2',
210 | destination: '3',
211 | label: 'label1'
212 | },
213 | {
214 | source: '4',
215 | destination: '5',
216 | label: 'label2'
217 | },
218 | {
219 | source: '6',
220 | destination: '7',
221 | label: 'label3'
222 | }
223 | ]
224 | );
225 | }
226 |
227 | @HostListener('keydown.control.a', ['$event'])
228 | public onCtrlA(event: KeyboardEvent) {
229 | this.fcCanvas.modelService.selectAll();
230 | }
231 |
232 | @HostListener('keydown.esc', ['$event'])
233 | public onEsc(event: KeyboardEvent) {
234 | this.fcCanvas.modelService.deselectAll();
235 | }
236 |
237 | @HostListener('keydown', ['$event'])
238 | public onKeydown(event: KeyboardEvent) {
239 | if (event.keyCode === DELETE) {
240 | this.fcCanvas.modelService.deleteSelected();
241 | }
242 | }
243 |
244 | public addNewNode() {
245 | const nodeName = prompt('Enter a node name:', 'New node');
246 | if (!nodeName) {
247 | return;
248 | }
249 |
250 | const newNode: FcNode = {
251 | name: nodeName,
252 | id: (this.nextNodeID++) + '',
253 | x: 200,
254 | y: 100,
255 | color: '#F15B26',
256 | connectors: [
257 | {
258 | id: (this.nextConnectorID++) + '',
259 | type: FlowchartConstants.leftConnectorType
260 | },
261 | {
262 | id: (this.nextConnectorID++) + '',
263 | type: FlowchartConstants.rightConnectorType
264 | }
265 | ]
266 | };
267 | this.model.nodes.push(newNode);
268 | }
269 |
270 | public activateWorkflow() {
271 | this.model.edges.forEach((edge) => {
272 | edge.active = !edge.active;
273 | });
274 | this.fcCanvas.modelService.detectChanges();
275 | }
276 |
277 | public deleteSelected() {
278 | this.fcCanvas.modelService.deleteSelected();
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { BrowserModule } from '@angular/platform-browser';
2 | import { NgModule } from '@angular/core';
3 |
4 | import { AppComponent } from './app.component';
5 | import { FC_NODE_COMPONENT_CONFIG, NgxFlowchartModule } from 'ngx-flowchart-dev';
6 | import { TestFcNodeComponent } from './test-node.component';
7 |
8 | @NgModule({
9 | /*providers: [
10 | {
11 | provide: FC_NODE_COMPONENT_CONFIG,
12 | useValue: {
13 | nodeComponentType: TestFcNodeComponent
14 | }
15 | }
16 | ],*/
17 | declarations: [
18 | AppComponent,
19 | TestFcNodeComponent
20 | ],
21 | imports: [
22 | BrowserModule,
23 | NgxFlowchartModule
24 | ],
25 | bootstrap: [AppComponent]
26 | })
27 | export class AppModule { }
28 |
--------------------------------------------------------------------------------
/src/app/test-node.component.html:
--------------------------------------------------------------------------------
1 |
3 | {{ node | json }}
4 |
5 |
--------------------------------------------------------------------------------
/src/app/test-node.component.ts:
--------------------------------------------------------------------------------
1 | import { Component } from '@angular/core';
2 | import { FcNodeComponent } from 'ngx-flowchart-dev';
3 |
4 | @Component({
5 | selector: 'app-default-node',
6 | templateUrl: './test-node.component.html',
7 | styleUrls: []
8 | })
9 | export class TestFcNodeComponent extends FcNodeComponent {
10 |
11 | constructor() {
12 | super();
13 | }
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/assets/.gitkeep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/ngx-flowchart/77c6bf52a3b43baee96fe69a9fe8b0d9a307c241/src/assets/.gitkeep
--------------------------------------------------------------------------------
/src/environments/environment.prod.ts:
--------------------------------------------------------------------------------
1 | export const environment = {
2 | production: true
3 | };
4 |
--------------------------------------------------------------------------------
/src/environments/environment.ts:
--------------------------------------------------------------------------------
1 | // This file can be replaced during build by using the `fileReplacements` array.
2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
3 | // The list of file replacements can be found in `angular.json`.
4 |
5 | export const environment = {
6 | production: false
7 | };
8 |
9 | /*
10 | * For easier debugging in development mode, you can import the following file
11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
12 | *
13 | * This import should be commented out in production mode because it will have a negative impact
14 | * on performance if an error is thrown.
15 | */
16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI.
17 |
--------------------------------------------------------------------------------
/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/thingsboard/ngx-flowchart/77c6bf52a3b43baee96fe69a9fe8b0d9a307c241/src/favicon.ico
--------------------------------------------------------------------------------
/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NgxFlowchart
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import { enableProdMode } from '@angular/core';
2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
3 |
4 | import { AppModule } from './app/app.module';
5 | import { environment } from './environments/environment';
6 |
7 | if (environment.production) {
8 | enableProdMode();
9 | }
10 |
11 | platformBrowserDynamic().bootstrapModule(AppModule)
12 | .catch(err => console.error(err));
13 |
--------------------------------------------------------------------------------
/src/polyfills.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * This file includes polyfills needed by Angular and is loaded before the app.
3 | * You can add your own extra polyfills to this file.
4 | *
5 | * This file is divided into 2 sections:
6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
8 | * file.
9 | *
10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
13 | *
14 | * Learn more in https://angular.io/guide/browser-support
15 | */
16 |
17 | /***************************************************************************************************
18 | * BROWSER POLYFILLS
19 | */
20 |
21 | /**
22 | * By default, zone.js will patch all possible macroTask and DomEvents
23 | * user can disable parts of macroTask/DomEvents patch by setting following flags
24 | * because those flags need to be set before `zone.js` being loaded, and webpack
25 | * will put import in the top of bundle, so user need to create a separate file
26 | * in this directory (for example: zone-flags.ts), and put the following flags
27 | * into that file, and then add the following code before importing zone.js.
28 | * import './zone-flags.ts';
29 | *
30 | * The flags allowed in zone-flags.ts are listed here.
31 | *
32 | * The following flags will work for all browsers.
33 | *
34 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
35 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
36 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
37 | *
38 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
39 | * with the following flag, it will bypass `zone.js` patch for IE/Edge
40 | *
41 | * (window as any).__Zone_enable_cross_context_check = true;
42 | *
43 | */
44 |
45 | /***************************************************************************************************
46 | * Zone JS is required by default for Angular itself.
47 | */
48 | import 'zone.js'; // Included with Angular CLI.
49 |
50 | /***************************************************************************************************
51 | * APPLICATION IMPORTS
52 | */
53 |
--------------------------------------------------------------------------------
/src/styles.scss:
--------------------------------------------------------------------------------
1 | /* You can add global styles to this file, and also import other style files */
2 |
3 | body {
4 | font-family: sans-serif;
5 | margin: 0;
6 | display: flex;
7 | flex-direction: column;
8 | flex: 1;
9 | height: 100vh;
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.app.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "compilerOptions": {
4 | "outDir": "./out-tsc/app",
5 | "types": ["jquery"]
6 | },
7 | "angularCompilerOptions": {
8 | "fullTemplateTypeCheck": true
9 | },
10 | "files": [
11 | "src/main.ts",
12 | "src/polyfills.ts"
13 | ],
14 | "include": [
15 | "src/**/*.d.ts"
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": false,
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "outDir": "./dist/out-tsc",
6 | "forceConsistentCasingInFileNames": true,
7 | "esModuleInterop": true,
8 | "noImplicitOverride": true,
9 | "noPropertyAccessFromIndexSignature": true,
10 | "noFallthroughCasesInSwitch": true,
11 | "sourceMap": true,
12 | "declaration": false,
13 | "module": "es2020",
14 | "moduleResolution": "node",
15 | "emitDecoratorMetadata": true,
16 | "experimentalDecorators": true,
17 | "importHelpers": true,
18 | "target": "ES2022",
19 | "typeRoots": [
20 | "node_modules/@types"
21 | ],
22 | "lib": [
23 | "es2018",
24 | "dom"
25 | ],
26 | "paths": {
27 | "ngx-flowchart": [
28 | "dist/ngx-flowchart"
29 | ],
30 | "ngx-flowchart/*": [
31 | "dist/ngx-flowchart/*"
32 | ],
33 | "ngx-flowchart-dev": [
34 | "projects/ngx-flowchart/src/public-api"
35 | ],
36 | "ngx-flowchart1": [
37 | "dist/ngx-flowchart1"
38 | ]
39 | },
40 | "useDefineForClassFields": false
41 | },
42 | "angularCompilerOptions": {
43 | "enableI18nLegacyMessageIdFormat": false,
44 | "strictInjectionParameters": true,
45 | "strictInputAccessModifiers": true,
46 | "strictTemplates": false
47 | }
48 | }
49 |
--------------------------------------------------------------------------------