ngx-vflow 1.1.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/lib/vflow/components/edge-label/edge-label.component.mjs +26 -9
- package/esm2022/lib/vflow/components/node/node.component.mjs +3 -3
- package/esm2022/lib/vflow/components/vflow/vflow.component.mjs +10 -2
- package/esm2022/lib/vflow/constants/magic-number-to-fix-glitch-in-chrome.constant.mjs +4 -0
- package/esm2022/lib/vflow/interfaces/edge-label.interface.mjs +1 -1
- package/esm2022/lib/vflow/models/node.model.mjs +4 -1
- package/esm2022/lib/vflow/services/draggable.service.mjs +34 -12
- package/esm2022/lib/vflow/services/flow-settings.service.mjs +2 -1
- package/fesm2022/ngx-vflow.mjs +73 -22
- package/fesm2022/ngx-vflow.mjs.map +1 -1
- package/lib/vflow/components/edge-label/edge-label.component.d.ts +4 -2
- package/lib/vflow/components/vflow/vflow.component.d.ts +8 -1
- package/lib/vflow/constants/magic-number-to-fix-glitch-in-chrome.constant.d.ts +1 -0
- package/lib/vflow/interfaces/edge-label.interface.d.ts +12 -3
- package/lib/vflow/models/node.model.d.ts +2 -0
- package/lib/vflow/services/draggable.service.d.ts +9 -0
- package/lib/vflow/services/flow-settings.service.d.ts +1 -0
- package/package.json +1 -1
|
@@ -3,10 +3,12 @@ import { select } from 'd3-selection';
|
|
|
3
3
|
import { drag } from 'd3-drag';
|
|
4
4
|
import { round } from '../utils/round';
|
|
5
5
|
import { FlowEntitiesService } from './flow-entities.service';
|
|
6
|
+
import { FlowSettingsService } from './flow-settings.service';
|
|
6
7
|
import * as i0 from "@angular/core";
|
|
7
8
|
export class DraggableService {
|
|
8
9
|
constructor() {
|
|
9
10
|
this.entitiesService = inject(FlowEntitiesService);
|
|
11
|
+
this.settingsService = inject(FlowSettingsService);
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
14
|
* Enable draggable behavior for element.
|
|
@@ -65,7 +67,7 @@ export class DraggableService {
|
|
|
65
67
|
x: round(event.x + initialPositions[index].x),
|
|
66
68
|
y: round(event.y + initialPositions[index].y),
|
|
67
69
|
};
|
|
68
|
-
moveNode(model, point);
|
|
70
|
+
this.moveNode(model, point);
|
|
69
71
|
});
|
|
70
72
|
});
|
|
71
73
|
}
|
|
@@ -78,21 +80,41 @@ export class DraggableService {
|
|
|
78
80
|
: // we only can move current node if it's not selected
|
|
79
81
|
[model];
|
|
80
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* @todo make it unit testable
|
|
85
|
+
*/
|
|
86
|
+
moveNode(model, point) {
|
|
87
|
+
point = this.alignToGrid(point);
|
|
88
|
+
const parent = model.parent();
|
|
89
|
+
// keep node in bounds of parent
|
|
90
|
+
if (parent) {
|
|
91
|
+
point.x = Math.min(parent.width() - model.width(), point.x);
|
|
92
|
+
point.x = Math.max(0, point.x);
|
|
93
|
+
point.y = Math.min(parent.height() - model.height(), point.y);
|
|
94
|
+
point.y = Math.max(0, point.y);
|
|
95
|
+
}
|
|
96
|
+
model.setPoint(point);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* @todo make it unit testable
|
|
100
|
+
*/
|
|
101
|
+
alignToGrid(point) {
|
|
102
|
+
const [snapX, snapY] = this.settingsService.snapGrid();
|
|
103
|
+
if (snapX > 1) {
|
|
104
|
+
point.x = align(point.x, snapX);
|
|
105
|
+
}
|
|
106
|
+
if (snapY > 1) {
|
|
107
|
+
point.y = align(point.y, snapY);
|
|
108
|
+
}
|
|
109
|
+
return point;
|
|
110
|
+
}
|
|
81
111
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
82
112
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService }); }
|
|
83
113
|
}
|
|
84
114
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService, decorators: [{
|
|
85
115
|
type: Injectable
|
|
86
116
|
}] });
|
|
87
|
-
function
|
|
88
|
-
|
|
89
|
-
// keep node in bounds of parent
|
|
90
|
-
if (parent) {
|
|
91
|
-
point.x = Math.min(parent.size().width - model.size().width, point.x);
|
|
92
|
-
point.x = Math.max(0, point.x);
|
|
93
|
-
point.y = Math.min(parent.size().height - model.size().height, point.y);
|
|
94
|
-
point.y = Math.max(0, point.y);
|
|
95
|
-
}
|
|
96
|
-
model.setPoint(point);
|
|
117
|
+
function align(num, constant) {
|
|
118
|
+
return Math.ceil(num / constant) * constant;
|
|
97
119
|
}
|
|
98
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
120
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZHJhZ2dhYmxlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ3gtdmZsb3ctbGliL3NyYy9saWIvdmZsb3cvc2VydmljZXMvZHJhZ2dhYmxlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUN0QyxPQUFPLEVBQWUsSUFBSSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBRTVDLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN2QyxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUU5RCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQzs7QUFLOUQsTUFBTSxPQUFPLGdCQUFnQjtJQUQ3QjtRQUVVLG9CQUFlLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDOUMsb0JBQWUsR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQztLQXNIdkQ7SUFwSEM7Ozs7O09BS0c7SUFDSSxNQUFNLENBQUMsT0FBZ0IsRUFBRSxLQUFnQjtRQUM5QyxNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSSxPQUFPLENBQUMsT0FBZ0I7UUFDN0IsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDaEQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSSxPQUFPLENBQUMsT0FBZ0I7UUFDN0IsTUFBTSxDQUFD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Q0FBQztZQUUvQixLQUFLLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxNQUFNLEVBQUUsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDOUQsS0FBSyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDakMsQ0FBQztRQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDeEIsQ0FBQztJQUVEOztPQUVHO0lBQ0ssV0FBVyxDQUFDLEtBQVk7UUFDOUIsTUFBTSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBRXZELElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ2QsS0FBSyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNsQyxDQUFDO1FBRUQsSUFBSSxLQUFLLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDZCxLQUFLLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ2xDLENBQUM7UUFFRCxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7K0dBdkhVLGdCQUFnQjttSEFBaEIsZ0JBQWdCOzs0RkFBaEIsZ0JBQWdCO2tCQUQ1QixVQUFVOztBQTJIWCxTQUFTLEtBQUssQ0FBQyxHQUFXLEVBQUUsUUFBZ0I7SUFDMUMsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsR0FBRyxRQUFRLENBQUMsR0FBRyxRQUFRLENBQUM7QUFDOUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgc2VsZWN0IH0gZnJvbSAnZDMtc2VsZWN0aW9uJztcbmltcG9ydCB7IEQzRHJhZ0V2ZW50LCBkcmFnIH0gZnJvbSAnZDMtZHJhZyc7XG5pbXBvcnQgeyBOb2RlTW9kZWwgfSBmcm9tICcuLi9tb2RlbHMvbm9kZS5tb2RlbCc7XG5pbXBvcnQgeyByb3VuZCB9IGZyb20gJy4uL3V0aWxzL3JvdW5kJztcbmltcG9ydCB7IEZsb3dFbnRpdGllc1NlcnZpY2UgfSBmcm9tICcuL2Zsb3ctZW50aXRpZXMuc2VydmljZSc7XG5pbXBvcnQgeyBQb2ludCB9IGZyb20gJy4uL2ludGVyZmFjZXMvcG9pbnQuaW50ZXJmYWNlJztcbmltcG9ydCB7IEZsb3dTZXR0aW5nc1NlcnZpY2UgfSBmcm9tICcuL2Zsb3ctc2V0dGluZ3Muc2VydmljZSc7XG5cbnR5cGUgRHJhZ0V2ZW50ID0gRDNEcmFnRXZlbnQ8RWxlbWVudCwgdW5rbm93biwgdW5rbm93bj47XG5cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBEcmFnZ2FibGVTZXJ2aWNlIHtcbiAgcHJpdmF0ZSBlbnRpdGllc1NlcnZpY2UgPSBpbmplY3QoRmxvd0VudGl0aWVzU2VydmljZSk7XG4gIHByaXZhdGUgc2V0dGluZ3NTZXJ2aWNlID0gaW5qZWN0KEZsb3dTZXR0aW5nc1NlcnZpY2UpO1xuXG4gIC8qKlxuICAgKiBFbmFibGUgZHJhZ2dhYmxlIGJlaGF2aW9yIGZvciBlbGVtZW50LlxuICAgKlxuICAgKiBAcGFyYW0gZWxlbWVudCB0YXJnZXQgZWxlbWVudCBmb3IgdG9nZ2xpbmcgZHJhZ2dhYmxlXG4gICAqIEBwYXJhbSBtb2RlbCBtb2RlbCB3aXRoIGRhdGEgZm9yIHRoaXMgZWxlbWVudFxuICAgKi9cbiAgcHVibGljIGVuYWJsZShlbGVtZW50OiBFbGVtZW50LCBtb2RlbDogTm9kZU1vZGVsKSB7XG4gICAgc2VsZWN0KGVsZW1lbnQpLmNhbGwodGhpcy5nZXREcmFnQmVoYXZpb3IobW9kZWwpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEaXNhYmxlIGRyYWdnYWJsZSBiZWhhdmlvciBmb3IgZWxlbWVudC5cbiAgICpcbiAgICogQHBhcmFtIGVsZW1lbnQgdGFyZ2V0IGVsZW1lbnQgZm9yIHRvZ2dsaW5nIGRyYWdnYWJsZVxuICAgKiBAcGFyYW0gbW9kZWwgbW9kZWwgd2l0aCBkYXRhIGZvciB0aGlzIGVsZW1lbnRcbiAgICovXG4gIHB1YmxpYyBkaXNhYmxlKGVsZW1lbnQ6IEVsZW1lbnQpIHtcbiAgICBzZWxlY3QoZWxlbWVudCkuY2FsbChkcmFnKCkub24oJ2RyYWcnLCBudWxsKSk7XG4gIH1cblxuICAvKipcbiAgICogVE9ETzogbm90IHNodXJlIGlmIHRoaXMgd29yaywgbmVlZCB0byBjaGVja1xuICAgKlxuICAgKiBAcGFyYW0gZWxlbWVudFxuICAgKi9cbiAgcHVibGljIGRlc3Ryb3koZWxlbWVudDogRWxlbWVudCkge1xuICAgIHNlbGVjdChlbGVtZW50KS5vbignLmRyYWcnLCBudWxsKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBOb2RlIGRyYWcgYmVoYXZpb3IuIFVwZGF0ZWQgbm9kZSdzIGNvb3JkaW5hdGUgYWNjb3JkaW5nIHRvIGRyYWdnaW5nXG4gICAqXG4gICAqIEBwYXJhbSBtb2RlbFxuICAgKiBAcmV0dXJuc1xuICAgKi9cbiAgcHJpdmF0ZSBnZXREcmFnQmVoYXZpb3IobW9kZWw6IE5vZGVNb2RlbCkge1xuICAgIGxldCBkcmFnTm9kZXM6IE5vZGVNb2RlbFtdID0gW107XG4gICAgbGV0IGluaXRpYWxQb3NpdGlvbnM6IFBvaW50W10gPSBbXTtcblxuICAgIGNvbnN0IGZpbHRlckNvbmRpdGlvbiA9IChldmVudDogRXZlbnQpID0+IHtcbiAgICAgIC8vIGlmIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSBkcmFnIGhhbmRsZSwgd2Ugc2hvdWxkIGNoZWNrIGlmIHdlIGFyZSBkcmFnZ2luZyBpdFxuICAgICAgaWYgKG1vZGVsLmRyYWdIYW5kbGVzQ291bnQoKSkge1xuICAgICAgICByZXR1cm4gISEoZXZlbnQudGFyZ2V0IGFzIEVsZW1lbnQpLmNsb3Nlc3QoJy52Zmxvdy1kcmFnLWhhbmRsZScpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIGRyYWcoKVxuICAgICAgLmZpbHRlcihmaWx0ZXJDb25kaXRpb24pXG4gICAgICAub24oJ3N0YXJ0JywgKGV2ZW50OiBEcmFnRXZlbnQpID0+IHtcbiAgICAgICAgZHJhZ05vZGVzID0gdGhpcy5nZXREcmFnTm9kZXMobW9kZWwpO1xuXG4gICAgICAgIGluaXRpYWxQb3NpdGlvbnMgPSBkcmFnTm9kZXMubWFwKChub2RlKSA9PiAoe1xuICAgICAgICAgIHg6IG5vZGUucG9pbnQoKS54IC0gZXZlbnQueCxcbiAgICAgICAgICB5OiBub2RlLnBvaW50KCkueSAtIGV2ZW50LnksXG4gICAgICAgIH0pKTtcbiAgICAgIH0pXG5cbiAgICAgIC5vbignZHJhZycsIChldmVudDogRHJhZ0V2ZW50KSA9PiB7XG4gICAgICAgIGRyYWdOb2Rlcy5mb3JFYWNoKChtb2RlbCwgaW5kZXgpID0+IHtcbiAgICAgICAgICBjb25zdCBwb2ludCA9IHtcbiAgICAgICAgICAgIHg6IHJvdW5kKGV2ZW50LnggKyBpbml0aWFsUG9zaXRpb25zW2luZGV4XS54KSxcbiAgICAgICAgICAgIHk6IHJvdW5kKGV2ZW50LnkgKyBpbml0aWFsUG9zaXRpb25zW2luZGV4XS55KSxcbiAgICAgICAgICB9O1xuXG4gICAgICAgICAgdGhpcy5tb3ZlTm9kZShtb2RlbCwgcG9pbnQpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXREcmFnTm9kZXMobW9kZWw6IE5vZGVNb2RlbCkge1xuICAgIHJldHVybiBtb2RlbC5zZWxlY3RlZCgpXG4gICAgICA/IHRoaXMuZW50aXRpZXNTZXJ2aWNlXG4gICAgICAgICAgLm5vZGVzKClcbiAgICAgICAgICAvLyBzZWxlY3RlZCBkcmFnZ2FibGUgbm9kZXMgKHdpdGggY3VycmVudCBub2RlKVxuICAgICAgICAgIC5maWx0ZXIoKG5vZGUpID0+IG5vZGUuc2VsZWN0ZWQoKSAmJiBub2RlLmRyYWdnYWJsZSgpKVxuICAgICAgOiAvLyB3ZSBvbmx5IGNhbiBtb3ZlIGN1cnJlbnQgbm9kZSBpZiBpdCdzIG5vdCBzZWxlY3RlZFxuICAgICAgICBbbW9kZWxdO1xuICB9XG5cbiAgLyoqXG4gICAqIEB0b2RvIG1ha2UgaXQgdW5pdCB0ZXN0YWJsZVxuICAgKi9cbiAgcHJpdmF0ZSBtb3ZlTm9kZShtb2RlbDogTm9kZU1vZGVsLCBwb2ludDogUG9pbnQpIHtcbiAgICBwb2ludCA9IHRoaXMuYWxpZ25Ub0dyaWQocG9pbnQpO1xuXG4gICAgY29uc3QgcGFyZW50ID0gbW9kZWwucGFyZW50KCk7XG4gICAgLy8ga2VlcCBub2RlIGluIGJvdW5kcyBvZiBwYXJlbnRcbiAgICBpZiAocGFyZW50KSB7XG4gICAgICBwb2ludC54ID0gTWF0aC5taW4ocGFyZW50LndpZHRoKCkgLSBtb2RlbC53aWR0aCgpLCBwb2ludC54KTtcbiAgICAgIHBvaW50LnggPSBNYXRoLm1heCgwLCBwb2ludC54KTtcblxuICAgICAgcG9pbnQueSA9IE1hdGgubWluKHBhcmVudC5oZWlnaHQoKSAtIG1vZGVsLmhlaWdodCgpLCBwb2ludC55KTtcbiAgICAgIHBvaW50LnkgPSBNYXRoLm1heCgwLCBwb2ludC55KTtcbiAgICB9XG5cbiAgICBtb2RlbC5zZXRQb2ludChwb2ludCk7XG4gIH1cblxuICAvKipcbiAgICogQHRvZG8gbWFrZSBpdCB1bml0IHRlc3RhYmxlXG4gICAqL1xuICBwcml2YXRlIGFsaWduVG9HcmlkKHBvaW50OiBQb2ludCkge1xuICAgIGNvbnN0IFtzbmFwWCwgc25hcFldID0gdGhpcy5zZXR0aW5nc1NlcnZpY2Uuc25hcEdyaWQoKTtcblxuICAgIGlmIChzbmFwWCA+IDEpIHtcbiAgICAgIHBvaW50LnggPSBhbGlnbihwb2ludC54LCBzbmFwWCk7XG4gICAgfVxuXG4gICAgaWYgKHNuYXBZID4gMSkge1xuICAgICAgcG9pbnQueSA9IGFsaWduKHBvaW50LnksIHNuYXBZKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcG9pbnQ7XG4gIH1cbn1cblxuZnVuY3Rpb24gYWxpZ24obnVtOiBudW1iZXIsIGNvbnN0YW50OiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gTWF0aC5jZWlsKG51bSAvIGNvbnN0YW50KSAqIGNvbnN0YW50O1xufVxuIl19
|
|
@@ -18,6 +18,7 @@ export class FlowSettingsService {
|
|
|
18
18
|
this.minZoom = signal(0.5);
|
|
19
19
|
this.maxZoom = signal(3);
|
|
20
20
|
this.background = signal({ type: 'solid', color: '#fff' });
|
|
21
|
+
this.snapGrid = signal([1, 1]);
|
|
21
22
|
}
|
|
22
23
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
23
24
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService }); }
|
|
@@ -25,4 +26,4 @@ export class FlowSettingsService {
|
|
|
25
26
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService, decorators: [{
|
|
26
27
|
type: Injectable
|
|
27
28
|
}] });
|
|
28
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmxvdy1zZXR0aW5ncy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvbmd4LXZmbG93LWxpYi9zcmMvbGliL3ZmbG93L3NlcnZpY2VzL2Zsb3ctc2V0dGluZ3Muc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFrQixNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7O0FBSW5FLE1BQU0sT0FBTyxtQkFBbUI7SUFEaEM7UUFFUyx1QkFBa0IsR0FBRyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDekM7O1dBRUc7UUFDSSxTQUFJLEdBQThDLE1BQU0sQ0FBQyxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBRTVFOztXQUVHO1FBQ0ksc0JBQWlCLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRXJDOztXQUVHO1FBQ0ksdUJBQWtCLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRS9CLFlBQU8sR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7UUFFdEIsWUFBTyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUVwQixlQUFVLEdBQUcsTUFBTSxDQUFhLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUVsRSxhQUFRLEdBQUcsTUFBTSxDQUFtQixDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDO0tBQ3BEOytHQXhCWSxtQkFBbUI7bUhBQW5CLG1CQUFtQjs7NEZBQW5CLG1CQUFtQjtrQkFEL0IsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIFdyaXRhYmxlU2lnbmFsLCBzaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEJhY2tncm91bmQgfSBmcm9tICcuLi90eXBlcy9iYWNrZ3JvdW5kLnR5cGUnO1xuXG5ASW5qZWN0YWJsZSgpXG5leHBvcnQgY2xhc3MgRmxvd1NldHRpbmdzU2VydmljZSB7XG4gIHB1YmxpYyBlbnRpdGllc1NlbGVjdGFibGUgPSBzaWduYWwodHJ1ZSk7XG4gIC8qKlxuICAgKiBAc2VlIHtWZmxvd0NvbXBvbmVudC52aWV3fVxuICAgKi9cbiAgcHVibGljIHZpZXc6IFdyaXRhYmxlU2lnbmFsPFtudW1iZXIsIG51bWJlcl0gfCAnYXV0byc+ID0gc2lnbmFsKFs0MDAsIDQwMF0pO1xuXG4gIC8qKlxuICAgKiBTZXQgYmFzZWQgb24gdmlldyBwcm9wZXJ0eS4gTWF5IGNoYW5nZSBpZiB2aWV3IGlzICdhdXRvJ1xuICAgKi9cbiAgcHVibGljIGNvbXB1dGVkRmxvd1dpZHRoID0gc2lnbmFsKDApO1xuXG4gIC8qKlxuICAgKiBTZXQgYmFzZWQgb24gdmlldyBwcm9wZXJ0eS4gTWF5IGNoYW5nZSBpZiB2aWV3IGlzICdhdXRvJ1xuICAgKi9cbiAgcHVibGljIGNvbXB1dGVkRmxvd0hlaWdodCA9IHNpZ25hbCgwKTtcblxuICBwdWJsaWMgbWluWm9vbSA9IHNpZ25hbCgwLjUpO1xuXG4gIHB1YmxpYyBtYXhab29tID0gc2lnbmFsKDMpO1xuXG4gIHB1YmxpYyBiYWNrZ3JvdW5kID0gc2lnbmFsPEJhY2tncm91bmQ+KHsgdHlwZTogJ3NvbGlkJywgY29sb3I6ICcjZmZmJyB9KTtcblxuICBwdWJsaWMgc25hcEdyaWQgPSBzaWduYWw8W251bWJlciwgbnVtYmVyXT4oWzEsIDFdKTtcbn1cbiJdfQ==
|
package/fesm2022/ngx-vflow.mjs
CHANGED
|
@@ -165,6 +165,7 @@ class FlowSettingsService {
|
|
|
165
165
|
this.minZoom = signal(0.5);
|
|
166
166
|
this.maxZoom = signal(3);
|
|
167
167
|
this.background = signal({ type: 'solid', color: '#fff' });
|
|
168
|
+
this.snapGrid = signal([1, 1]);
|
|
168
169
|
}
|
|
169
170
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
170
171
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FlowSettingsService }); }
|
|
@@ -459,6 +460,7 @@ const round = (num) => Math.round(num * 100) / 100;
|
|
|
459
460
|
class DraggableService {
|
|
460
461
|
constructor() {
|
|
461
462
|
this.entitiesService = inject(FlowEntitiesService);
|
|
463
|
+
this.settingsService = inject(FlowSettingsService);
|
|
462
464
|
}
|
|
463
465
|
/**
|
|
464
466
|
* Enable draggable behavior for element.
|
|
@@ -517,7 +519,7 @@ class DraggableService {
|
|
|
517
519
|
x: round(event.x + initialPositions[index].x),
|
|
518
520
|
y: round(event.y + initialPositions[index].y),
|
|
519
521
|
};
|
|
520
|
-
moveNode(model, point);
|
|
522
|
+
this.moveNode(model, point);
|
|
521
523
|
});
|
|
522
524
|
});
|
|
523
525
|
}
|
|
@@ -530,22 +532,42 @@ class DraggableService {
|
|
|
530
532
|
: // we only can move current node if it's not selected
|
|
531
533
|
[model];
|
|
532
534
|
}
|
|
535
|
+
/**
|
|
536
|
+
* @todo make it unit testable
|
|
537
|
+
*/
|
|
538
|
+
moveNode(model, point) {
|
|
539
|
+
point = this.alignToGrid(point);
|
|
540
|
+
const parent = model.parent();
|
|
541
|
+
// keep node in bounds of parent
|
|
542
|
+
if (parent) {
|
|
543
|
+
point.x = Math.min(parent.width() - model.width(), point.x);
|
|
544
|
+
point.x = Math.max(0, point.x);
|
|
545
|
+
point.y = Math.min(parent.height() - model.height(), point.y);
|
|
546
|
+
point.y = Math.max(0, point.y);
|
|
547
|
+
}
|
|
548
|
+
model.setPoint(point);
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* @todo make it unit testable
|
|
552
|
+
*/
|
|
553
|
+
alignToGrid(point) {
|
|
554
|
+
const [snapX, snapY] = this.settingsService.snapGrid();
|
|
555
|
+
if (snapX > 1) {
|
|
556
|
+
point.x = align(point.x, snapX);
|
|
557
|
+
}
|
|
558
|
+
if (snapY > 1) {
|
|
559
|
+
point.y = align(point.y, snapY);
|
|
560
|
+
}
|
|
561
|
+
return point;
|
|
562
|
+
}
|
|
533
563
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
534
564
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService }); }
|
|
535
565
|
}
|
|
536
566
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: DraggableService, decorators: [{
|
|
537
567
|
type: Injectable
|
|
538
568
|
}] });
|
|
539
|
-
function
|
|
540
|
-
|
|
541
|
-
// keep node in bounds of parent
|
|
542
|
-
if (parent) {
|
|
543
|
-
point.x = Math.min(parent.size().width - model.size().width, point.x);
|
|
544
|
-
point.x = Math.max(0, point.x);
|
|
545
|
-
point.y = Math.min(parent.size().height - model.size().height, point.y);
|
|
546
|
-
point.y = Math.max(0, point.y);
|
|
547
|
-
}
|
|
548
|
-
model.setPoint(point);
|
|
569
|
+
function align(num, constant) {
|
|
570
|
+
return Math.ceil(num / constant) * constant;
|
|
549
571
|
}
|
|
550
572
|
|
|
551
573
|
class EdgeTemplateDirective {
|
|
@@ -827,6 +849,10 @@ function isTemplateDynamicGroupNode(node) {
|
|
|
827
849
|
return node.type === 'template-group';
|
|
828
850
|
}
|
|
829
851
|
|
|
852
|
+
// this is a number to fix visual artifact in chrome.
|
|
853
|
+
// the bug reproduces if edgeLabelWrapperRef size fully matched the size of parent foreignObject
|
|
854
|
+
const MAGIC_NUMBER_TO_FIX_GLITCH_IN_CHROME = 2;
|
|
855
|
+
|
|
830
856
|
class NodeModel {
|
|
831
857
|
static { this.defaultWidth = 100; }
|
|
832
858
|
static { this.defaultHeight = 50; }
|
|
@@ -850,6 +876,8 @@ class NodeModel {
|
|
|
850
876
|
this.size$ = toObservable(this.size);
|
|
851
877
|
this.styleWidth = computed(() => `${this.width()}px`);
|
|
852
878
|
this.styleHeight = computed(() => `${this.height()}px`);
|
|
879
|
+
this.foWidth = computed(() => this.width() + MAGIC_NUMBER_TO_FIX_GLITCH_IN_CHROME);
|
|
880
|
+
this.foHeight = computed(() => this.height() + MAGIC_NUMBER_TO_FIX_GLITCH_IN_CHROME);
|
|
853
881
|
this.renderOrder = signal(0);
|
|
854
882
|
this.selected = signal(false);
|
|
855
883
|
this.selected$ = toObservable(this.selected);
|
|
@@ -1752,6 +1780,7 @@ class EdgeLabelComponent {
|
|
|
1752
1780
|
constructor() {
|
|
1753
1781
|
this.zone = inject(NgZone);
|
|
1754
1782
|
this.destroyRef = inject(DestroyRef);
|
|
1783
|
+
this.settingsService = inject(FlowSettingsService);
|
|
1755
1784
|
// TODO: too many inputs
|
|
1756
1785
|
this.model = input.required();
|
|
1757
1786
|
this.edgeModel = input.required();
|
|
@@ -1771,15 +1800,29 @@ class EdgeLabelComponent {
|
|
|
1771
1800
|
y: point.y - height / 2,
|
|
1772
1801
|
};
|
|
1773
1802
|
});
|
|
1803
|
+
this.edgeLabelStyle = computed(() => {
|
|
1804
|
+
const label = this.model().edgeLabel;
|
|
1805
|
+
if (label.type === 'default' && label.style) {
|
|
1806
|
+
const flowBackground = this.settingsService.background();
|
|
1807
|
+
let color = 'transparent';
|
|
1808
|
+
if (flowBackground.type === 'dots') {
|
|
1809
|
+
color = flowBackground.backgroundColor ?? '#fff';
|
|
1810
|
+
}
|
|
1811
|
+
if (flowBackground.type === 'solid') {
|
|
1812
|
+
color = flowBackground.color;
|
|
1813
|
+
}
|
|
1814
|
+
label.style.backgroundColor = label.style.backgroundColor ?? color;
|
|
1815
|
+
return label.style;
|
|
1816
|
+
}
|
|
1817
|
+
return null;
|
|
1818
|
+
});
|
|
1774
1819
|
}
|
|
1775
1820
|
ngAfterViewInit() {
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
const MAGIC_VALUE_TO_FIX_GLITCH_IN_CHROME = 2;
|
|
1779
|
-
resizable([this.edgeLabelWrapperRef().nativeElement], this.zone)
|
|
1821
|
+
const labelElement = this.edgeLabelWrapperRef().nativeElement;
|
|
1822
|
+
resizable([labelElement], this.zone)
|
|
1780
1823
|
.pipe(startWith(null), tap(() => {
|
|
1781
|
-
const width =
|
|
1782
|
-
const height =
|
|
1824
|
+
const width = labelElement.clientWidth + MAGIC_NUMBER_TO_FIX_GLITCH_IN_CHROME;
|
|
1825
|
+
const height = labelElement.clientHeight + MAGIC_NUMBER_TO_FIX_GLITCH_IN_CHROME;
|
|
1783
1826
|
this.model().size.set({ width, height });
|
|
1784
1827
|
}), takeUntilDestroyed(this.destroyRef))
|
|
1785
1828
|
.subscribe();
|
|
@@ -1793,11 +1836,11 @@ class EdgeLabelComponent {
|
|
|
1793
1836
|
};
|
|
1794
1837
|
}
|
|
1795
1838
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1796
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EdgeLabelComponent, isStandalone: true, selector: "g[edgeLabel]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, edgeModel: { classPropertyName: "edgeModel", publicName: "edgeModel", isSignal: true, isRequired: true, transformFunction: null }, point: { classPropertyName: "point", publicName: "point", isSignal: true, isRequired: false, transformFunction: null }, htmlTemplate: { classPropertyName: "htmlTemplate", publicName: "htmlTemplate", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "edgeLabelWrapperRef", first: true, predicate: ["edgeLabelWrapper"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (model().edgeLabel.type === 'html-template' && htmlTemplate()) {\n
|
|
1839
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EdgeLabelComponent, isStandalone: true, selector: "g[edgeLabel]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, edgeModel: { classPropertyName: "edgeModel", publicName: "edgeModel", isSignal: true, isRequired: true, transformFunction: null }, point: { classPropertyName: "point", publicName: "point", isSignal: true, isRequired: false, transformFunction: null }, htmlTemplate: { classPropertyName: "htmlTemplate", publicName: "htmlTemplate", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "edgeLabelWrapperRef", first: true, predicate: ["edgeLabelWrapper"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (model(); as model) {\n @if (model.edgeLabel.type === 'html-template' && htmlTemplate()) {\n @if (htmlTemplate(); as htmlTemplate) {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\">\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\" />\n </div>\n </svg:foreignObject>\n }\n }\n\n @if (model.edgeLabel.type === 'default') {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\">\n <div #edgeLabelWrapper class=\"edge-label-wrapper\" [style]=\"edgeLabelStyle()\">\n {{ model.edgeLabel.text }}\n </div>\n </svg:foreignObject>\n }\n}\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1797
1840
|
}
|
|
1798
1841
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EdgeLabelComponent, decorators: [{
|
|
1799
1842
|
type: Component,
|
|
1800
|
-
args: [{ standalone: true, selector: 'g[edgeLabel]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet], template: "@if (model().edgeLabel.type === 'html-template' && htmlTemplate()) {\n
|
|
1843
|
+
args: [{ standalone: true, selector: 'g[edgeLabel]', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet], template: "@if (model(); as model) {\n @if (model.edgeLabel.type === 'html-template' && htmlTemplate()) {\n @if (htmlTemplate(); as htmlTemplate) {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\">\n <div #edgeLabelWrapper class=\"edge-label-wrapper\">\n <ng-container *ngTemplateOutlet=\"htmlTemplate; context: getLabelContext()\" />\n </div>\n </svg:foreignObject>\n }\n }\n\n @if (model.edgeLabel.type === 'default') {\n <svg:foreignObject\n [attr.x]=\"edgeLabelPoint().x\"\n [attr.y]=\"edgeLabelPoint().y\"\n [attr.width]=\"model.size().width\"\n [attr.height]=\"model.size().height\">\n <div #edgeLabelWrapper class=\"edge-label-wrapper\" [style]=\"edgeLabelStyle()\">\n {{ model.edgeLabel.text }}\n </div>\n </svg:foreignObject>\n }\n}\n", styles: [".edge-label-wrapper{width:max-content;margin-top:1px;margin-left:1px}\n"] }]
|
|
1801
1844
|
}] });
|
|
1802
1845
|
|
|
1803
1846
|
class EdgeComponent {
|
|
@@ -2619,7 +2662,7 @@ class NodeComponent {
|
|
|
2619
2662
|
}
|
|
2620
2663
|
}
|
|
2621
2664
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2622
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NodeComponent, isStandalone: true, selector: "g[node]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, groupNodeTemplate: { classPropertyName: "groupNodeTemplate", publicName: "groupNodeTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], ngImport: i0, template: "<!-- Default node -->\n@if (model().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().
|
|
2665
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: NodeComponent, isStandalone: true, selector: "g[node]", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: true, transformFunction: null }, nodeTemplate: { classPropertyName: "nodeTemplate", publicName: "nodeTemplate", isSignal: true, isRequired: false, transformFunction: null }, groupNodeTemplate: { classPropertyName: "groupNodeTemplate", publicName: "groupNodeTemplate", isSignal: true, isRequired: false, transformFunction: null } }, host: { classAttribute: "vflow-node" }, providers: [HandleService, NodeAccessorService], ngImport: i0, template: "<!-- Default node -->\n@if (model().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (pointerStart)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- Template node -->\n@if (model().node.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: model().node, selected: model().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().node.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().node.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (pointerStart)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().node.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (pointerStart)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: {\n node: model().node,\n selected: model().selected,\n width: model().width,\n height: model().height,\n },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (!handle.template) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"model().magnetRadius\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@if (toolbar(); as toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"], dependencies: [{ kind: "directive", type: PointerDirective, selector: "[pointerStart], [pointerEnd], [pointerOver], [pointerOut]", outputs: ["pointerOver", "pointerOut", "pointerStart", "pointerEnd"] }, { kind: "component", type: DefaultNodeComponent, selector: "default-node", inputs: ["selected"] }, { kind: "component", type: HandleComponent, selector: "handle", inputs: ["position", "type", "id", "template"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: ResizableComponent, selector: "[resizable]", inputs: ["resizable", "resizerColor", "gap"] }, { kind: "directive", type: HandleSizeControllerDirective, selector: "[handleSizeController]", inputs: ["handleSizeController"] }, { kind: "directive", type: NodeHandlesControllerDirective, selector: "[nodeHandlesController]" }, { kind: "directive", type: NodeResizeControllerDirective, selector: "[nodeResizeController]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2623
2666
|
}
|
|
2624
2667
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: NodeComponent, decorators: [{
|
|
2625
2668
|
type: Component,
|
|
@@ -2635,7 +2678,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
2635
2678
|
HandleSizeControllerDirective,
|
|
2636
2679
|
NodeHandlesControllerDirective,
|
|
2637
2680
|
NodeResizeControllerDirective,
|
|
2638
|
-
], template: "<!-- Default node -->\n@if (model().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().
|
|
2681
|
+
], template: "<!-- Default node -->\n@if (model().node.type === 'default') {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (pointerStart)=\"pullNode(); selectNode()\">\n <default-node\n nodeHandlesController\n [selected]=\"model().selected()\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\"\n [style.max-width]=\"model().styleWidth()\"\n [style.max-height]=\"model().styleHeight()\">\n <div [outerHTML]=\"model().text()\"></div>\n\n <handle type=\"source\" position=\"right\" />\n <handle type=\"target\" position=\"left\" />\n </default-node>\n </svg:foreignObject>\n}\n\n<!-- Template node -->\n@if (model().node.type === 'html-template' && nodeTemplate()) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngTemplateOutlet]=\"nodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: { node: model().node, selected: model().selected },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Component node -->\n@if (model().isComponentType) {\n <svg:foreignObject\n class=\"selectable\"\n [attr.width]=\"model().foWidth()\"\n [attr.height]=\"model().foHeight()\"\n (pointerStart)=\"pullNode()\">\n <div\n nodeHandlesController\n nodeResizeController\n class=\"wrapper\"\n [style.width]=\"model().styleWidth()\"\n [style.height]=\"model().styleHeight()\">\n <ng-container\n [ngComponentOutlet]=\"$any(model().node.type)\"\n [ngComponentOutletInputs]=\"model().componentTypeInputs\"\n [ngComponentOutletInjector]=\"injector\" />\n </div>\n </svg:foreignObject>\n}\n\n<!-- Default group node -->\n@if (model().node.type === 'default-group') {\n <svg:rect\n class=\"default-group-node\"\n rx=\"5\"\n ry=\"5\"\n [resizable]=\"model().resizable()\"\n [gap]=\"3\"\n [resizerColor]=\"model().color()\"\n [class.default-group-node_selected]=\"model().selected()\"\n [attr.width]=\"model().size().width\"\n [attr.height]=\"model().size().height\"\n [style.stroke]=\"model().color()\"\n [style.fill]=\"model().color()\"\n (pointerStart)=\"pullNode(); selectNode()\" />\n}\n\n<!-- Template group node -->\n@if (model().node.type === 'template-group' && groupNodeTemplate()) {\n <svg:g class=\"selectable\" nodeHandlesController (pointerStart)=\"pullNode()\">\n <ng-container\n [ngTemplateOutlet]=\"groupNodeTemplate() ?? null\"\n [ngTemplateOutletContext]=\"{\n $implicit: {\n node: model().node,\n selected: model().selected,\n width: model().width,\n height: model().height,\n },\n }\"\n [ngTemplateOutletInjector]=\"injector\" />\n </svg:g>\n}\n\n<!-- Resizer -->\n@if (model().resizerTemplate(); as template) {\n @if (model().resizable()) {\n <ng-template [ngTemplateOutlet]=\"template\" />\n }\n}\n\n<!-- Handles -->\n@for (handle of model().handles(); track handle) {\n @if (!handle.template) {\n <svg:circle\n class=\"default-handle\"\n r=\"5\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n [attr.stroke-width]=\"handle.strokeWidth\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\" />\n }\n\n @if (handle.template) {\n <svg:g\n [handleSizeController]=\"handle\"\n (pointerStart)=\"startConnection($event, handle)\"\n (pointerEnd)=\"endConnection()\">\n <ng-container *ngTemplateOutlet=\"handle.template; context: handle.templateContext\" />\n </svg:g>\n }\n\n @if (showMagnet()) {\n <svg:circle\n class=\"magnet\"\n [attr.r]=\"model().magnetRadius\"\n [attr.cx]=\"handle.hostOffset().x\"\n [attr.cy]=\"handle.hostOffset().y\"\n (pointerEnd)=\"endConnection(); resetValidateConnection(handle)\"\n (pointerOver)=\"validateConnection(handle)\"\n (pointerOut)=\"resetValidateConnection(handle)\" />\n }\n}\n\n<!-- Toolbar -->\n@if (toolbar(); as toolbar) {\n <svg:foreignObject\n [attr.width]=\"toolbar.size().width\"\n [attr.height]=\"toolbar.size().height\"\n [attr.transform]=\"toolbar.transform()\">\n <ng-container [ngTemplateOutlet]=\"toolbar.template()\" />\n </svg:foreignObject>\n}\n", styles: [".magnet{opacity:0}.wrapper{display:table-cell}.default-group-node{stroke-width:1.5px;fill-opacity:.05}.default-group-node_selected{stroke-width:2px}.default-handle{stroke:#fff;fill:#1b262c}\n"] }]
|
|
2639
2682
|
}] });
|
|
2640
2683
|
|
|
2641
2684
|
class ConnectionComponent {
|
|
@@ -3116,6 +3159,12 @@ class VflowComponent {
|
|
|
3116
3159
|
get connection() {
|
|
3117
3160
|
return this.flowEntitiesService.connection();
|
|
3118
3161
|
}
|
|
3162
|
+
/**
|
|
3163
|
+
* Snap grid for node movement. Passes as [x, y]
|
|
3164
|
+
*/
|
|
3165
|
+
set snapGrid(value) {
|
|
3166
|
+
this.flowSettingsService.snapGrid.set(value);
|
|
3167
|
+
}
|
|
3119
3168
|
// #endregion
|
|
3120
3169
|
// #region MAIN_INPUTS
|
|
3121
3170
|
/**
|
|
@@ -3217,7 +3266,7 @@ class VflowComponent {
|
|
|
3217
3266
|
});
|
|
3218
3267
|
}
|
|
3219
3268
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VflowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3220
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowComponent, isStandalone: true, selector: "vflow", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: false, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: false, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: false, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: false, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: false, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: false, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: false, isRequired: false, transformFunction: (settings) => new ConnectionModel(settings) }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: false, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, providers: [
|
|
3269
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: VflowComponent, isStandalone: true, selector: "vflow", inputs: { view: { classPropertyName: "view", publicName: "view", isSignal: false, isRequired: false, transformFunction: null }, minZoom: { classPropertyName: "minZoom", publicName: "minZoom", isSignal: false, isRequired: false, transformFunction: null }, maxZoom: { classPropertyName: "maxZoom", publicName: "maxZoom", isSignal: false, isRequired: false, transformFunction: null }, background: { classPropertyName: "background", publicName: "background", isSignal: false, isRequired: false, transformFunction: null }, optimization: { classPropertyName: "optimization", publicName: "optimization", isSignal: true, isRequired: false, transformFunction: null }, entitiesSelectable: { classPropertyName: "entitiesSelectable", publicName: "entitiesSelectable", isSignal: false, isRequired: false, transformFunction: null }, keyboardShortcuts: { classPropertyName: "keyboardShortcuts", publicName: "keyboardShortcuts", isSignal: false, isRequired: false, transformFunction: null }, connection: { classPropertyName: "connection", publicName: "connection", isSignal: false, isRequired: false, transformFunction: (settings) => new ConnectionModel(settings) }, snapGrid: { classPropertyName: "snapGrid", publicName: "snapGrid", isSignal: false, isRequired: false, transformFunction: null }, nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: false, isRequired: true, transformFunction: null }, edges: { classPropertyName: "edges", publicName: "edges", isSignal: false, isRequired: false, transformFunction: null } }, outputs: { onComponentNodeEvent: "onComponentNodeEvent" }, providers: [
|
|
3221
3270
|
DraggableService,
|
|
3222
3271
|
ViewportService,
|
|
3223
3272
|
FlowStatusService,
|
|
@@ -3278,6 +3327,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3278
3327
|
args: [{
|
|
3279
3328
|
transform: (settings) => new ConnectionModel(settings),
|
|
3280
3329
|
}]
|
|
3330
|
+
}], snapGrid: [{
|
|
3331
|
+
type: Input
|
|
3281
3332
|
}], nodes: [{
|
|
3282
3333
|
type: Input,
|
|
3283
3334
|
args: [{ required: true }]
|