ngx-diagrams
Version:
> Light Weight, Modular, Typed Diagram Engine for Angular
3,647 lines • 168 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@angular/common'), require('@angular/core'), require('rxjs'), require('rxjs/operators'), require('paths-js/path'), require('pathfinding'), require('dagre')) :
typeof define === 'function' && define.amd ? define('ngx-diagrams', ['exports', '@angular/common', '@angular/core', 'rxjs', 'rxjs/operators', 'paths-js/path', 'pathfinding', 'dagre'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global['ngx-diagrams'] = {}, global.ng.common, global.ng.core, global.rxjs, global.rxjs.operators, global.Path, global.pathfinding, global.dagre));
}(this, (function (exports, common, i0, rxjs, operators, SVGPath, PF, dagre) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var SVGPath__default = /*#__PURE__*/_interopDefaultLegacy(SVGPath);
/*! *****************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise */
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b)
if (Object.prototype.hasOwnProperty.call(b, p))
d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
var __assign = function () {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s)
if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
function __rest(s, e) {
var t = {};
for (var p in s)
if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
}
function __decorate(decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function")
r = Reflect.decorate(decorators, target, key, desc);
else
for (var i = decorators.length - 1; i >= 0; i--)
if (d = decorators[i])
r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
}
function __param(paramIndex, decorator) {
return function (target, key) { decorator(target, key, paramIndex); };
}
function __metadata(metadataKey, metadataValue) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function")
return Reflect.metadata(metadataKey, metadataValue);
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try {
step(generator.next(value));
}
catch (e) {
reject(e);
} }
function rejected(value) { try {
step(generator["throw"](value));
}
catch (e) {
reject(e);
} }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function () { if (t[0] & 1)
throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function () { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f)
throw new TypeError("Generator is already executing.");
while (_)
try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done)
return t;
if (y = 0, t)
op = [op[0] & 2, t.value];
switch (op[0]) {
case 0:
case 1:
t = op;
break;
case 4:
_.label++;
return { value: op[1], done: false };
case 5:
_.label++;
y = op[1];
op = [0];
continue;
case 7:
op = _.ops.pop();
_.trys.pop();
continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) {
_ = 0;
continue;
}
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) {
_.label = op[1];
break;
}
if (op[0] === 6 && _.label < t[1]) {
_.label = t[1];
t = op;
break;
}
if (t && _.label < t[2]) {
_.label = t[2];
_.ops.push(op);
break;
}
if (t[2])
_.ops.pop();
_.trys.pop();
continue;
}
op = body.call(thisArg, _);
}
catch (e) {
op = [6, e];
y = 0;
}
finally {
f = t = 0;
}
if (op[0] & 5)
throw op[1];
return { value: op[0] ? op[1] : void 0, done: true };
}
}
var __createBinding = Object.create ? (function (o, m, k, k2) {
if (k2 === undefined)
k2 = k;
Object.defineProperty(o, k2, { enumerable: true, get: function () { return m[k]; } });
}) : (function (o, m, k, k2) {
if (k2 === undefined)
k2 = k;
o[k2] = m[k];
});
function __exportStar(m, o) {
for (var p in m)
if (p !== "default" && !Object.prototype.hasOwnProperty.call(o, p))
__createBinding(o, m, p);
}
function __values(o) {
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
if (m)
return m.call(o);
if (o && typeof o.length === "number")
return {
next: function () {
if (o && i >= o.length)
o = void 0;
return { value: o && o[i++], done: !o };
}
};
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
}
function __read(o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m)
return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done)
ar.push(r.value);
}
catch (error) {
e = { error: error };
}
finally {
try {
if (r && !r.done && (m = i["return"]))
m.call(i);
}
finally {
if (e)
throw e.error;
}
}
return ar;
}
function __spread() {
for (var ar = [], i = 0; i < arguments.length; i++)
ar = ar.concat(__read(arguments[i]));
return ar;
}
function __spreadArrays() {
for (var s = 0, i = 0, il = arguments.length; i < il; i++)
s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
}
;
function __await(v) {
return this instanceof __await ? (this.v = v, this) : new __await(v);
}
function __asyncGenerator(thisArg, _arguments, generator) {
if (!Symbol.asyncIterator)
throw new TypeError("Symbol.asyncIterator is not defined.");
var g = generator.apply(thisArg, _arguments || []), i, q = [];
return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i;
function verb(n) { if (g[n])
i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }
function resume(n, v) { try {
step(g[n](v));
}
catch (e) {
settle(q[0][3], e);
} }
function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
function fulfill(value) { resume("next", value); }
function reject(value) { resume("throw", value); }
function settle(f, v) { if (f(v), q.shift(), q.length)
resume(q[0][0], q[0][1]); }
}
function __asyncDelegator(o) {
var i, p;
return i = {}, verb("next"), verb("throw", function (e) { throw e; }), verb("return"), i[Symbol.iterator] = function () { return this; }, i;
function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === "return" } : f ? f(v) : v; } : f; }
}
function __asyncValues(o) {
if (!Symbol.asyncIterator)
throw new TypeError("Symbol.asyncIterator is not defined.");
var m = o[Symbol.asyncIterator], i;
return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function (v) { resolve({ value: v, done: d }); }, reject); }
}
function __makeTemplateObject(cooked, raw) {
if (Object.defineProperty) {
Object.defineProperty(cooked, "raw", { value: raw });
}
else {
cooked.raw = raw;
}
return cooked;
}
;
var __setModuleDefault = Object.create ? (function (o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function (o, v) {
o["default"] = v;
};
function __importStar(mod) {
if (mod && mod.__esModule)
return mod;
var result = {};
if (mod != null)
for (var k in mod)
if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k))
__createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
}
function __importDefault(mod) {
return (mod && mod.__esModule) ? mod : { default: mod };
}
function __classPrivateFieldGet(receiver, privateMap) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to get private field on non-instance");
}
return privateMap.get(receiver);
}
function __classPrivateFieldSet(receiver, privateMap, value) {
if (!privateMap.has(receiver)) {
throw new TypeError("attempted to set private field on non-instance");
}
privateMap.set(receiver, value);
return value;
}
var BaseAction = /** @class */ (function () {
function BaseAction(mouseX, mouseY) {
this.mouseX = mouseX;
this.mouseY = mouseY;
this.ms = new Date().getTime();
}
return BaseAction;
}());
var MoveCanvasAction = /** @class */ (function (_super) {
__extends(MoveCanvasAction, _super);
function MoveCanvasAction(mouseX, mouseY, diagramModel) {
var _this = _super.call(this, mouseX, mouseY) || this;
_this.initialOffsetX = diagramModel.getOffsetX();
_this.initialOffsetY = diagramModel.getOffsetY();
return _this;
}
return MoveCanvasAction;
}(BaseAction));
var SelectingAction = /** @class */ (function (_super) {
__extends(SelectingAction, _super);
function SelectingAction(mouseX, mouseY) {
var _this = _super.call(this, mouseX, mouseY) || this;
_this.mouseX2 = mouseX;
_this.mouseY2 = mouseY;
return _this;
}
SelectingAction.prototype.getBoxDimensions = function () {
this.dimensions = {
left: this.mouseX2 > this.mouseX ? this.mouseX : this.mouseX2,
top: this.mouseY2 > this.mouseY ? this.mouseY : this.mouseY2,
width: Math.abs(this.mouseX2 - this.mouseX),
height: Math.abs(this.mouseY2 - this.mouseY),
right: this.mouseX2 < this.mouseX ? this.mouseX : this.mouseX2,
bottom: this.mouseY2 < this.mouseY ? this.mouseY : this.mouseY2,
};
return this.dimensions;
};
SelectingAction.prototype.containsElement = function (_a, diagramModel) {
var x = _a.x, y = _a.y;
var z = diagramModel.getZoomLevel() / 100.0;
var dimensions = this.getBoxDimensions();
return (x * z + diagramModel.getOffsetX() > dimensions.left &&
x * z + diagramModel.getOffsetX() < dimensions.right &&
y * z + diagramModel.getOffsetY() > dimensions.top &&
y * z + diagramModel.getOffsetY() < dimensions.bottom);
};
return SelectingAction;
}(BaseAction));
var ROUTING_SCALING_FACTOR = 10;
var PathFinding = /** @class */ (function () {
function PathFinding(diagramEngine, heuristic) {
if (heuristic === void 0) { heuristic = PF.Heuristic.manhattan; }
this.diagramEngine = diagramEngine;
this.pathFinderInstance = new PF.AStarFinder({
heuristic: heuristic,
diagonalMovement: PF.DiagonalMovement.Always,
weight: 0,
});
}
/**
* Taking as argument a fully unblocked walking matrix, this method
* finds a direct path from point A to B.
*/
PathFinding.prototype.calculateDirectPath = function (from, to) {
var matrix = this.diagramEngine.getCanvasMatrix();
var grid = new PF.Grid(matrix);
var fromX = this.diagramEngine.translateRoutingX(Math.floor(from.x / ROUTING_SCALING_FACTOR));
var toX = this.diagramEngine.translateRoutingX(Math.floor(to.x / ROUTING_SCALING_FACTOR));
var fromY = this.diagramEngine.translateRoutingX(Math.floor(from.y / ROUTING_SCALING_FACTOR));
var toY = this.diagramEngine.translateRoutingX(Math.floor(to.y / ROUTING_SCALING_FACTOR));
var path = this.pathFinderInstance.findPath(fromX, fromY, toX, toY, grid);
return path;
};
/**
* Using @link{#calculateDirectPath}'s result as input, we here
* determine the first walkable point found in the matrix that includes
* blocked paths.
*/
PathFinding.prototype.calculateLinkStartEndCoords = function (matrix, path) {
var startIndex = path.findIndex(function (point) { return matrix[point[1]][point[0]] === 0; });
var endIndex = path.length -
1 -
path
.slice()
.reverse()
.findIndex(function (point) { return matrix[point[1]][point[0]] === 0; });
// are we trying to create a path exclusively through blocked areas?
// if so, let's fallback to the linear routing
if (startIndex === -1 || endIndex === -1) {
return undefined;
}
var pathToStart = path.slice(0, startIndex);
var pathToEnd = path.slice(endIndex);
return {
start: {
x: path[startIndex][0],
y: path[startIndex][1],
},
end: {
x: path[endIndex][0],
y: path[endIndex][1],
},
pathToStart: pathToStart,
pathToEnd: pathToEnd,
};
};
/**
* Puts everything together: merges the paths from/to the centre of the ports,
* with the path calculated around other elements.
*/
PathFinding.prototype.calculateDynamicPath = function (routingMatrix, start, end, pathToStart, pathToEnd) {
var _this = this;
// generate the path based on the matrix with obstacles
var grid = new PF.Grid(routingMatrix);
var dynamicPath = this.pathFinderInstance.findPath(start.x, start.y, end.x, end.y, grid);
// aggregate everything to have the calculated path ready for rendering
var pathCoords = pathToStart
.concat(dynamicPath, pathToEnd)
.map(function (coords) { return [
_this.diagramEngine.translateRoutingX(coords[0], true),
_this.diagramEngine.translateRoutingY(coords[1], true),
]; });
return PF.Util.compressPath(pathCoords);
};
return PathFinding;
}());
(function (LOG_LEVEL) {
LOG_LEVEL[LOG_LEVEL["LOG"] = 0] = "LOG";
LOG_LEVEL[LOG_LEVEL["ERROR"] = 1] = "ERROR";
})(exports.LOG_LEVEL || (exports.LOG_LEVEL = {}));
// @internal
exports.__DEV__ = true;
// @internal
exports.__LOG__ = exports.LOG_LEVEL.ERROR;
function enableDiagramProdMode() {
exports.__DEV__ = false;
}
// @internal
function setLogLevel(level) {
exports.__LOG__ = level;
}
// @internal
function isDev() {
return exports.__DEV__;
}
// @internal
function log(message, level) {
if (level === void 0) { level = exports.LOG_LEVEL.LOG; }
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
if (isDev() && exports.__LOG__ === level) {
if (exports.__LOG__ === exports.LOG_LEVEL.ERROR) {
console.error.apply(console, __spread([message], args));
}
console.log.apply(console, __spread([message], args));
}
}
/**
* rxjs log operator
* @internal
*/
function withLog(message, level) {
if (level === void 0) { level = exports.LOG_LEVEL.LOG; }
var args = [];
for (var _i = 2; _i < arguments.length; _i++) {
args[_i - 2] = arguments[_i];
}
return function (source) { return isDev()
? source.pipe(operators.tap(function (val) { return log.apply(void 0, __spread([message, level, val], args)); }))
: source; };
}
/**
* rxjs entity properties operator
* @internal
*/
function entityProperty(destroyedNotifier, replayBy, logMessage) {
if (replayBy === void 0) { replayBy = 1; }
if (logMessage === void 0) { logMessage = ''; }
return function (source) { return source.pipe(operators.distinctUntilChanged(function (a, b) { return a instanceof Map || b instanceof Map ? false : a === b; }), operators.shareReplay(replayBy), withLog(logMessage), operators.takeUntil(destroyedNotifier)); };
}
/**
* Generates a unique ID
*/
function UID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = (Math.random() * 16) | 0;
var v = c === 'x' ? r : (r & 0x3) | 0x8;
return v.toString(16);
});
}
function isArray(val) {
return Array.isArray(val);
}
function isString(val) {
return typeof val === 'string';
}
function isFunction(val) {
return typeof val === 'function';
}
// @internal
function isNil(v) {
return v === null || v === undefined;
}
function coerceArray(value) {
if (isNil(value)) {
return [];
}
return Array.isArray(value) ? value : [value];
}
function isEmptyArray(arr) {
return !arr || !isArray(arr) || arr.length === 0;
}
function mapToArray(map) {
var result = [];
for (var key in map) {
if (!isNil(map[key])) {
result.push(map[key]);
}
}
return result;
}
function mapToEntries(map) {
var result = [];
for (var key in map) {
result.push([key, map[key]]);
}
return result;
}
function unique(arr) {
return __spread(new Set(arr));
}
function arrayToMap(arr) {
var e_1, _a;
var result = {};
try {
for (var arr_1 = __values(arr), arr_1_1 = arr_1.next(); !arr_1_1.done; arr_1_1 = arr_1.next()) {
var val = arr_1_1.value;
if (!isNil(val)) {
result[val.id] = val;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (arr_1_1 && !arr_1_1.done && (_a = arr_1.return)) _a.call(arr_1);
}
finally { if (e_1) throw e_1.error; }
}
return result;
}
function generateLinePath(firstPoint, lastPoint) {
return "M" + firstPoint.x$ + "," + firstPoint.y + " L " + lastPoint.x$ + "," + lastPoint.y;
}
function generateCurvePath(firstPoint, lastPoint, curvy) {
if (curvy === void 0) { curvy = 0; }
var isHorizontal = Math.abs(firstPoint.x - lastPoint.x) > Math.abs(firstPoint.y - lastPoint.y);
var curvyX = isHorizontal ? curvy : 0;
var curvyY = isHorizontal ? 0 : curvy;
return "M" + firstPoint.x + "," + firstPoint.y + " C " + (firstPoint.x + curvyX) + "," + (firstPoint.y + curvyY) + "\n " + (lastPoint.x - curvyX) + "," + (lastPoint.y - curvyY) + " " + lastPoint.x + "," + lastPoint.y;
}
function generateDynamicPath(pathCoords) {
var path = SVGPath__default['default']();
path = path.moveto(pathCoords[0][0] * ROUTING_SCALING_FACTOR, pathCoords[0][1] * ROUTING_SCALING_FACTOR);
pathCoords.slice(1).forEach(function (coords) {
path = path.lineto(coords[0] * ROUTING_SCALING_FACTOR, coords[1] * ROUTING_SCALING_FACTOR);
});
return path.print();
}
function OutsideZone(targetClass, functionName, descriptor) {
var source = descriptor.value;
descriptor.value = function () {
var _this = this;
var data = [];
for (var _i = 0; _i < arguments.length; _i++) {
data[_i] = arguments[_i];
}
if (!this.ngZone) {
throw new Error("Class with 'OutsideZone' decorator should have 'ngZone' class property with 'NgZone' class.");
}
return this.ngZone.runOutsideAngular(function () { return source.call.apply(source, __spread([_this], data)); });
};
return descriptor;
}
var ValueState = /** @class */ (function () {
function ValueState(value, operator) {
this.stream$ = new rxjs.BehaviorSubject(value);
this.value$ = operator ? this.stream$.pipe(operator) : this.stream$.asObservable();
}
Object.defineProperty(ValueState.prototype, "value", {
get: function () {
return this.stream$.getValue();
},
enumerable: false,
configurable: true
});
ValueState.prototype.set = function (value) {
this.stream$.next(value);
return this;
};
ValueState.prototype.emit = function () {
this.stream$.next(this.value);
};
ValueState.prototype.select = function (project) {
var mapFn = project || (function (v) { return v; });
return this.value$.pipe(operators.map(function (value) { return mapFn(value); }), operators.distinctUntilChanged());
};
return ValueState;
}());
function createValueState(value, operator) {
return new ValueState(value, operator);
}
var EntityState = /** @class */ (function (_super) {
__extends(EntityState, _super);
function EntityState(value, entityPipe) {
return _super.call(this, value, entityPipe) || this;
}
EntityState.prototype.destroy = function () {
this.clear();
this.stream$ = null;
this.value$ = null;
};
EntityState.prototype.clear = function (destroy) {
if (destroy === void 0) { destroy = true; }
if (destroy) {
this.forEach(function (entity) { return entity.destroy(); });
}
this.value.clear();
return this;
};
EntityState.prototype.get = function (id) {
return this.value.get(id);
};
EntityState.prototype.has = function (id) {
return this.value.has(id);
};
EntityState.prototype.add = function (entity) {
this.value.set(entity.id, entity);
return this;
};
EntityState.prototype.addMany = function (entities) {
var e_1, _b;
try {
for (var entities_1 = __values(entities), entities_1_1 = entities_1.next(); !entities_1_1.done; entities_1_1 = entities_1.next()) {
var entity = entities_1_1.value;
this.add(entity);
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (entities_1_1 && !entities_1_1.done && (_b = entities_1.return)) _b.call(entities_1);
}
finally { if (e_1) throw e_1.error; }
}
return this;
};
EntityState.prototype.remove = function (id, destroy) {
if (destroy === void 0) { destroy = true; }
var _a;
if (destroy) {
(_a = this.value.get(id)) === null || _a === void 0 ? void 0 : _a.destroy();
}
this.value.delete(id);
return this;
};
EntityState.prototype.array = function () {
return Array.from(this.value.values());
};
EntityState.prototype.array$ = function () {
return this.select(function (value) { return Array.from(value.values()); });
};
EntityState.prototype.forEach = function (cb) {
this.value.forEach(cb);
};
EntityState.prototype.map = function (cb) {
return this.array().map(cb);
};
return EntityState;
}(ValueState));
function createEntityState(value, entityPipe) {
if (value === void 0) { value = []; }
if (isArray(value)) {
return new EntityState(new Map(value), entityPipe);
}
else {
return new EntityState(new Map(mapToEntries(value)), entityPipe);
}
}
// region events
var BaseEvent = /** @class */ (function () {
function BaseEvent(entity, options) {
var _this = this;
this.id = UID();
this.entity = entity;
this.entityId = entity.id;
this.firing = true;
this.stopPropagation = function () { return (_this.firing = false); };
this.propogate = options ? options.propagate : null;
}
return BaseEvent;
}());
var LockEvent = /** @class */ (function (_super) {
__extends(LockEvent, _super);
function LockEvent(entity, locked) {
if (locked === void 0) { locked = false; }
var _this = _super.call(this, entity) || this;
_this.locked = locked;
return _this;
}
return LockEvent;
}(BaseEvent));
var ParentChangeEvent = /** @class */ (function (_super) {
__extends(ParentChangeEvent, _super);
function ParentChangeEvent(entity, parent) {
var _this = _super.call(this, entity) || this;
_this.parent = parent;
return _this;
}
return ParentChangeEvent;
}(BaseEvent));
var SelectionEvent = /** @class */ (function (_super) {
__extends(SelectionEvent, _super);
function SelectionEvent(entity, selected) {
var _this = _super.call(this, entity) || this;
_this.isSelected = selected;
return _this;
}
return SelectionEvent;
}(BaseEvent));
var PaintedEvent = /** @class */ (function (_super) {
__extends(PaintedEvent, _super);
function PaintedEvent(entity, painted) {
if (painted === void 0) { painted = false; }
var _this = _super.call(this, entity) || this;
_this.isPainted = painted;
return _this;
}
return PaintedEvent;
}(BaseEvent));
// endregion
var BaseEntity = /** @class */ (function () {
function BaseEntity(id, logPrefix) {
if (logPrefix === void 0) { logPrefix = ''; }
this.destroyed$ = new rxjs.Subject();
this.locked$ = createValueState(false, this.entityPipe('locked'));
this._id = id || UID();
this._logPrefix = "" + logPrefix;
}
Object.defineProperty(BaseEntity.prototype, "id", {
get: function () {
return this._id;
},
set: function (id) {
this._id = id;
},
enumerable: false,
configurable: true
});
BaseEntity.prototype.log = function (message) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
log.apply(void 0, __spread([this._logPrefix + " " + message + ": ", exports.LOG_LEVEL.LOG], args));
};
BaseEntity.prototype.withLog = function (message) {
var args = [];
for (var _i = 1; _i < arguments.length; _i++) {
args[_i - 1] = arguments[_i];
}
return withLog.apply(void 0, __spread([this._logPrefix + " " + message + ": ", exports.LOG_LEVEL.LOG], args));
};
BaseEntity.prototype.entityPipe = function (logMessage) {
if (logMessage === void 0) { logMessage = ''; }
return entityProperty(this.onEntityDestroy(), 0, this._logPrefix + ": " + logMessage);
};
BaseEntity.prototype.getLocked = function () {
return this.locked$.value;
};
BaseEntity.prototype.setLocked = function (locked) {
if (locked === void 0) { locked = true; }
this.locked$.set(locked).emit();
};
// eslint-disable-next-line
BaseEntity.prototype.doClone = function (lookupTable, clone) {
if (lookupTable === void 0) { lookupTable = {}; }
/*noop*/
};
BaseEntity.prototype.clone = function (lookupTable) {
if (lookupTable === void 0) { lookupTable = {}; }
// try and use an existing clone first
if (lookupTable[this.id]) {
return lookupTable[this.id];
}
var clone = Object.assign({}, this);
clone.id = UID();
// clone.clearListeners();
lookupTable[this.id] = clone;
this.doClone(lookupTable, clone);
return clone;
};
BaseEntity.prototype.serialize = function () {
return {
id: this.id,
locked: this.getLocked()
};
};
BaseEntity.prototype.lockChanges = function () {
var _this = this;
return this.locked$.select(function (locked) { return new LockEvent(_this, locked); });
};
BaseEntity.prototype.destroy = function () {
this.log('entity destroyed');
this.destroyed$.next();
this.destroyed$.complete();
};
BaseEntity.prototype.onEntityDestroy = function () {
var _this = this;
return this.destroyed$.pipe(operators.map(function (opts) { return new BaseEvent(_this, opts); }));
};
return BaseEntity;
}());
var BaseModel = /** @class */ (function (_super) {
__extends(BaseModel, _super);
function BaseModel(type, id, logPrefix) {
if (logPrefix === void 0) { logPrefix = '[Base]'; }
var _this = _super.call(this, id, logPrefix) || this;
_this.parent$ = createValueState(null, _this.entityPipe('ParentsChange'));
_this.selected$ = createValueState(false, _this.entityPipe('SelectedChange'));
_this.hovered$ = createValueState(false, _this.entityPipe('HoveredChange'));
_this.painted$ = createValueState(false, _this.entityPipe('PaintedChange'));
_this._type = type;
return _this;
}
BaseModel.prototype.serialize = function () {
return Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { type: this.getType() });
};
BaseModel.prototype.getParent = function () {
return this.parent$.value;
};
BaseModel.prototype.setParent = function (parent) {
this.parent$.set(parent).emit();
};
BaseModel.prototype.parentChanges = function () {
var _this = this;
return this.parent$.select(function (p) { return new ParentChangeEvent(_this, p); });
};
BaseModel.prototype.getPainted = function () {
return this.painted$.value;
};
BaseModel.prototype.setPainted = function (painted) {
if (painted === void 0) { painted = true; }
this.painted$.set(painted).emit();
};
BaseModel.prototype.getHovered = function () {
return this.hovered$.value;
};
BaseModel.prototype.setHovered = function (painted) {
if (painted === void 0) { painted = true; }
this.hovered$.set(painted).emit();
};
BaseModel.prototype.selectHovered = function () {
return this.hovered$.value$;
};
BaseModel.prototype.paintChanges = function () {
var _this = this;
return this.painted$.select(function (p) { return new PaintedEvent(_this, p); });
};
BaseModel.prototype.getType = function () {
return this._type;
};
BaseModel.prototype.getSelected = function () {
return this.selected$.value;
};
BaseModel.prototype.selectSelected = function () {
return this.selected$.select();
};
BaseModel.prototype.setSelected = function (selected) {
if (selected === void 0) { selected = true; }
this.selected$.set(selected).emit();
};
BaseModel.prototype.selectionChanges = function () {
var _this = this;
return this.selected$.select(function (selected) { return new SelectionEvent(_this, selected); });
};
BaseModel.prototype.getSelectedEntities = function () {
return this.getSelected() ? [this] : [];
};
return BaseModel;
}(BaseEntity));
var PointModel = /** @class */ (function (_super) {
__extends(PointModel, _super);
function PointModel(link, coords, id, logPrefix) {
if (logPrefix === void 0) { logPrefix = '[Point]'; }
var _this = _super.call(this, link.getType(), id, logPrefix) || this;
_this.coords$ = createValueState(coords, _this.entityPipe('coords'));
_this.setParent(link);
return _this;
}
PointModel.prototype.serialize = function () {
return Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { coords: this.getCoords() });
};
PointModel.prototype.isConnectedToPort = function () {
return this.getParent().getPortForPoint(this) !== null;
};
PointModel.prototype.getLink = function () {
return this.getParent();
};
PointModel.prototype.destroy = function () {
if (this.getParent) {
this.getParent().removePoint(this);
}
_super.prototype.destroy.call(this);
};
PointModel.prototype.setCoords = function (newCoords) {
this.coords$.set(Object.assign(Object.assign({}, this.getCoords()), newCoords)).emit();
};
PointModel.prototype.selectCoords = function () {
return this.coords$.value$;
};
PointModel.prototype.getCoords = function () {
return this.coords$.value;
};
PointModel.prototype.selectX = function () {
return this.coords$.select(function (coords) { return coords.x; });
};
PointModel.prototype.selectY = function () {
return this.coords$.select(function (coords) { return coords.y; });
};
return PointModel;
}(BaseModel));
var LinkModel = /** @class */ (function (_super) {
__extends(LinkModel, _super);
function LinkModel(linkType, id, logPrefix) {
if (linkType === void 0) { linkType = 'default'; }
if (logPrefix === void 0) { logPrefix = '[Link]'; }
var _this = _super.call(this, linkType, id, logPrefix) || this;
_this.label$ = createValueState(null, _this.entityPipe('label'));
_this.points = [new PointModel(_this, { x: 0, y: 0 }), new PointModel(_this, { x: 0, y: 0 })];
_this.extras = {};
_this.sourcePort = null;
_this.targetPort = null;
return _this;
}
LinkModel.prototype.serialize = function () {
var _a;
var serializedPoints = this.points.map(function (point) { return point.serialize(); });
var label = (_a = this.getLabel()) === null || _a === void 0 ? void 0 : _a.serialize();
return Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { name: this.getName(), sourcePort: this.getSourcePort().id, targetPort: this.getTargetPort().id, extras: this.getExtras(), points: serializedPoints, label: label });
};
LinkModel.prototype.setName = function (name) {
this.name = name;
};
LinkModel.prototype.getName = function () {
return this.name;
};
LinkModel.prototype.getExtras = function () {
return this.extras;
};
LinkModel.prototype.setExtras = function (extras) {
this.extras = extras;
};
LinkModel.prototype.destroy = function () {
if (this.sourcePort) {
this.sourcePort.removeLink(this);
}
if (this.targetPort) {
this.targetPort.removeLink(this);
}
_super.prototype.destroy.call(this);
};
LinkModel.prototype.doClone = function (lookupTable, clone) {
if (lookupTable === void 0) { lookupTable = {}; }
clone.setPoints(this.getPoints().map(function (point) {
return point.clone(lookupTable);
}));
if (this.sourcePort) {
clone.setSourcePort(this.sourcePort.clone(lookupTable));
}
if (this.targetPort) {
clone.setTargetPort(this.targetPort.clone(lookupTable));
}
};
LinkModel.prototype.isLastPoint = function (point) {
var index = this.getPointIndex(point);
return index === this.points.length - 1;
};
LinkModel.prototype.getPointIndex = function (point) {
return this.points.indexOf(point);
};
LinkModel.prototype.getPointModel = function (id) {
var e_1, _b;
try {
for (var _c = __values(this.points), _d = _c.next(); !_d.done; _d = _c.next()) {
var point = _d.value;
if (point.id === id) {
return point;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
return null;
};
LinkModel.prototype.getPortForPoint = function (point) {
if (this.sourcePort !== null && this.getFirstPoint().id === point.id) {
return this.sourcePort;
}
if (this.targetPort !== null && this.getLastPoint().id === point.id) {
return this.targetPort;
}
return null;
};
LinkModel.prototype.getPointForPort = function (port) {
if (this.sourcePort !== null && this.sourcePort.id === port.id) {
return this.getFirstPoint();
}
if (this.targetPort !== null && this.targetPort.id === port.id) {
return this.getLastPoint();
}
return null;
};
LinkModel.prototype.getFirstPoint = function () {
return this.points[0];
};
LinkModel.prototype.getLastPoint = function () {
return this.points[this.points.length - 1];
};
LinkModel.prototype.setSourcePort = function (port) {
if (port !== null) {
port.addLink(this);
}
if (this.sourcePort !== null) {
this.sourcePort.removeLink(this);
}
this.sourcePort = port;
};
LinkModel.prototype.getSourcePort = function () {
return this.sourcePort;
};
LinkModel.prototype.getTargetPort = function () {
return this.targetPort;
};
LinkModel.prototype.setTargetPort = function (port) {
if (port !== null) {
port.addLink(this);
}
if (this.targetPort !== null) {
this.targetPort.removeLink(this);
}
this.targetPort = port;
};
LinkModel.prototype.point = function (_b) {
var x = _b.x, y = _b.y;
return this.addPoint(this.generatePoint({ x: x, y: y }));
};
LinkModel.prototype.getPoints = function () {
return this.points;
};
LinkModel.prototype.setPoints = function (points) {
var _this = this;
points.forEach(function (point) {
point.setParent(_this);
});
this.points = points;
};
LinkModel.prototype.setLabel = function (label) {
label.setParent(this);
this.label$.set(label).emit();
};
LinkModel.prototype.selectLabel = function () {
return this.label$.value$;
};
LinkModel.prototype.getLabel = function () {
return this.label$.value;
};
LinkModel.prototype.resetLabel = function () {
var currentLabel = this.getLabel();
if (currentLabel) {
currentLabel.setParent(null);
currentLabel.setPainted(false);
}
this.setLabel(null);
};
LinkModel.prototype.removePoint = function (pointModel) {
this.points.splice(this.getPointIndex(pointModel), 1);
};
LinkModel.prototype.removePointsBefore = function (pointModel) {
this.points.splice(0, this.getPointIndex(pointModel));
};
LinkModel.prototype.removePointsAfter = function (pointModel) {
this.points.splice(this.getPointIndex(pointModel) + 1);
};
LinkModel.prototype.removeMiddlePoints = function () {
if (this.points.length > 2) {
this.points.splice(0, this.points.length - 2);
}
};
LinkModel.prototype.addPoint = function (pointModel, index) {
if (index === void 0) { index = 1; }
pointModel.setParent(this);
pointModel.setLocked(this.getLocked());
this.points.splice(index, 0, pointModel);
return pointModel;
};
LinkModel.prototype.generatePoint = function (_b) {
var _c = _b.x, x = _c === void 0 ? 0 : _c, _d = _b.y, y = _d === void 0 ? 0 : _d;
return new PointModel(this, { x: x, y: y });
};
LinkModel.prototype.setLocked = function (locked) {
if (locked === void 0) { locked = true; }
_super.prototype.setLocked.call(this, locked);
this.points.forEach(function (point) { return point.setLocked(locked); });
};
return LinkModel;
}(BaseModel));
var MoveItemsAction = /** @class */ (function (_super) {
__extends(MoveItemsAction, _super);
function MoveItemsAction(mouseX, mouseY, diagramEngine) {
var _this = _super.call(this, mouseX, mouseY) || this;
_this.moved = false;
var selectedItems = diagramEngine.getDiagramModel().getSelectedItems();
// dont allow items which are locked to move and links which generate their position based on points.
selectedItems = selectedItems.filter(function (item) {
return !diagramEngine.isModelLocked(item) && !(item instanceof LinkModel);
});
_this.selectionModels = selectedItems.map(function (item) {
var _a = item.getCoords(), initialX = _a.x, initialY = _a.y;
return {
model: item,
initialX: initialX,
initialY: initialY,
};
});
return _this;
}
return MoveItemsAction;
}(BaseAction));
// TODO: refactor into entity-created.action, and fire every time a new entity is created!
var LinkCreatedAction = /** @class */ (function (_super) {
__extends(LinkCreatedAction, _super);
function LinkCreatedAction(mouseX, mouseY, link) {
var _this = _super.call(this, mouseX, mouseY) || this;
_this.sourcePort = link.getSourcePort();
_this.targetPort = link.getTargetPort();
_this.link = link;
return _this;
}
LinkCreatedAction.prototype.getOutPortNode = function () {
return this.sourcePort.getParent();
};
LinkCreatedAction.prototype.getInPortNode = function () {
return this.targetPort.getParent();
};
return LinkCreatedAction;
}(BaseAction));
var LooseLinkDestroyed = /** @class */ (function (_super) {
__extends(LooseLinkDestroyed, _super);
function LooseLinkDestroyed(mouseX, mouseY, link) {
var _this = _super.call(this, mouseX, mouseY) || this;
_this.sourcePort = link.getSourcePort();
_this.link = link;
return _this;
}
LooseLinkDestroyed.prototype.getOutPortNode = function () {
return this.sourcePort.getParent();
};
return LooseLinkDestroyed;
}(BaseAction));
var InvalidLinkDestroyed = /** @class */ (function (_super) {
__extends(InvalidLinkDestroyed, _super);
function InvalidLinkDestroyed(mouseX, mouseY, link) {
var _this = _super.call(this, mouseX, mouseY) || this;
_this.sourcePort = link.getSourcePort();
_this.link = link;
return _this;
}
InvalidLinkDestroyed.prototype.getOutPortNode = function () {
return this.sourcePort.getParent();
};
return InvalidLinkDestroyed;
}(BaseAction));
var NodeModel = /** @class */ (function (_super) {
__extends(NodeModel, _super);
function NodeModel(nodeType, id, extras, x, y, width, height, logPrefix) {
if (nodeType === void 0) { nodeType = 'default'; }
if (extras === void 0) { extras = {}; }
if (x === void 0) { x = 0; }
if (y === void 0) { y = 0; }
if (width === void 0) { width = 0; }
if (height === void 0) { height = 0; }
if (logPrefix === void 0) { logPrefix = '[Node]'; }
var _this = _super.call(this, nodeType, id, logPrefix) || this;
_this.diagramEngine$ = createValueState(null, _this.entityPipe('diagramEngine'));
_this.extras$ = createValueState({}, _this.entityPipe('extras'));
_this.ports$ = createEntityState([], _this.entityPipe('ports'));
_this.coords$ = createValueState({ x: 0, y: 0 }, _this.entityPipe('coords'));
_this.dimensions$ = createValueState({ width: 0, height: 0 }, _this.entityPipe('dimensions'));
_this.setExtras(extras);
_this.setDimensions({ width: width, height: height });
_this.setCoords({ x: x, y: y });
return _this;
}
NodeModel.prototype.getDiagramEngine = function () {
return this.diagramEngine$.value;
};
NodeModel.prototype.selectDiagramEngine = function () {
return this.diagramEngine$.value$;
};
NodeModel.prototype.setDiagramEngine = function (diagramEngine) {
this.diagramEngine$.set(diagramEngine).emit();
};
NodeModel.prototype.getCoords = function () {
return this.coords$.value;
};
NodeModel.prototype.setCoords = function (_a) {
var x = _a.x, y = _a.y;
var _b = this.getCoords(), oldX = _b.x, oldY = _b.y;
this.getPorts().forEach(function (port) {
port.getLinks().forEach(function (link) {
var point = link.getPointForPort(port);
var _a = point.getCoords(), pointX = _a.x, pointY = _a.y;
point.setCoords({ x: pointX + x - oldX, y: pointY + y - oldY });
});
});
this.coords$.set({ x: x, y: y }).emit();
};
NodeModel.prototype.serialize = function () {
var serializedPorts = this.getPortsArray().map(function (port) { return port.serialize(); });
return Object.assign(Object.assign(Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { nodeType: this.getType(), extras: this.getExtras(), width: this.getWidth(), height: this.getHeight() }), this.getCoords()), { ports: serializedPorts });
};
// TODO: override selectionChanges and replace this with it (convert to rx)
NodeModel.prototype.getSelectedEntities = function () {
var entities = _super.prototype.getSelectedEntities.call(this);
// add the points of each link that are selected here
if (this.getSelected()) {
this.getPorts().forEach(function (port) {
var points = port.getLinksArray().map(function (link) { return link.getPointForPort(port); });
entities = entities.concat(points);
});
}
this.log('selectedEntities', entities);
return entities;
};
// TODO: map to BaseEvent
NodeModel.prototype.coordsChanges = function () {
return this.coords$.value$;
};
NodeModel.prototype.selectCoords = function () {
return this.coords$.value$;
};
NodeModel.prototype.selectX = function () {
return this.coords$.select(function (coords) { return coords.x; });
};
NodeModel.prototype.selectY = function () {
return this.coords$.select(function (coords) { return coords.y; });
};
/**
* Assign a port to the node and set the node as its getParent
* @returns the inserted port
*/
NodeModel.prototype.addPort = function (port) {
port.setParent(this);
this.ports$.add(port).emit();
return port;
};
NodeModel.prototype.removePort = function (portOrId) {
var portId = typeof portOrId === 'string' ? portOrId : portOrId.id;
this.ports$.remove(portId).emit();
return portId;
};
NodeModel.prototype.getPort = function (id) {
return this.ports$.get(id);
};
NodeModel.prototype.selectPorts = function (selector) {
// TODO: implement selector
// TODO: create coerce func
return this.ports$.array$().pipe(this.withLog('selectPorts'));
};
NodeModel.prototype.getPorts = function () {
return this.ports$.value;
};
NodeModel.prototype.getPortsArray = function () {
return this.ports$.array();
};
NodeModel.prototype.setDimensions = function (dimensions) {
this.dimensions$.set(Object.assign(Object.assign({}, this.getDimensions()), dimensions)).emit();
};
NodeModel.prototype.getDimensions = function () {
return this.dimensions$.value;
};
// TODO: return BaseEvent extension
NodeModel.prototype.dimensionChanges = function () {
return this.dimensions$.select();
};
NodeModel.prototype.getHeight = function () {
return this.getDimensions().height;
};
NodeModel.prototype.setHeight = function (height) {
return this.setDimensions({ height: height });
};
NodeModel.prototype.getWidth = function () {
return this.getDimensions().width;
};
NodeModel.prototype.setWidth = function (width) {
return this.setDimensions({ width: width });
};
NodeModel.prototype.selectWidth = function () {
return this.dimensions$.select(function (d) { return d.width; }).pipe(this.withLog('selectWidth'));
};
NodeModel.prototype.selectHeight = function () {
return this.dimensions$.select(function (d) { return d.height; }).pipe(this.withLog('selectHeight'));
};
NodeModel.prototype.setExtras = function (extras) {
this.extras$.set(extras).emit();
};
NodeModel.prototype.getExtras = function () {
return this.extras$.value;
};
NodeModel.prototype.selectExtras = function (selector) {
return this.extras$.select(selector);
};
NodeModel.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.removeAllPorts();
};
NodeModel.prototype.removeAllPorts = function () {
this.ports$.clear().emit();
};
return NodeModel;
}(BaseModel));
var PortModel = /** @class */ (function (_super) {
__extends(PortModel, _super);
function PortModel(name, type, id, maximumLinks, linkType, magnetic, logPrefix) {
if (magnetic === void 0) { magnetic = true; }
if (logPrefix === void 0) { logPrefix = '[Port]'; }
var _this = _super.call(this, type, id, logPrefix) || this;
_this.links$ = createEntityState([], _this.entityPipe('links'));
_this.x$ = createValueState(0, _this.entityPipe('x'));
_this.y$ = createValueState(0, _this.entityPipe('y'));
_this.width$ = createValueState(0, _this.entityPipe('y'));
_this.height$ = createValueState(0, _this.entityPipe('y'));
_this.magnetic$ = createValueState(true, _this.entityPipe('magnetic'));
_this.canCreateLinks$ = createValueState(true, _this.entityPipe('magnetic'));
_this.name = name;
_this.maximumLinks = maximumLinks;
_this.linkType = linkType;
_this.setMagnetic(magnetic);
return _this;
}
PortModel.prototype.serialize = function () {
return Object.assign(Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { name: this.getName(), linkType: this.getLinkType(), maximumLinks: this.getMaximumLinks(), type: this.getType(), magnetic: this.getMagnetic(), height: this.getHeight(), width: this.getWidth(), canCreateLinks: this.getCanCreateLinks() }), this.getCoords());
};
PortModel.prototype.getNode = function () {
return this.getParent();
};
PortModel.prototype.getName = function () {
return this.name;
};
PortModel.prototype.getCanCreateLinks = function () {
var numberOfLinks = this.getLinks().size;
if (this.maximumLinks && numberOfLinks >= this.maximumLinks) {
return false;
}
return this.canCreateLinks$.value;
};
PortModel.prototype.getCoords = function () {
return { x: this.getX(), y: this.getY() };
};
PortModel.prototype.selectCanCreateLinks = function () {
return this.canCreateLinks$.value$;
};
PortModel.prototype.setCanCreateLinks = function (value) {
this.canCreateLinks$.set(value).emit();
};
PortModel.prototype.getMagnetic = function () {
return this.magnetic$.value;
};
PortModel.prototype.selectMagnetic = function () {
return this.magnetic$.value$;
};
PortModel.prototype.setMagnetic = function (magnetic) {
this.magnetic$.set(magnetic).emit();
};
PortModel.prototype.selectX = function () {
return this.x$.value$;
};
PortModel.prototype.selectY = function () {
return this.y$.value$;
};
PortModel.prototype.getY = function () {
return this.y$.value;
};
PortModel.prototype.getX = function () {
return this.x$.value;
};
PortModel.prototype.getHeight = function () {
return this.height$.value;
};
PortModel.prototype.getWidth = function () {
return this.width$.value;
};
PortModel.prototype.getMaximumLinks = function () {
return this.maximumLinks;
};
PortModel.prototype.setMaximumLinks = function (maximumLinks) {
this.maximumLinks = maximumLinks;
};
PortModel.prototype.getLinkType = function () {
return this.linkType;
};
PortModel.prototype.setLinkType = function (type) {
this.linkType = type;
};
PortModel.prototype.removeLink = function (linkOrId) {
var linkId = isString(linkOrId) ? linkOrId : linkOrId.id;
this.links$.remove(linkId, false).emit();
};
PortModel.prototype.addLink = function (link) {
this.links$.add(link).emit();
};
PortModel.prototype.getLinks = function () {
return this.links$.value;
};
PortModel.prototype.getLinksArray = function () {
return this.links$.array();
};
PortModel.prototype.selectLinks = function () {
return this.links$.value$;
};
PortModel.prototype.updateCoords = function (_a) {
var x = _a.x, y = _a.y, width = _a.width, height = _a.height;
this.x$.set(x).emit();
this.y$.set(y).emit();
this.width$.set(width).emit();
this.height$.set(height).emit();
};
PortModel.prototype.canLinkToPort = function (port) {
return true;
};
PortModel.prototype.isLocked = function () {
return _super.prototype.getLocked.call(this);
};
PortModel.prototype.createLinkModel = function () {
if (this.getCanCreateLinks()) {
return new LinkModel();
}
};
PortModel.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.links$.clear().emit();
};
return PortModel;
}(BaseModel));
var NgxDiagramComponent = /** @class */ (function () {
function NgxDiagramComponent(document, ngZone, renderer, cdRef, elRef) {
this.document = document;
this.ngZone = ngZone;
this.renderer = renderer;
this.cdRef = cdRef;
this.elRef = elRef;
this.allowCanvasZoom = true;
this.allowCanvasTranslation = true;
this.inverseZoom = true;
this.allowLooseLinks = true;
this.maxZoomOut = null;
this.maxZoomIn = null;
this.portMagneticRadius = 30;
this.smartRouting = false;
this.actionStartedFiring = new i0.EventEmitter();
this.actionStillFiring = new i0.EventEmitter();
this.actionStoppedFiring = new i0.EventEmitter();
this.action$ = new rxjs.BehaviorSubject(null);
this.nodesRendered$ = new rxjs.BehaviorSubject(false);
this.destroyed$ = new rxjs.ReplaySubject(1);
}
Object.defineProperty(NgxDiagramComponent.prototype, "host", {
get: function () {
return this.elRef.nativeElement;
},
enumerable: false,
configurable: true
});
// TODO: handle destruction of container, resetting all observables to avoid memory leaks!
NgxDiagramComponent.prototype.ngAfterViewInit = function () {
if (this.diagramModel) {
this.initNodes();
this.initLinks();
this.initSubs();
}
};
NgxDiagramComponent.prototype.ngOnDestroy = function () {
this.destroyed$.next(true);
this.destroyed$.complete();
};
/**
* fire the action registered and notify subscribers
*/
NgxDiagramComponent.prototype.fireAction = function () {
if (this.action$.value) {
this.actionStillFiring.emit(this.action$.value);
}
};
/**
* Unregister the action, post firing and notify subscribers
*/
NgxDiagramComponent.prototype.stopFiringAction = function (shouldSkipEvent) {
if (!shouldSkipEvent) {
this.actionStoppedFiring.emit(this.action$.value);
}
this.action$.next(null);
};
/**
* Register the new action, pre firing and notify subscribers
*/
NgxDiagramComponent.prototype.startFiringAction = function (action) {
this.action$.next(action);
this.actionStartedFiring.emit(action);
};
NgxDiagramComponent.prototype.selectAction = function () {
return this.action$;
};
NgxDiagramComponent.prototype.shouldDrawSelectionBox = function () {
var action = this.action$.getValue();
if (action instanceof SelectingAction) {
action.getBoxDimensions();
return true;
}
return false;
};
NgxDiagramComponent.prototype.getMouseElement = function (event) {
var target = event.target;
// is it a port?
var element = target.closest('[data-portid]');
if (element) {
// get the relevant node and return the port.
var nodeEl = target.closest('[data-nodeid]');
return {
model: this.diagramModel
.getNode(nodeEl.getAttribute('data-nodeid'))
.getPort(element.getAttribute('data-portid')),
element: element
};
}
// look for a point
element = target.closest('[data-pointid]');
if (element) {
return {
model: this.diagramModel
.getLink(element.getAttribute('data-linkid'))
.getPointModel(element.getAttribute('data-pointid')),
element: element
};
}
// look for a link
element = target.closest('[data-linkid]');
if (element) {
return {
model: this.diagramModel.getLink(element.getAttribute('data-linkid')),
element: element
};
}
// a node maybe
element = target.closest('[data-nodeid]');
if (element) {
return {
model: this.diagramModel.getNode(element.getAttribute('data-nodeid')),
element: element
};
}
// just the canvas
return null;
};
NgxDiagramComponent.prototype.onMouseUp = function (event) {
var _this = this;
var diagramEngine = this.diagramModel.getDiagramEngine();
var action = this.action$.getValue();
// are we going to connect a link to something?
if (action instanceof MoveItemsAction) {
var element_1 = this.getMouseElement(event);
action.selectionModels.forEach(function (model) {
// only care about points connecting to things
if (!model || !(model.model instanceof PointModel)) {
return;
}
var el;
if (model.magnet) {
el = model.magnet;
}
else if (element_1 && element_1.model) {
el = element_1.model;
}
if (el instanceof PortModel && !diagramEngine.isModelLocked(el)) {
var link = model.model.getLink();
if (link.getTargetPort() !== null) {
// if this was a valid link already and we are adding a node in the middle, create 2 links from the original
if (link.getTargetPort() !== el && link.getSourcePort() !== el) {
var targetPort = link.getTargetPort();
var newLink = link.clone({});
newLink.setSourcePort(el);
newLink.setTargetPort(targetPort);
link.setTargetPort(el);
targetPort.removeLink(link);
newLink.removePointsBefore(newLink.getPoints()[link.getPointIndex(model.model)]);
link.removePointsAfter(model.model);
diagramEngine.getDiagramModel().addLink(newLink);
// if we are connecting to the same target or source, destroy tweener points
}
else if (link.getTargetPort() === el) {
link.removePointsAfter(model.model);
}
else if (link.getSourcePort() === el) {
link.removePointsBefore(model.model);
}
}
else {
link.setTargetPort(el);
var targetPort = link.getTargetPort();
var srcPort = link.getSourcePort();
if (targetPort.id !== srcPort.id && srcPort.canLinkToPort(targetPort)) {
// link is valid, fire the event
_this.startFiringAction(new LinkCreatedAction(event.clientX, event.clientY, link));
}
}
}
// reset current magent
model.magnet = undefined;
});
// check for / destroy any loose links in any models which have been moved
if (!this.allowLooseLinks) {
action.selectionModels.forEach(function (model) {
// only care about points connecting to things
if (!model || !(model.model instanceof PointModel)) {
return;
}
var selectedPoint = model.model;
var link = selectedPoint.getLink();
if (link.getSourcePort() === null || link.getTargetPort() === null) {
link.destroy();
_this.startFiringAction(new LooseLinkDestroyed(event.clientX, event.clientY, link));
}
});
}
// destroy any invalid links
action.selectionModels.forEach(function (model) {
// only care about points connecting to things
if (!model || !(model.model instanceof PointModel)) {
return;
}
var link = model.model.getLink();
var sourcePort = link.getSourcePort();
var targetPort = link.getTargetPort();
if (sourcePort !== null && targetPort !== null) {
if (!sourcePort.canLinkToPort(targetPort)) {
// link not allowed
link.destroy();
_this.startFiringAction(new InvalidLinkDestroyed(event.clientX, event.clientY, link));
}
else if (targetPort
.getLinksArray()
.some(function (link) { return link !== link && (link.getSourcePort() === sourcePort || link.getTargetPort() === sourcePort); })) {
// link is a duplicate
link.destroy();
}
}
});
this.stopFiringAction();
}
else {
this.stopFiringAction();
}
this.action$.next(null);
};
/**
* @description Mouse Move Event Handler
* @param event MouseEvent
*/
NgxDiagramComponent.prototype.onMouseMove = function (event) {
var _this = this;
var action = this.action$.getValue();
if (action === null || action === undefined) {
return;
}
if (action instanceof SelectingAction) {
var relative = this.diagramModel.getDiagramEngine().getRelativePoint(event.clientX, event.clientY);
this.diagramModel.getNodes().forEach(function (node) {
if (action.containsElement(node.getCoords(), _this.diagramModel)) {
node.setSelected();
}
else {
node.setSelected(false);
}
});
this.diagramModel.getLinks().forEach(function (link) {
var allSelected = true;
link.getPoints().forEach(function (point) {
if (action.containsElement(point.getCoords(), _this.diagramModel)) {
point.setSelected();
}
else {
point.setSelected(false);
allSelected = false;
}
});
if (allSelected) {
link.setSelected();
}
});
action.mouseX2 = relative.x;
action.mouseY2 = relative.y;
this.fireAction();
this.action$.next(action);
return;
}
else if (action instanceof MoveItemsAction) {
var coords_1 = {
x: event.clientX - action.mouseX,
y: event.clientY - action.mouseY
};
var amountZoom_1 = this.diagramModel.getZoomLevel() / 100;
action.selectionModels.forEach(function (selectionModel) {
var e_1, _a;
// reset all previous magnets if any
selectionModel.magnet = undefined;
// in this case we need to also work out the relative grid position
if (selectionModel.model instanceof NodeModel ||
(selectionModel.model instanceof PointModel && !selectionModel.model.isConnectedToPort())) {
var newCoords = {
x: selectionModel.initialX + coords_1.x / amountZoom_1,
y: selectionModel.initialY + coords_1.y / amountZoom_1
};
var gridRelativeCoords = _this.diagramModel.getGridPosition(newCoords);
// magnetic inputs handling
if (selectionModel.model instanceof PointModel && _this.portMagneticRadius) {
// get all ports on canvas, check distances, if smaller then defined radius, magnetize!
var portsMap = _this.diagramModel.getAllPorts({ filter: function (p) { return p.getMagnetic(); } });
try {
for (var _b = __values(portsMap.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var port = _c.value;
var portCoords = port.getCoords();
var distance = Math.hypot(portCoords.x - newCoords.x, portCoords.y - newCoords.y);
if (distance <= _this.portMagneticRadius) {
var portCenter = _this.diagramModel.getDiagramEngine().getPortCenter(port);
selectionModel.model.setCoords(portCenter);
selectionModel.magnet = port;
return;
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_1) throw e_1.error; }
}
}
selectionModel.model.setCoords(gridRelativeCoords);
if (selectionModel.model instanceof NodeModel) {
// update port coordinates as well
selectionModel.model.getPorts().forEach(function (port) {
var portCoords = _this.diagramModel.getDiagramEngine().getPortCoords(port);
port.updateCoords(portCoords);
});
}
if (_this.diagramModel.getDiagramEngine().getSmartRouting()) {
setTimeout(function () {
_this.diagramModel.getDiagramEngine().calculateRoutingMatrix();
}, 1);
}
}
else if (selectionModel.model instanceof PointModel) {
// will only run here when trying to create a point on an existing link
// we want points that are connected to ports, to not necessarily snap to grid
// this stuff needs to be pixel perfect, dont touch it
var newCoords = _this.diagramModel.getGridPosition({ x: coords_1.x / amountZoom_1, y: coords_1.y / amountZoom_1 });
selectionModel.model.setCoords({
x: selectionModel.initialX + newCoords.x,
y: selectionModel.initialY + newCoords.y
});
}
});
this.fireAction();
}
else if (action instanceof MoveCanvasAction) {
if (this.allowCanvasTranslation) {
this.diagramModel.setOffset(action.initialOffsetX + (event.clientX - action.mouseX), action.initialOffsetY + (event.clientY - action.mouseY));
this.fireAction();
}
}
};
NgxDiagramComponent.prototype.onMouseDown = function (event) {
if (event.button === 3) {
return;
}
var selectedModel = this.getMouseElement(event);
// canvas selected
if (selectedModel === null) {
// multiple selection
if (event.shiftKey) {
// initiate multiple selection selector
var relative = this.diagramModel.getDiagramEngine().getRelativePoint(event.clientX, event.clientY);
this.startFiringAction(new SelectingAction(relative.x, relative.y));
}
else {
// drag canvas action
this.diagramModel.clearSelection();
this.startFiringAction(new MoveCanvasAction(event.clientX, event.clientY, this.diagramModel));
}
}
else if (selectedModel.model instanceof PortModel) {
// its a port element, we want to drag a link
if (!selectedModel.model.isLocked() && selectedModel.model.getCanCreateLinks()) {
var relative = this.diagramModel.getDiagramEngine().getRelativeMousePoint(event);
var sourcePort = selectedModel.model;
var link = sourcePort.createLinkModel();
// if we don't have a link then we have reached the max amount, or we cannot create new ones
if (link) {
link.setSourcePort(sourcePort);
link.removeMiddlePoints();
if (link.getSourcePort() !== sourcePort) {
link.setSourcePort(sourcePort);
}
link.setTargetPort(null);
link.getFirstPoint().setCoords(relative);
link.getLastPoint().setCoords(relative);
this.diagramModel.clearSelection();
link.getLastPoint().setSelected();
this.diagramModel.addLink(link);
this.startFiringAction(new MoveItemsAction(event.clientX, event.clientY, this.diagramModel.getDiagramEngine()));
}
}
else {
this.diagramModel.clearSelection();
}
}
else if (selectedModel.model instanceof PointModel && selectedModel.model.isConnectedToPort()) {
this.diagramModel.clearSelection();
}
else {
// its some other element, probably want to move it
if (!event.shiftKey && !selectedModel.model.getSelected()) {
this.diagramModel.clearSelection();
}
selectedModel.model.setSelected();
this.startFiringAction(new MoveItemsAction(event.clientX, event.clientY, this.diagramModel.getDiagramEngine()));
}
this.createMouseListeners();
};
NgxDiagramComponent.prototype.onMouseWheel = function (event) {
if (!this.allowCanvasZoom) {
return;
}
event.preventDefault();
event.stopPropagation();
var currentZoomLevel = this.diagramModel.getZoomLevel();
var oldZoomFactor = currentZoomLevel / 100;
var scrollDelta = this.inverseZoom ? -event.deltaY : event.deltaY;
// check if it is pinch gesture
if (event.ctrlKey && scrollDelta % 1 !== 0) {
/* Chrome and Firefox sends wheel event with deltaY that
have fractional part, also `ctrlKey` prop of the event is true
though ctrl isn't pressed
*/
scrollDelta /= 3;
}
else {
scrollDelta /= 60;
}
if (currentZoomLevel + scrollDelta > 10) {
var newZoomLvl = currentZoomLevel + scrollDelta;
this.diagramModel.setZoomLevel(newZoomLvl);
}
var updatedZoomLvl = this.diagramModel.getZoomLevel();
var zoomFactor = updatedZoomLvl / 100;
var boundingRect = event.currentTarget.getBoundingClientRect();
var clientWidth = boundingRect.width;
var clientHeight = boundingRect.height;
// compute difference between rect before and after scroll
var widthDiff = clientWidth * zoomFactor - clientWidth * oldZoomFactor;
var heightDiff = clientHeight * zoomFactor - clientHeight * oldZoomFactor;
// compute mouse coords relative to canvas
var clientX = event.clientX - boundingRect.left;
var clientY = event.clientY - boundingRect.top;
// compute width and height increment factor
var xFactor = (clientX - this.diagramModel.getOffsetX()) / oldZoomFactor / clientWidth;
var yFactor = (clientY - this.diagramModel.getOffsetY()) / oldZoomFactor / clientHeight;
var updatedXOffset = this.diagramModel.getOffsetX() - widthDiff * xFactor;
var updatedYOffset = this.diagramModel.getOffsetY() - heightDiff * yFactor;
this.diagramModel.setOffset(updatedXOffset, updatedYOffset);
};
NgxDiagramComponent.prototype.setLayerStyles = function (x, y, zoom) {
var nodesLayer = this.getNodesLayer();
var linksLayer = this.getLinksLayer();
var style = 'transform';
var value = "translate(" + x + "px, " + y + "px) scale(" + zoom / 100.0 + ")";
this.renderer.setStyle(nodesLayer, style, value);
this.renderer.setStyle(linksLayer, style, value);
};
NgxDiagramComponent.prototype.initNodes = function () {
var _this = this;
this.nodes$ = this.diagramModel.selectNodes();
this.diagramModel.getDiagramEngine().setCanvas(this.canvas.nativeElement);
this.diagramModel.getDiagramEngine().setSmartRoutingStatus(this.smartRouting);
this.diagramModel.setMaxZoomIn(this.maxZoomIn);
this.diagramModel.setMaxZoomOut(this.maxZoomOut);
this.nodes$.pipe(operators.takeUntil(this.destroyed$)).subscribe(function (nodes) {
var e_2, _a;
_this.nodesRendered$.next(false);
try {
for (var _b = __values(nodes.values()), _c = _b.next(); !_c.done; _c = _b.next()) {
var node = _c.value;
if (!node.getPainted()) {
_this.diagramModel.getDiagramEngine().generateWidgetForNode(node, _this.nodesLayer);
_this.cdRef.detectChanges();
}
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
}
finally { if (e_2) throw e_2.error; }
}
_this.nodesRendered$.next(true);
});
};
NgxDiagramComponent.prototype.initLinks = function () {
var _this = this;
this.links$ = this.diagramModel.selectLinks();
rxjs.combineLatest([this.nodesRendered$, this.links$])
.pipe(operators.filter(function (_a) {
var _b = __read(_a, 1), nodesRendered = _b[0];
return !!nodesRendered;
}), operators.takeUntil(this.destroyed$))
.subscribe(function (_a) {
var e_3, _b;
var _c = __read(_a, 2), links = _c[1];
try {
for (var _d = __values(links.values()), _e = _d.next(); !_e.done; _e = _d.next()) {
var link = _e.value;
if (!link.getPainted() && link.getSourcePort().getPainted()) {
if (link.getSourcePort() !== null) {
var portCenter = _this.diagramModel.getDiagramEngine().getPortCenter(link.getSourcePort());
link.getPoints()[0].setCoords(portCenter);
var portCoords = _this.diagramModel.getDiagramEngine().getPortCoords(link.getSourcePort());
link.getSourcePort().updateCoords(portCoords);
}
if (link.getTargetPort() !== null) {
var portCenter = _this.diagramModel.getDiagramEngine().getPortCenter(link.getTargetPort());
link.getPoints()[link.getPoints().length - 1].setCoords(portCenter);
var portCoords = _this.diagramModel.getDiagramEngine().getPortCoords(link.getTargetPort());
link.getTargetPort().updateCoords(portCoords);
}
_this.diagramModel.getDiagramEngine().generateWidgetForLink(link, _this.linksLayer);
_this.cdRef.detectChanges();
}
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (_e && !_e.done && (_b = _d.return)) _b.call(_d);
}
finally { if (e_3) throw e_3.error; }
}
});
};
NgxDiagramComponent.prototype.initSubs = function () {
var _this = this;
rxjs.combineLatest([
this.diagramModel.selectOffsetX(),
this.diagramModel.selectOffsetY(),
this.diagramModel.selectZoomLevel()
])
.pipe(operators.tap(function (_a) {
var _b = __read(_a, 3), x = _b[0], y = _b[1], zoom = _b[2];
return _this.setLayerStyles(x, y, zoom);
}), operators.takeUntil(this.destroyed$))
.subscribe();
};
NgxDiagramComponent.prototype.getNodesLayer = function () {
return this.host.querySelector('.ngdx-nodes-layer');
};
NgxDiagramComponent.prototype.getLinksLayer = function () {
return this.host.querySelector('.ngdx-links-layer');
};
NgxDiagramComponent.prototype.createMouseListeners = function () {
var _this = this;
var mouseUp$ = rxjs.fromEvent(this.document, 'mouseup').pipe(operators.tap(function (e) { return _this.onMouseUp(e); }), operators.take(1));
var mouseMove$ = rxjs.fromEvent(this.document, 'mousemove').pipe(operators.tap(function (e) { return _this.onMouseMove(e); }), operators.takeUntil(mouseUp$));
rxjs.merge(mouseMove$, mouseUp$).subscribe();
};
return NgxDiagramComponent;
}());
NgxDiagramComponent.decorators = [
{ type: i0.Component, args: [{
selector: 'ngdx-diagram',
template: "<div class=\"ngdx-diagram\" #canvas (mousedown)=\"onMouseDown($event)\" (wheel)=\"onMouseWheel($event)\">\n\t<!-- Nodes Layer -->\n\t<div class=\"ngdx-nodes-layer\">\n\t\t<ng-template #nodesLayer></ng-template>\n\t</div>\n\n\t<!-- Links Layer -->\n\t<div class=\"ngdx-links-layer\">\n\t\t<ng-template #linksLayer></ng-template>\n\t</div>\n\n\t<!-- Selection Box -->\n\t<div\n\t\t*ngIf=\"shouldDrawSelectionBox() && selectAction() | async as action\"\n\t\tclass=\"selector\"\n\t\t[ngStyle]=\"{\n\t\t\ttop: action.dimensions.top + 'px',\n\t\t\tleft: action.dimensions.left + 'px',\n\t\t\twidth: action.dimensions.width + 'px',\n\t\t\theight: action.dimensions.height + 'px'\n\t\t}\"></div>\n</div>\n",
changeDetection: i0.ChangeDetectionStrategy.OnPush,
styles: [".ngdx-diagram{cursor:move;display:flex;flex-grow:1;overflow:hidden;position:relative}.ngdx-diagram .selector{background-color:rgba(0,192,255,.2);border:2px solid #00c0ff;position:absolute}.ngdx-diagram .ngdx-nodes-layer{z-index:150}.ngdx-diagram .ngdx-links-layer,.ngdx-diagram .ngdx-nodes-layer{bottom:0;height:100%;left:0;overflow:visible!important;pointer-events:none;position:absolute;right:0;top:0;transform-origin:0 0;width:100%}.ngdx-diagram .ngdx-links-layer{z-index:100}"]
},] }
];
NgxDiagramComponent.ctorParameters = function () { return [
{ type: undefined, decorators: [{ type: i0.Inject, args: [common.DOCUMENT,] }] },
{ type: i0.NgZone },
{ type: i0.Renderer2 },
{ type: i0.ChangeDetectorRef },
{ type: i0.ElementRef }
]; };
NgxDiagramComponent.propDecorators = {
diagramModel: [{ type: i0.Input, args: ['model',] }],
allowCanvasZoom: [{ type: i0.Input }],
allowCanvasTranslation: [{ type: i0.Input }],
inverseZoom: [{ type: i0.Input }],
allowLooseLinks: [{ type: i0.Input }],
maxZoomOut: [{ type: i0.Input }],
maxZoomIn: [{ type: i0.Input }],
portMagneticRadius: [{ type: i0.Input }],
smartRouting: [{ type: i0.Input }],
actionStartedFiring: [{ type: i0.Output }],
actionStillFiring: [{ type: i0.Output }],
actionStoppedFiring: [{ type: i0.Output }],
nodesLayer: [{ type: i0.ViewChild, args: ['nodesLayer', { read: i0.ViewContainerRef },] }],
linksLayer: [{ type: i0.ViewChild, args: ['linksLayer', { read: i0.ViewContainerRef },] }],
canvas: [{ type: i0.ViewChild, args: ['canvas', { read: i0.ElementRef },] }]
};
__decorate([
OutsideZone,
__metadata("design:type", Function),
__metadata("design:paramtypes", [MouseEvent]),
__metadata("design:returntype", void 0)
], NgxDiagramComponent.prototype, "onMouseUp", null);
__decorate([
OutsideZone,
__metadata("design:type", Function),
__metadata("design:paramtypes", [MouseEvent]),
__metadata("design:returntype", void 0)
], NgxDiagramComponent.prototype, "onMouseMove", null);
__decorate([
OutsideZone,
__metadata("design:type", Function),
__metadata("design:paramtypes", [MouseEvent]),
__metadata("design:returntype", void 0)
], NgxDiagramComponent.prototype, "onMouseDown", null);
__decorate([
OutsideZone,
__metadata("design:type", Function),
__metadata("design:paramtypes", [WheelEvent]),
__metadata("design:returntype", void 0)
], NgxDiagramComponent.prototype, "onMouseWheel", null);
__decorate([
OutsideZone,
__metadata("design:type", Function),
__metadata("design:paramtypes", [Number, Number, Number]),
__metadata("design:returntype", void 0)
], NgxDiagramComponent.prototype, "setLayerStyles", null);
var AbstractFactory = /** @class */ (function () {
function AbstractFactory(type) {
this._type = type;
}
Object.defineProperty(AbstractFactory.prototype, "type", {
get: function () {
return this._type;
},
enumerable: false,
configurable: true
});
return AbstractFactory;
}());
var AbstractLabelFactory = /** @class */ (function (_super) {
__extends(AbstractLabelFactory, _super);
function AbstractLabelFactory() {
return _super !== null && _super.apply(this, arguments) || this;
}
return AbstractLabelFactory;
}(AbstractFactory));
var LabelModel = /** @class */ (function (_super) {
__extends(LabelModel, _super);
function LabelModel(type, id, logPrefix) {
if (logPrefix === void 0) { logPrefix = '[Label]'; }
var _this = _super.call(this, type, id, logPrefix) || this;
_this.coords$ = createValueState({ x: 0, y: 0 }, _this.entityPipe('coords'));
_this.rotation$ = createValueState(0, _this.entityPipe('rotation'));
return _this;
}
LabelModel.prototype.serialize = function () {
return Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { type: this.getType(), rotation: this.getRotation(), coords: this.getCoords() });
};
LabelModel.prototype.getRotation = function () {
return this.rotation$.value;
};
LabelModel.prototype.getCoords = function () {
return this.coords$.value;
};
LabelModel.prototype.destroy = function () {
_super.prototype.destroy.call(this);
};
LabelModel.prototype.setRotation = function (angle) {
this.rotation$.set(angle).emit();
};
LabelModel.prototype.selectRotation = function () {
return this.rotation$.value$;
};
LabelModel.prototype.setCoords = function (newCoords) {
this.coords$.set(Object.assign(Object.assign({}, this.coords$.value), newCoords)).emit();
};
LabelModel.prototype.selectCoords = function () {
return this.coords$.value$;
};
return LabelModel;
}(BaseModel));
var DefaultLabelModel = /** @class */ (function (_super) {
__extends(DefaultLabelModel, _super);
function DefaultLabelModel(label, type, id, logPrefix) {
if (label === void 0) { label = 'NO LABEL'; }
if (type === void 0) { type = 'default'; }
if (logPrefix === void 0) { logPrefix = '[DefaultLabel]'; }
var _this = _super.call(this, type, id, logPrefix) || this;
_this.label$ = createValueState('', _this.entityPipe('label'));
_this.setLabel(label);
return _this;
}
DefaultLabelModel.prototype.setLabel = function (label) {
this.label$.set(label).emit();
};
DefaultLabelModel.prototype.getLabel = function () {
return this.label$.value;
};
DefaultLabelModel.prototype.selectLabel = function () {
return this.label$.value$;
};
return DefaultLabelModel;
}(LabelModel));
var DefaultLabelComponent = /** @class */ (function (_super) {
__extends(DefaultLabelComponent, _super);
function DefaultLabelComponent() {
return _super.call(this, 'ngdx-default-label') || this;
}
return DefaultLabelComponent;
}(DefaultLabelModel));
DefaultLabelComponent.decorators = [
{ type: i0.Component, args: [{
selector: 'ngdx-default-label',
template: "<div\n class=\"default-label\"\n [ngStyle]=\"{\n\t\ttransform:\n\t\t\t'translate(' +\n\t\t\t(selectCoords() | async).x +\n\t\t\t'px, ' +\n\t\t\t(selectCoords() | async).y +\n\t\t\t'px)' +\n\t\t\t'rotate(' +\n\t\t\t(selectRotation() | async) +\n\t\t\t'deg)'\n\t}\">\n {{ selectLabel() | async }}\n</div>\n",
changeDetection: i0.ChangeDetectionStrategy.OnPush,
styles: [".default-label{-moz-user-select:none;-ms-user-select:none;-webkit-user-select:none;color:#fff;user-select:none}"]
},] }
];
DefaultLabelComponent.ctorParameters = function () { return []; };
var DefaultLabelFactory = /** @class */ (function (_super) {
__extends(DefaultLabelFactory, _super);
function DefaultLabelFactory(resolver, renderer) {
var _this = _super.call(this, 'default') || this;
_this.resolver = resolver;
_this.renderer = renderer;
return _this;
}
DefaultLabelFactory.prototype.generateWidget = function (label, labelHost) {
var componentRef = labelHost.createComponent(this.getRecipe());
// attach coordinates and default positional behaviour to the generated component host
var rootNode = componentRef.location.nativeElement;
// default style for link
this.renderer.setStyle(rootNode, 'position', 'absolute');
// data attributes
this.renderer.setAttribute(rootNode, 'data-labelid', label.id);
// on destroy make sure to destroy the componentRef
label.onEntityDestroy().subscribe(function () {
componentRef.destroy();
});
// assign all passed properties to node initialization.
Object.entries(label).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
componentRef.instance[key] = value;
});
componentRef.instance.setPainted(true);
return componentRef;
};
DefaultLabelFactory.prototype.getRecipe = function () {
return this.resolver.resolveComponentFactory(DefaultLabelComponent);
};
DefaultLabelFactory.prototype.getNewInstance = function () {
return new DefaultLabelModel();
};
return DefaultLabelFactory;
}(AbstractLabelFactory));
var AbstractLinkFactory = /** @class */ (function (_super) {
__extends(AbstractLinkFactory, _super);
function AbstractLinkFactory() {
return _super !== null && _super.apply(this, arguments) || this;
}
return AbstractLinkFactory;
}(AbstractFactory));
var DefaultLinkModel = /** @class */ (function (_super) {
__extends(DefaultLinkModel, _super);
function DefaultLinkModel(_a) {
var _b = _a === void 0 ? {} : _a, _c = _b.type, type = _c === void 0 ? 'default' : _c, id = _b.id, _d = _b.logPrefix, logPrefix = _d === void 0 ? '[DefaultLink]' : _d;
var _this = _super.call(this, type, id, logPrefix) || this;
_this.width$ = createValueState(3, _this.entityPipe('width'));
_this.color$ = createValueState('rgba(255, 255, 255, 0.5)', _this.entityPipe('color'));
_this.curvyness$ = createValueState(50, _this.entityPipe('curvyness'));
return _this;
}
DefaultLinkModel.prototype.setWidth = function (width) {
this.width$.set(width).emit();
};
DefaultLinkModel.prototype.setColor = function (color) {
this.color$.set(color).emit();
};
DefaultLinkModel.prototype.selectWidth = function () {
return this.width$.value$;
};
DefaultLinkModel.prototype.selectColor = function () {
return this.color$.value$;
};
DefaultLinkModel.prototype.setCurvyness = function (curvyness) {
this.curvyness$.set(curvyness).emit();
};
Object.defineProperty(DefaultLinkModel.prototype, "color", {
get: function () {
return this.color$.value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(DefaultLinkModel.prototype, "width", {
get: function () {
return this.width$.value;
},
enumerable: false,
configurable: true
});
Object.defineProperty(DefaultLinkModel.prototype, "curvyness", {
get: function () {
return this.curvyness$.value;
},
enumerable: false,
configurable: true
});
return DefaultLinkModel;
}(LinkModel));
var DefaultLinkComponent = /** @class */ (function (_super) {
__extends(DefaultLinkComponent, _super);
function DefaultLinkComponent(cdRef) {
var _this = _super.call(this, { type: 'ngdx-default-link' }) || this;
_this.cdRef = cdRef;
_this.path$ = createValueState(null, _this.entityPipe('path'));
_this.points$ = createValueState([], _this.entityPipe('points'));
return _this;
}
DefaultLinkComponent.prototype.trackByPoints = function (i, point) {
return point.id;
};
DefaultLinkComponent.prototype.ngOnInit = function () {
if (this.diagramEngine.getSmartRouting()) {
this.pathFinding = this.diagramEngine.getPathfinding();
}
};
DefaultLinkComponent.prototype.ngAfterViewInit = function () {
var _this = this;
var firstPCoords$ = this.getFirstPoint().selectCoords();
var lastPCoords$ = this.getLastPoint().selectCoords();
// Observe link coords and update drawing accordingly
rxjs.combineLatest([firstPCoords$, lastPCoords$])
.pipe(operators.takeUntil(this.onEntityDestroy()))
.subscribe(function (_a) {
var _b = __read(_a, 2), firstPCoords = _b[0], lastPCoords = _b[1];
var points = [firstPCoords, lastPCoords];
if (_this.diagramEngine.getSmartRouting()) {
// first step: calculate a direct path between the points being linked
var directPathCoords = _this.pathFinding.calculateDirectPath(firstPCoords, lastPCoords);
var routingMatrix = _this.diagramEngine.getRoutingMatrix();
// now we need to extract, from the routing matrix, the very first walkable points
// so they can be used as origin and destination of the link to be created
var smartLink = _this.pathFinding.calculateLinkStartEndCoords(routingMatrix, directPathCoords);
if (smartLink) {
var start = smartLink.start, end = smartLink.end, pathToStart = smartLink.pathToStart, pathToEnd = smartLink.pathToEnd;
// second step: calculate a path avoiding hitting other elements
var simplifiedPath = _this.pathFinding.calculateDynamicPath(routingMatrix, start, end, pathToStart, pathToEnd);
var smartPath = generateDynamicPath(simplifiedPath);
_this.path$.set(smartPath).emit();
}
}
else {
// handle regular links
// draw the smoothing
// if the points are too close, just draw a straight line
var isHorizontal = Math.abs(firstPCoords.x - lastPCoords.x) > Math.abs(firstPCoords.y - lastPCoords.y);
var xOrY = isHorizontal ? 'x' : 'y';
var isStraight = false;
if (Math.abs(points[0][xOrY] - points[1][xOrY]) < 50) {
isStraight = true;
}
var path = generateCurvePath(firstPCoords, lastPCoords, isStraight ? 0 : _this.curvyness);
_this.path$.set(path).emit();
}
var label = _this.getLabel();
// update label position
if (label) {
label.setCoords(_this.calcCenterOfPath(firstPCoords, lastPCoords));
// TODO: check whether we want the label to rotate along with the line
// label.setRotation(this.calcLabelIncline(firstPCoords, lastPCoords));
}
// TODO: handle the multiple lines in between the points
// https://github.com/projectstorm/react-diagrams/blob/master/src/defaults/widgets/DefaultLinkWidget.tsx#L344-L371
_this.cdRef.detectChanges();
});
// observe link label and draw/remove accordingly
this.selectLabel()
.pipe(operators.filter(Boolean))
.subscribe(function (label) {
_this.diagramEngine.generateWidgetForLabel(label, _this.labelLayer);
_this.cdRef.detectChanges();
});
};
DefaultLinkComponent.prototype.calcLabelIncline = function (firstPoint, secondPoint) {
var dy = secondPoint.y - firstPoint.y;
var dx = secondPoint.x - firstPoint.x;
if (dx === 0) {
return 0;
}
var inclineAngel = (Math.atan(dy / dx) * 180) / Math.PI;
if (inclineAngel < 0) {
inclineAngel += 180;
}
return inclineAngel;
};
DefaultLinkComponent.prototype.calcCenterOfPath = function (firstPoint, secondPoint) {
return { x: (firstPoint.x + secondPoint.x) / 2 + 20, y: (firstPoint.y + secondPoint.y) / 2 + 20 };
};
DefaultLinkComponent.prototype.selectPath = function () {
return this.path$.value$;
};
return DefaultLinkComponent;
}(DefaultLinkModel));
DefaultLinkComponent.decorators = [
{ type: i0.Component, args: [{
selector: 'ngdx-default-link',
template: "<!-- Label Host -->\n<ng-template #labelLayer></ng-template>\n\n<svg class=\"link-container\">\n <!-- Link -->\n <g [id]=\"id\">\n <path\n [attr.stroke-width]=\"width\"\n [attr.stroke]=\"selectColor() | async\"\n [attr.d]=\"selectPath() | async\"\n class=\"default-link\"\n (mouseleave)=\"setHovered(false)\"\n (mouseenter)=\"setHovered()\"\n [ngClass]=\"{ hovered: selectHovered() | async }\"\n ></path>\n <path\n class=\"default-link\"\n (mouseleave)=\"setHovered(false)\"\n (mouseenter)=\"setHovered()\"\n [attr.stroke-width]=\"20\"\n [attr.stroke]=\"selectColor() | async\"\n [attr.stroke-linecap]=\"'round'\"\n [attr.data-linkid]=\"id\"\n [attr.stroke-opacity]=\"(selectHovered() | async) ? '0.1' : '0'\"\n [attr.d]=\"selectPath() | async\"\n ></path>\n </g>\n\n <!-- Points -->\n <g *ngFor=\"let point of getPoints(); trackBy: trackByPoints\" [id]=\"point.id\">\n <circle\n fill=\"currentColor\"\n [attr.cx]=\"point.selectX() | async\"\n [attr.cy]=\"point.selectY() | async\"\n r=\"5\"\n class=\"default-point\"\n [ngClass]=\"{ hovered: point.selectHovered() | async }\"\n />\n <circle\n [attr.data-pointid]=\"point.id\"\n [attr.data-linkid]=\"id\"\n (mouseleave)=\"point.setHovered(false); setHovered(false)\"\n (mouseenter)=\"point.setHovered(); setHovered()\"\n [attr.cx]=\"point.selectX() | async\"\n [attr.cy]=\"point.selectY() | async\"\n r=\"15\"\n [attr.opacity]=\"0\"\n [ngClass]=\"{ selected: point.selectSelected() | async }\"\n />\n </g>\n</svg>\n",
changeDetection: i0.ChangeDetectionStrategy.OnPush,
styles: [".link-container{pointer-events:all;position:relative}.default-link,.link-container{fill:none;overflow:visible}@-webkit-keyframes dash{0%{stroke-dashoffset:24}to{stroke-dashoffset:0}}@keyframes dash{0%{stroke-dashoffset:24}to{stroke-dashoffset:0}}.default-link.hovered{-webkit-animation:dash 1s linear infinite;animation:dash 1s linear infinite;stroke:#00c0ff;stroke-dasharray:10,2}.default-point{color:#d3d3d3;overflow:visible;pointer-events:all}.default-point.hovered{color:#00c0ff}"]
},] }
];
DefaultLinkComponent.ctorParameters = function () { return [
{ type: i0.ChangeDetectorRef }
]; };
DefaultLinkComponent.propDecorators = {
labelLayer: [{ type: i0.ViewChild, args: ['labelLayer', { read: i0.ViewContainerRef, static: true },] }]
};
var DefaultLinkFactory = /** @class */ (function (_super) {
__extends(DefaultLinkFactory, _super);
function DefaultLinkFactory(resolver, renderer) {
var _this = _super.call(this, 'default') || this;
_this.resolver = resolver;
_this.renderer = renderer;
return _this;
}
DefaultLinkFactory.prototype.generateWidget = function (diagramEngine, link, linksHost) {
var componentRef = linksHost.createComponent(this.getRecipe());
// attach coordinates and default positional behaviour to the generated component host
var rootNode = componentRef.location.nativeElement;
// default style for link
this.renderer.setStyle(rootNode, 'position', 'absolute');
this.renderer.addClass(rootNode, 'label');
// data attributes
this.renderer.setAttribute(rootNode, 'data-linkid', link.id);
// on destroy make sure to destroy the componentRef
link.onEntityDestroy().subscribe(function () {
componentRef.destroy();
});
// assign all passed properties to link initialization.
Object.entries(link).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
componentRef.instance[key] = value;
});
componentRef.instance.diagramEngine = diagramEngine;
componentRef.instance.setPainted(true);
return componentRef;
};
DefaultLinkFactory.prototype.getRecipe = function () {
return this.resolver.resolveComponentFactory(DefaultLinkComponent);
};
DefaultLinkFactory.prototype.getNewInstance = function () {
return new DefaultLinkModel();
};
return DefaultLinkFactory;
}(AbstractLinkFactory));
var DefaultPortModel = /** @class */ (function (_super) {
__extends(DefaultPortModel, _super);
function DefaultPortModel(_a) {
var _b = _a === void 0 ? {} : _a, _c = _b.isInput, isInput = _c === void 0 ? true : _c, _d = _b.name, name = _d === void 0 ? 'port' : _d, _e = _b.type, type = _e === void 0 ? 'default' : _e, _f = _b.id, id = _f === void 0 ? null : _f, _g = _b.label, label = _g === void 0 ? null : _g, _h = _b.linkType, linkType = _h === void 0 ? 'default' : _h, _j = _b.maximumLinks, maximumLinks = _j === void 0 ? null : _j;
var _this = _super.call(this, name, type, id, null, linkType) || this;
_this.in = isInput;
_this.label = label || name;
if (_this.in) {
_this.setCanCreateLinks(false);
}
else {
_this.setMaximumLinks(maximumLinks);
_this.setMagnetic(false);
}
return _this;
}
DefaultPortModel.prototype.link = function (port) {
if (_super.prototype.getCanCreateLinks.call(this)) {
var link = new DefaultLinkModel({ type: this.getLinkType() });
link.setSourcePort(this);
link.setTargetPort(port);
return link;
}
return null;
};
DefaultPortModel.prototype.createLinkModel = function () {
if (_super.prototype.getCanCreateLinks.call(this)) {
return new DefaultLinkModel({ type: this.getLinkType() });
}
};
DefaultPortModel.prototype.canLinkToPort = function (port) {
if (port instanceof DefaultPortModel) {
return this.in !== port.in;
}
return true;
};
return DefaultPortModel;
}(PortModel));
var DefaultNodeModel = /** @class */ (function (_super) {
__extends(DefaultNodeModel, _super);
function DefaultNodeModel(_a) {
var _b = _a === void 0 ? {} : _a, _c = _b.name, name = _c === void 0 ? 'Untitled' : _c, _d = _b.type, type = _d === void 0 ? 'default' : _d, _e = _b.color, color = _e === void 0 ? 'rgb(0, 192, 255)' : _e, id = _b.id;
var _this = _super.call(this, type, id) || this;
_this.name = name;
_this.color = color;
_this.height$ = _this.selectHeight();
_this.width$ = _this.selectWidth();
return _this;
}
DefaultNodeModel.prototype.addInPort = function (_a) {
var name = _a.name, _b = _a.type, type = _b === void 0 ? 'default' : _b, id = _a.id, _c = _a.linkType, linkType = _c === void 0 ? 'default' : _c;
var port = new DefaultPortModel({
isInput: true,
name: name,
type: type,
id: id,
label: null,
linkType: linkType
});
this.addPort(port);
return port;
};
DefaultNodeModel.prototype.addOutPort = function (_a) {
var name = _a.name, _b = _a.type, type = _b === void 0 ? 'default' : _b, id = _a.id, _c = _a.linkType, linkType = _c === void 0 ? 'default' : _c, _d = _a.maximumLinks, maximumLinks = _d === void 0 ? null : _d;
var port = new DefaultPortModel({
isInput: false,
name: name,
type: type,
id: id,
label: null,
linkType: linkType,
maximumLinks: maximumLinks
});
this.addPort(port);
return port;
};
return DefaultNodeModel;
}(NodeModel));
var DefaultNodeComponent = /** @class */ (function (_super) {
__extends(DefaultNodeComponent, _super);
function DefaultNodeComponent() {
return _super.call(this, { type: 'ngdx-default-node' }) || this;
}
DefaultNodeComponent.prototype.ngOnInit = function () {
var _this = this;
// when node is painted and port isn't, draw ports
this.paintChanges()
.pipe(operators.filter(function (paintedE) { return paintedE.isPainted; }), operators.switchMap(function () { return _this.selectPorts(); }))
.subscribe(function (ports) {
ports.forEach(function (port) {
if (!port.getPainted()) {
_this.generatePort(port);
}
});
});
};
DefaultNodeComponent.prototype.generatePort = function (port) {
var diagramEngine = this.getDiagramEngine();
diagramEngine.generateWidgetForPort(port, this.portsLayer);
port.paintChanges().subscribe(function (paintedEvent) {
if (paintedEvent.isPainted) {
port.updateCoords(diagramEngine.getPortCoords(port));
}
});
};
return DefaultNodeComponent;
}(DefaultNodeModel));
DefaultNodeComponent.decorators = [
{ type: i0.Component, args: [{
selector: 'ngdx-default-node',
template: "<div\n class=\"default-node\"\n [ngStyle]=\"{\n 'height.px': height$ | async,\n 'width.px': width$ | async,\n 'background-color': color\n }\"\n>\n <div class=\"ports\">\n <ng-template #portsLayer></ng-template>\n </div>\n</div>\n",
changeDetection: i0.ChangeDetectionStrategy.OnPush,
styles: [":host.selected .default-node{background-color:#fff!important;border-color:#00f}:host .default-node{border-radius:10px;cursor:auto;pointer-events:all;transition:all .3s ease-in-out;width:100%}:host .default-node .title{border-bottom:1px solid #00f;padding:10px;text-align:center}:host .ports{display:flex;flex-direction:column;flex-grow:1}"]
},] }
];
DefaultNodeComponent.ctorParameters = function () { return []; };
DefaultNodeComponent.propDecorators = {
portsLayer: [{ type: i0.ViewChild, args: ['portsLayer', { read: i0.ViewContainerRef, static: true },] }]
};
var AbstractNodeFactory = /** @class */ (function (_super) {
__extends(AbstractNodeFactory, _super);
function AbstractNodeFactory() {
return _super !== null && _super.apply(this, arguments) || this;
}
return AbstractNodeFactory;
}(AbstractFactory));
var DefaultNodeFactory = /** @class */ (function (_super) {
__extends(DefaultNodeFactory, _super);
function DefaultNodeFactory(resolver, renderer) {
var _this = _super.call(this, 'default') || this;
_this.resolver = resolver;
_this.renderer = renderer;
return _this;
}
DefaultNodeFactory.prototype.generateWidget = function (diagramEngine, node, nodesHost) {
var _this = this;
var componentRef = nodesHost.createComponent(this.getRecipe());
// attach coordinates and default positional behaviour to the generated component host
var rootNode = componentRef.location.nativeElement;
// default style for node
this.renderer.setStyle(rootNode, 'position', 'absolute');
this.renderer.setStyle(rootNode, 'display', 'block');
// data attributes
this.renderer.setAttribute(rootNode, 'data-nodeid', node.id);
// subscribe to node coordinates
node.selectCoords().subscribe(function (_a) {
var x = _a.x, y = _a.y;
_this.renderer.setStyle(rootNode, 'left', x + "px");
_this.renderer.setStyle(rootNode, 'top', y + "px");
});
node.selectionChanges().subscribe(function (e) {
e.isSelected
? _this.renderer.addClass(rootNode, 'selected')
: _this.renderer.removeClass(rootNode, 'selected');
});
node.onEntityDestroy().subscribe(function () {
componentRef.destroy();
});
// assign all passed properties to node initialization.
Object.entries(node).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
componentRef.instance[key] = value;
});
componentRef.instance.setDiagramEngine(diagramEngine);
componentRef.instance.setPainted(true);
return componentRef;
};
DefaultNodeFactory.prototype.getRecipe = function () {
return this.resolver.resolveComponentFactory(DefaultNodeComponent);
};
DefaultNodeFactory.prototype.getNewInstance = function (initialConfig) {
return new DefaultNodeModel(initialConfig);
};
return DefaultNodeFactory;
}(AbstractNodeFactory));
var AbstractPortFactory = /** @class */ (function (_super) {
__extends(AbstractPortFactory, _super);
function AbstractPortFactory() {
return _super !== null && _super.apply(this, arguments) || this;
}
return AbstractPortFactory;
}(AbstractFactory));
var DefaultPortComponent = /** @class */ (function (_super) {
__extends(DefaultPortComponent, _super);
function DefaultPortComponent() {
return _super.call(this) || this;
}
return DefaultPortComponent;
}(DefaultPortModel));
DefaultPortComponent.decorators = [
{ type: i0.Component, args: [{
selector: 'ngdx-default-port',
template: "<div [ngClass]=\"in ? 'in' : 'out'\" draggable=\"false\"></div>\n",
changeDetection: i0.ChangeDetectionStrategy.OnPush,
styles: [":host{background-color:#d3d3d3;border:1px solid grey;border-radius:60px;height:10px;margin:10px 0;position:relative;width:10px}:host:hover{background-color:green}:host.out{right:-195px}:host.in{left:-5px}"]
},] }
];
DefaultPortComponent.ctorParameters = function () { return []; };
var DefaultPortFactory = /** @class */ (function (_super) {
__extends(DefaultPortFactory, _super);
function DefaultPortFactory(resolver, renderer) {
var _this = _super.call(this, 'default') || this;
_this.resolver = resolver;
_this.renderer = renderer;
return _this;
}
DefaultPortFactory.prototype.generateWidget = function (port, portsHost) {
var componentRef = portsHost.createComponent(this.getRecipe());
// attach coordinates and default positional behaviour to the generated component host
var rootNode = componentRef.location.nativeElement;
// data attributes
this.renderer.setAttribute(rootNode, 'data-portid', port.id);
this.renderer.setAttribute(rootNode, 'data-name', port.getName());
port.in
? this.renderer.addClass(rootNode, 'in')
: this.renderer.addClass(rootNode, 'out');
// assign all passed properties to node initialization.
Object.entries(port).forEach(function (_a) {
var _b = __read(_a, 2), key = _b[0], value = _b[1];
componentRef.instance[key] = value;
});
port.onEntityDestroy().subscribe(function () {
componentRef.destroy();
});
componentRef.instance.setPainted(true);
return componentRef;
};
DefaultPortFactory.prototype.getRecipe = function () {
return this.resolver.resolveComponentFactory(DefaultPortComponent);
};
DefaultPortFactory.prototype.getNewInstance = function (initialConfig) {
return new DefaultPortModel(Object.assign({ isInput: true, name: 'unknown' }, initialConfig));
};
return DefaultPortFactory;
}(AbstractPortFactory));
var DiagramModel = /** @class */ (function (_super) {
__extends(DiagramModel, _super);
function DiagramModel(diagramEngine, id, logPrefix) {
if (logPrefix === void 0) { logPrefix = '[Diagram]'; }
var _this = _super.call(this, id, logPrefix) || this;
_this.diagramEngine = diagramEngine;
_this.nodes$ = createEntityState([], _this.entityPipe('nodes'));
_this.links$ = createEntityState([], _this.entityPipe('links'));
_this.offsetX$ = createValueState(0, _this.entityPipe('offsetX'));
_this.offsetY$ = createValueState(0, _this.entityPipe('offsetY'));
_this.zoom$ = createValueState(100, _this.entityPipe('zoom'));
_this.maxZoomOut$ = createValueState(null);
_this.maxZoomIn$ = createValueState(null);
_this.gridSize$ = createValueState(0);
return _this;
}
// TODO: support the following events for links and nodes
// removed, updated<positionChanged/dataChanged>, added
DiagramModel.prototype.getNodes = function () {
return this.nodes$.value;
};
DiagramModel.prototype.getNodesArray = function () {
return this.nodes$.array();
};
DiagramModel.prototype.getNode = function (id) {
return this.nodes$.get(id);
};
DiagramModel.prototype.getLink = function (id) {
return this.links$.get(id);
};
DiagramModel.prototype.getLinks = function () {
return this.links$.value;
};
DiagramModel.prototype.getLinksArray = function () {
return this.links$.array();
};
DiagramModel.prototype.getAllPorts = function (options) {
if (options === void 0) { options = {}; }
var result = new Map();
this.getNodes().forEach(function (node) {
var ports = options.filter ? node.getPortsArray().filter(options.filter) : node.getPortsArray();
ports.forEach(function (port) { return result.set(port.id, port); });
});
return result;
};
/**
* Add a node to the diagram
* @returns Inserted Node
*/
DiagramModel.prototype.addNode = function (node) {
this.nodes$.add(node).emit();
return node;
};
/**
* Delete a node from the diagram
*/
DiagramModel.prototype.deleteNode = function (nodeOrId) {
var e_1, _a, e_2, _b;
var nodeId = typeof nodeOrId === 'string' ? nodeOrId : nodeOrId.id;
var node = this.getNode(nodeId);
try {
for (var _c = __values(node.getPorts().values()), _d = _c.next(); !_d.done; _d = _c.next()) {
var port = _d.value;
try {
for (var _e = (e_2 = void 0, __values(port.getLinks().values())), _f = _e.next(); !_f.done; _f = _e.next()) {
var link = _f.value;
this.deleteLink(link);
}
}
catch (e_2_1) { e_2 = { error: e_2_1 }; }
finally {
try {
if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
}
finally { if (e_2) throw e_2.error; }
}
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
}
finally { if (e_1) throw e_1.error; }
}
this.nodes$.remove(nodeId).emit();
};
/**
* Get nodes as observable, use `.getValue()` for snapshot
*/
DiagramModel.prototype.selectNodes = function () {
return this.nodes$.value$;
};
/**
* Add link
* @returns Newly created link
*/
DiagramModel.prototype.addLink = function (link) {
this.links$.add(link).emit();
return link;
};
/**
* Delete link
*/
DiagramModel.prototype.deleteLink = function (linkOrId) {
var linkId = typeof linkOrId === 'string' ? linkOrId : linkOrId.id;
this.links$.remove(linkId).emit();
};
DiagramModel.prototype.reset = function () {
this.nodes$.clear().emit();
this.links$.clear().emit();
};
/**
* Get links behaviour subject, use `.getValue()` for snapshot
*/
DiagramModel.prototype.selectLinks = function () {
return this.links$.value$;
};
// /**
// * Serialize the diagram model to JSON
// * @returns diagram model as a string
// */
DiagramModel.prototype.serialize = function () {
var serializedNodes = this.nodes$.map(function (node) { return node.serialize(); });
var serializedLinks = this.links$.map(function (link) { return link.serialize(); });
return Object.assign(Object.assign({}, _super.prototype.serialize.call(this)), { nodes: serializedNodes, links: serializedLinks });
};
DiagramModel.prototype.setMaxZoomOut = function (maxZoomOut) {
this.maxZoomOut$.set(maxZoomOut).emit();
};
DiagramModel.prototype.setMaxZoomIn = function (maxZoomIn) {
this.maxZoomIn$.set(maxZoomIn).emit();
};
DiagramModel.prototype.getMaxZoomOut = function () {
return this.maxZoomOut$.value;
};
DiagramModel.prototype.getMaxZoomIn = function () {
return this.maxZoomIn$.value;
};
DiagramModel.prototype.setOffset = function (x, y) {
this.offsetX$.set(x).emit();
this.offsetY$.set(y).emit();
};
DiagramModel.prototype.setOffsetX = function (x) {
this.offsetX$.set(x).emit();
};
DiagramModel.prototype.getOffsetX = function () {
return this.offsetX$.value;
};
DiagramModel.prototype.selectOffsetX = function () {
return this.offsetX$.value$;
};
DiagramModel.prototype.setOffsetY = function (y) {
this.offsetY$.set(y).emit();
};
DiagramModel.prototype.getOffsetY = function () {
return this.offsetY$.value;
};
DiagramModel.prototype.selectOffsetY = function () {
return this.offsetY$.value$;
};
DiagramModel.prototype.setZoomLevel = function (z) {
var maxZoomIn = this.getMaxZoomIn();
var maxZoomOut = this.getMaxZoomOut();
// check if zoom levels exceeded defined boundaries
if ((maxZoomIn && z > maxZoomIn) || (maxZoomOut && z < maxZoomOut)) {
return;
}
this.zoom$.set(z).emit();
};
DiagramModel.prototype.getZoomLevel = function () {
return this.zoom$.value;
};
DiagramModel.prototype.selectZoomLevel = function () {
return this.zoom$.value$;
};
DiagramModel.prototype.getDiagramEngine = function () {
return this.diagramEngine;
};
DiagramModel.prototype.clearSelection = function (ignore) {
if (ignore === void 0) { ignore = null; }
this.getSelectedItems().forEach(function (element) {
if ((ignore === null || ignore === void 0 ? void 0 : ignore.id) === element.id) {
return;
}
element.setSelected(false);
});
};
DiagramModel.prototype.getGridPosition = function (_a) {
var x = _a.x, y = _a.y;
var gridSize = this.gridSize$.value;
if (gridSize === 0) {
return { x: x, y: y };
}
return {
x: gridSize * Math.floor((x + gridSize / 2) / gridSize),
y: gridSize * Math.floor((y + gridSize / 2) / gridSize)
};
};
DiagramModel.prototype.getSelectedItems = function () {
var e_3, _a;
var filters = [];
for (var _i = 0; _i < arguments.length; _i++) {
filters[_i] = arguments[_i];
}
filters = coerceArray(filters);
var items = [];
var nodes = this.nodes$.array();
var links = this.links$.array();
var selectedNodes = function () { return nodes.flatMap(function (node) { return node.getSelectedEntities(); }); };
var selectedPorts = function () { return nodes.flatMap(function (node) { return node.getPortsArray().flatMap(function (port) { return port.getSelectedEntities(); }); }); };
var selectedLinks = function () { return links.flatMap(function (link) { return link.getSelectedEntities(); }); };
var selectedPoints = function () { return links.flatMap(function (link) { return link.getPoints().flatMap(function (point) { return point.getSelectedEntities(); }); }); };
if (isEmptyArray(filters)) {
items.push.apply(items, __spread(selectedNodes(), selectedPorts(), selectedLinks(), selectedPoints()));
}
else {
var byType = {
node: selectedNodes,
port: selectedPorts,
link: selectedLinks,
point: selectedPoints
};
try {
for (var filters_1 = __values(filters), filters_1_1 = filters_1.next(); !filters_1_1.done; filters_1_1 = filters_1.next()) {
var type = filters_1_1.value;
items.push.apply(items, __spread(byType[type]()));
}
}
catch (e_3_1) { e_3 = { error: e_3_1 }; }
finally {
try {
if (filters_1_1 && !filters_1_1.done && (_a = filters_1.return)) _a.call(filters_1);
}
finally { if (e_3) throw e_3.error; }
}
}
return unique(items);
};
DiagramModel.prototype.addAll = function () {
var e_4, _a;
var models = [];
for (var _i = 0; _i < arguments.length; _i++) {
models[_i] = arguments[_i];
}
var links = [];
var nodes = [];
try {
for (var models_1 = __values(models), models_1_1 = models_1.next(); !models_1_1.done; models_1_1 = models_1.next()) {
var model = models_1_1.value;
if (model instanceof LinkModel) {
links.push(model);
}
else if (model instanceof NodeModel) {
nodes.push(model);
}
}
}
catch (e_4_1) { e_4 = { error: e_4_1 }; }
finally {
try {
if (models_1_1 && !models_1_1.done && (_a = models_1.return)) _a.call(models_1);
}
finally { if (e_4) throw e_4.error; }
}
this.addLinks(links);
this.addNodes(nodes);
return models;
};
DiagramModel.prototype.addLinks = function (links) {
this.links$.addMany(links).emit();
};
DiagramModel.prototype.addNodes = function (nodes) {
this.nodes$.addMany(nodes).emit();
};
DiagramModel.prototype.destroy = function () {
_super.prototype.destroy.call(this);
this.nodes$.destroy();
this.links$.destroy();
};
return DiagramModel;
}(BaseEntity));
var TemplateVarContext = /** @class */ (function () {
function TemplateVarContext() {
}
return TemplateVarContext;
}());
var TemplateVarDirective = /** @class */ (function () {
function TemplateVarDirective(vcRef, templateRef) {
this.vcRef = vcRef;
this.templateRef = templateRef;
this.context = new TemplateVarContext();
}
Object.defineProperty(TemplateVarDirective.prototype, "templateVar", {
set: function (context) {
this.context.$implicit = this.context.templateVar = context;
this.updateView();
},
enumerable: false,
configurable: true
});
TemplateVarDirective.prototype.updateView = function () {
if (!this.view) {
this.vcRef.clear();
this.view = this.vcRef.createEmbeddedView(this.templateRef, this.context);
}
else {
this.view.markForCheck();
}
};
return TemplateVarDirective;
}());
TemplateVarDirective.decorators = [
{ type: i0.Directive, args: [{
selector: '[templateVar]',
},] }
];
TemplateVarDirective.ctorParameters = function () { return [
{ type: i0.ViewContainerRef },
{ type: i0.TemplateRef }
]; };
TemplateVarDirective.propDecorators = {
templateVar: [{ type: i0.Input }]
};
var NgxDiagramsModule = /** @class */ (function () {
function NgxDiagramsModule() {
}
return NgxDiagramsModule;
}());
NgxDiagramsModule.decorators = [
{ type: i0.NgModule, args: [{
declarations: [NgxDiagramComponent, TemplateVarDirective],
imports: [common.CommonModule],
exports: [NgxDiagramComponent],
},] }
];
var DiagramEngine = /** @class */ (function () {
function DiagramEngine(resolver, rendererFactory) {
this.resolver = resolver;
this.rendererFactory = rendererFactory;
this.nodeFactories = new Map();
this.labelFactories = new Map();
this.linkFactories = new Map();
this.portFactories = new Map();
this.canvas$ = createValueState(null);
// calculated only when smart routing is active
this.canvasMatrix = [];
this.routingMatrix = [];
// used when at least one element has negative coordinates
this.hAdjustmentFactor = 0;
this.vAdjustmentFactor = 0;
this.markMatrixPoint = function (matrix, x, y) {
if (matrix[y] !== undefined && matrix[y][x] !== undefined) {
matrix[y][x] = 1;
}
};
this._renderer = this.rendererFactory.createRenderer(null, null);
}
DiagramEngine.prototype.createDiagram = function () {
this.diagramModel = new DiagramModel(this);
return this.diagramModel;
};
DiagramEngine.prototype.registerDefaultFactories = function () {
this.registerNodeFactory(new DefaultNodeFactory(this.resolver, this._renderer));
this.registerPortFactory(new DefaultPortFactory(this.resolver, this._renderer));
this.registerLinkFactory(new DefaultLinkFactory(this.resolver, this._renderer));
this.registerLabelFactory(new DefaultLabelFactory(this.resolver, this._renderer));
};
//#region Factories
// LABELS
DiagramEngine.prototype.registerLabelFactory = function (labelFactory) {
this.labelFactories.set(labelFactory.type, labelFactory);
};
DiagramEngine.prototype.getLabelFactories = function () {
return this.labelFactories;
};
DiagramEngine.prototype.getLabelFactory = function (type) {
if (this.labelFactories.has(type)) {
return this.labelFactories.get(type);
}
throw new Error("cannot find factory for node of type: [" + type + "]");
};
DiagramEngine.prototype.getFactoryForLabel = function (label) {
return this.getLabelFactory(label.getType());
};
DiagramEngine.prototype.generateWidgetForLabel = function (label, labelHost) {
var labelFactory = this.getFactoryForLabel(label);
if (!labelFactory) {
throw new Error("Cannot find widget factory for node: " + label.getType());
}
return labelFactory.generateWidget(label, labelHost);
};
// NODES
DiagramEngine.prototype.registerNodeFactory = function (nodeFactory) {
this.nodeFactories.set(nodeFactory.type, nodeFactory);
};
DiagramEngine.prototype.getNodeFactories = function () {
return this.nodeFactories;
};
DiagramEngine.prototype.getNodeFactory = function (type) {
if (this.nodeFactories.has(type)) {
return this.nodeFactories.get(type);
}
throw new Error("cannot find factory for node of type: [" + type + "]");
};
DiagramEngine.prototype.getFactoryForNode = function (node) {
return this.getNodeFactory(node.getType());
};
DiagramEngine.prototype.generateWidgetForNode = function (node, nodesHost) {
var nodeFactory = this.getFactoryForNode(node);
if (!nodeFactory) {
throw new Error("Cannot find widget factory for node: " + node.getType());
}
return nodeFactory.generateWidget(this, node, nodesHost);
};
// PORTS
DiagramEngine.prototype.registerPortFactory = function (factory) {
this.portFactories.set(factory.type, factory);
};
DiagramEngine.prototype.getPortFactories = function () {
return this.portFactories;
};
DiagramEngine.prototype.getPortFactory = function (type) {
if (this.portFactories.has(type)) {
return this.portFactories.get(type);
}
throw new Error("cannot find factory for port of type: [" + type + "]");
};
DiagramEngine.prototype.getFactoryForPort = function (port) {
return this.getPortFactory(port.getType());
};
DiagramEngine.prototype.generateWidgetForPort = function (port, portsHost) {
var portFactory = this.getFactoryForPort(port);
if (!portFactory) {
throw new Error("Cannot find widget factory for port: " + port.getType());
}
return portFactory.generateWidget(port, portsHost);
};
// LINKS
DiagramEngine.prototype.getLinkFactories = function () {
return this.linkFactories;
};
DiagramEngine.prototype.registerLinkFactory = function (factory) {
this.linkFactories.set(factory.type, factory);
};
DiagramEngine.prototype.getLinkFactory = function (type) {
if (this.linkFactories.has(type)) {
return this.linkFactories.get(type);
}
throw new Error("cannot find factory for link of type: [" + type + "]");
};
DiagramEngine.prototype.getFactoryForLink = function (link) {
return this.getLinkFactory(link.getType());
};
DiagramEngine.prototype.generateWidgetForLink = function (link, linksHost) {
var linkFactory = this.getFactoryForLink(link);
if (!linkFactory) {
throw new Error("Cannot find link factory for link: " + link.getType());
}
return linkFactory.generateWidget(this, link, linksHost);
};
//#endregion
DiagramEngine.prototype.getNodeElement = function (node) {
var selector = this.canvas$.value.querySelector("[data-nodeid=\"" + node.id + "\"]");
if (selector === null) {
throw new Error('Cannot find Node element with node id: [' + node.id + ']');
}
return selector;
};
DiagramEngine.prototype.getNodePortElement = function (port) {
var selector = this.canvas$.value.querySelector("[data-nodeid=\"" + port.getParent().id + "\"] [data-portid=\"" + port.id + "\"]");
if (selector === null) {
throw new Error('Cannot find Node Port element with node id: [' + port.getParent().id + '] and port id: [' + port.id + ']');
}
return selector;
};
DiagramEngine.prototype.getPortCenter = function (port) {
var sourceElement = this.getNodePortElement(port);
var sourceRect = sourceElement.getBoundingClientRect();
var rel = this.getRelativePoint(sourceRect.left, sourceRect.top);
return {
x: sourceElement.offsetWidth / 2 +
(rel.x - this.diagramModel.getOffsetX()) / (this.diagramModel.getZoomLevel() / 100.0),
y: sourceElement.offsetHeight / 2 +
(rel.y - this.diagramModel.getOffsetY()) / (this.diagramModel.getZoomLevel() / 100.0)
};
};
/**
* Calculate rectangular coordinates of the port passed in.
*/
DiagramEngine.prototype.getPortCoords = function (port) {
var sourceElement = this.getNodePortElement(port);
var sourceRect = sourceElement.getBoundingClientRect();
var canvasRect = this.canvas$.value.getBoundingClientRect();
return {
x: (sourceRect.x - this.diagramModel.getOffsetX()) / (this.diagramModel.getZoomLevel() / 100.0) - canvasRect.left,
y: (sourceRect.y - this.diagramModel.getOffsetY()) / (this.diagramModel.getZoomLevel() / 100.0) - canvasRect.top,
width: sourceRect.width,
height: sourceRect.height
};
};
/**
* Determine the width and height of the node passed in.
* It currently assumes nodes have a rectangular shape, can be overriden for customised shapes.
*/
DiagramEngine.prototype.getNodeDimensions = function (node) {
if (!this.canvas$.value) {
return {
width: 0,
height: 0
};
}
var nodeElement = this.getNodeElement(node);
var nodeRect = nodeElement.getBoundingClientRect();
return {
width: nodeRect.width,
height: nodeRect.height
};
};
DiagramEngine.prototype.setCanvas = function (canvas) {
this.canvas$.set(canvas).emit();
};
DiagramEngine.prototype.getRelativeMousePoint = function (event) {
var point = this.getRelativePoint(event.clientX, event.clientY);
return {
x: (point.x - this.diagramModel.getOffsetX()) / (this.diagramModel.getZoomLevel() / 100.0),
y: (point.y - this.diagramModel.getOffsetY()) / (this.diagramModel.getZoomLevel() / 100.0)
};
};
DiagramEngine.prototype.getRelativePoint = function (x, y) {
var canvasRect = this.canvas$.value.getBoundingClientRect();
return { x: x - canvasRect.left, y: y - canvasRect.top };
};
DiagramEngine.prototype.getDiagramModel = function () {
return this.diagramModel;
};
DiagramEngine.prototype.isModelLocked = function (model) {
if (this.diagramModel.getLocked()) {
return true;
}
return model.getLocked();
};
/**
* fit the canvas zoom levels to the elements contained.
* @param additionalZoomFactor allow for further zooming out to make sure edges doesn't cut
*/
DiagramEngine.prototype.zoomToFit = function (additionalZoomFactor) {
var _this = this;
if (additionalZoomFactor === void 0) { additionalZoomFactor = 0.005; }
this.canvas$.value$.pipe(operators.filter(Boolean), operators.take(1), operators.delay(0)).subscribe(function (canvas) {
var xFactor = canvas.clientWidth / canvas.scrollWidth;
var yFactor = canvas.clientHeight / canvas.scrollHeight;
var zoomFactor = xFactor < yFactor ? xFactor : yFactor;
var newZoomLvl = _this.diagramModel.getZoomLevel() * (zoomFactor - additionalZoomFactor);
var maxZoomOut = _this.diagramModel.getMaxZoomOut();
if (maxZoomOut && newZoomLvl < maxZoomOut) {
newZoomLvl = maxZoomOut;
}
_this.diagramModel.setZoomLevel(newZoomLvl);
// TODO: either block the canvas movement on 0,0 or detect the top left furthest element and set the offest to its edges
_this.diagramModel.setOffset(0, 0);
});
};
// SMART ROUTING
DiagramEngine.prototype.setSmartRoutingStatus = function (status) {
if (status && !this.pathFinding) {
this.pathFinding = new PathFinding(this);
}
else {
this.pathFinding = null;
}
this.smartRouting = status;
};
DiagramEngine.prototype.getPathfinding = function () {
return this.pathFinding;
};
DiagramEngine.prototype.calculateCanvasMatrix = function () {
var _a = this.calculateMatrixDimensions(), canvasWidth = _a.width, hAdjustmentFactor = _a.hAdjustmentFactor, canvasHeight = _a.height, vAdjustmentFactor = _a.vAdjustmentFactor;
this.hAdjustmentFactor = hAdjustmentFactor;
this.vAdjustmentFactor = vAdjustmentFactor;
var matrixWidth = Math.ceil(canvasWidth / ROUTING_SCALING_FACTOR);
var matrixHeight = Math.ceil(canvasHeight / ROUTING_SCALING_FACTOR);
this.canvasMatrix = Array.from({ length: matrixHeight }, function (_, i) { return i + 1; }).map(function () {
return new Array(matrixWidth).fill(0);
});
};
/**
* Despite being a long method, we simply iterate over all three collections (nodes, ports and points)
* to find the highest X and Y dimensions, so we can build the matrix large enough to contain all elements.
*/
DiagramEngine.prototype.calculateMatrixDimensions = function () {
var allNodesCoords = this.diagramModel.getNodesArray().map(function (item) { return ({
x: item.getCoords().x,
width: item.getWidth(),
y: item.getCoords().y,
height: item.getHeight()
}); });
var allLinks = this.diagramModel.getLinksArray();
var allPortsCoords = allLinks
.flatMap(function (link) { return [link.getSourcePort(), link.getTargetPort()]; })
.filter(function (port) { return port !== null; })
.map(function (item) { return ({
x: item.getX(),
width: item.getWidth(),
y: item.getY(),
height: item.getHeight()
}); });
var allPointsCoords = allLinks
.flatMap(function (link) { return link.getPoints(); })
.map(function (item) { return ({
// points don't have width/height, so let's just use 0
x: item.getCoords().x,
width: 0,
y: item.getCoords().y,
height: 0
}); });
var canvas = this.canvas$.value;
var allElements = allNodesCoords.concat(allPortsCoords, allPointsCoords);
var minX = Math.floor(Math.min(allElements.reduce(function (a, b) {
return a.x <= b.x ? a : b;
}).x, 0) / ROUTING_SCALING_FACTOR) * ROUTING_SCALING_FACTOR;
var maxXElement = allElements.reduce(function (a, b) {
return a.x + a.width >= b.x + b.width ? a : b;
});
var maxX = Math.max(maxXElement.x + maxXElement.width, canvas.offsetWidth);
var minY = Math.floor(Math.min(allElements.reduce(function (a, b) {
return a.y <= b.y ? a : b;
}).y, 0) / ROUTING_SCALING_FACTOR) * ROUTING_SCALING_FACTOR;
var maxYElement = allElements.reduce(function (a, b) {
return a.y + a.height >= b.y + b.height ? a : b;
});
var maxY = Math.max(maxYElement.y + maxYElement.height, canvas.offsetWidth);
var width = Math.ceil(Math.abs(minX) + maxX);
var height = Math.ceil(Math.abs(minY) + maxY);
return {
width: width,
hAdjustmentFactor: Math.abs(minX) / ROUTING_SCALING_FACTOR + 1,
height: height,
vAdjustmentFactor: Math.abs(minY) / ROUTING_SCALING_FACTOR + 1
};
};
/**
* A representation of the canvas in the following format:
*
* +-----------------+
* | 0 0 0 0 0 0 0 0 |
* | 0 0 0 0 0 0 0 0 |
* | 0 0 0 0 0 0 0 0 |
* | 0 0 0 0 0 0 0 0 |
* | 0 0 0 0 0 0 0 0 |
* +-----------------+
*
* In which all walkable points are marked by zeros.
* It uses @link{#ROUTING_SCALING_FACTOR} to reduce the matrix dimensions and improve performance.
*/
DiagramEngine.prototype.getCanvasMatrix = function () {
if (this.canvasMatrix.length === 0) {
this.calculateCanvasMatrix();
}
return this.canvasMatrix;
};
/**
* The routing matrix does not have negative indexes, but elements could be negatively positioned.
* We use the functions below to translate back and forth between these coordinates, relying on the
* calculated values of hAdjustmentFactor and vAdjustmentFactor.
*/
DiagramEngine.prototype.translateRoutingX = function (x, reverse) {
if (reverse === void 0) { reverse = false; }
return x + this.hAdjustmentFactor * (reverse ? -1 : 1);
};
DiagramEngine.prototype.translateRoutingY = function (y, reverse) {
if (reverse === void 0) { reverse = false; }
return y + this.vAdjustmentFactor * (reverse ? -1 : 1);
};
/**
* A representation of the canvas in the following format:
*
* +-----------------+
* | 0 0 1 1 0 0 0 0 |
* | 0 0 1 1 0 0 1 1 |
* | 0 0 0 0 0 0 1 1 |
* | 1 1 0 0 0 0 0 0 |
* | 1 1 0 0 0 0 0 0 |
* +-----------------+
*
* In which all points blocked by a node (and its ports) are
* marked as 1; points were there is nothing (ie, free) receive 0.
*/
DiagramEngine.prototype.getRoutingMatrix = function () {
if (this.routingMatrix.length === 0) {
this.calculateRoutingMatrix();
}
return this.routingMatrix;
};
DiagramEngine.prototype.calculateRoutingMatrix = function () {
var matrix = this.getCanvasMatrix().map(function (item) { return item.slice(0); });
// nodes need to be marked as blocked points
this.markNodes(matrix);
// same thing for ports
this.markPorts(matrix);
this.routingMatrix = matrix;
};
DiagramEngine.prototype.getSmartRouting = function () {
return !!this.smartRouting;
};
/**
* Updates (by reference) where nodes will be drawn on the matrix passed in.
*/
DiagramEngine.prototype.markNodes = function (matrix) {
var _this = this;
this.diagramModel.getNodes().forEach(function (node) {
var startX = Math.floor(node.getCoords().x / ROUTING_SCALING_FACTOR);
var endX = Math.ceil((node.getCoords().x + node.getWidth()) / ROUTING_SCALING_FACTOR);
var startY = Math.floor(node.getCoords().y / ROUTING_SCALING_FACTOR);
var endY = Math.ceil((node.getCoords().y + node.getHeight()) / ROUTING_SCALING_FACTOR);
for (var x = startX - 1; x <= endX + 1; x++) {
for (var y = startY - 1; y < endY + 1; y++) {
_this.markMatrixPoint(matrix, _this.translateRoutingX(x), _this.translateRoutingY(y));
}
}
});
};
/**
* Updates (by reference) where ports will be drawn on the matrix passed in.
*/
DiagramEngine.prototype.markPorts = function (matrix) {
var _this = this;
var allElements = this.diagramModel
.getLinksArray()
.flatMap(function (link) { return [link.getSourcePort(), link.getTargetPort()]; });
allElements
.filter(function (port) { return port !== null; })
.forEach(function (port) {
var startX = Math.floor(port.getX() / ROUTING_SCALING_FACTOR);
var endX = Math.ceil((port.getX() + port.getWidth()) / ROUTING_SCALING_FACTOR);
var startY = Math.floor(port.getY() / ROUTING_SCALING_FACTOR);
var endY = Math.ceil((port.getY() + port.getHeight()) / ROUTING_SCALING_FACTOR);
for (var x = startX - 1; x <= endX + 1; x++) {
for (var y = startY - 1; y < endY + 1; y++) {
_this.markMatrixPoint(matrix, _this.translateRoutingX(x), _this.translateRoutingY(y));
}
}
});
};
return DiagramEngine;
}());
DiagramEngine.ɵprov = i0.ɵɵdefineInjectable({ factory: function DiagramEngine_Factory() { return new DiagramEngine(i0.ɵɵinject(i0.ComponentFactoryResolver), i0.ɵɵinject(i0.RendererFactory2)); }, token: DiagramEngine, providedIn: NgxDiagramsModule });
DiagramEngine.decorators = [
{ type: i0.Injectable, args: [{ providedIn: NgxDiagramsModule },] }
];
DiagramEngine.ctorParameters = function () { return [
{ type: i0.ComponentFactoryResolver },
{ type: i0.RendererFactory2 }
]; };
var DefaultLinkModule = /** @class */ (function () {
function DefaultLinkModule() {
}
return DefaultLinkModule;
}());
DefaultLinkModule.decorators = [
{ type: i0.NgModule, args: [{
declarations: [DefaultLinkComponent],
imports: [common.CommonModule],
exports: [DefaultLinkComponent],
entryComponents: [DefaultLinkComponent],
},] }
];
var DefaultNodeModule = /** @class */ (function () {
function DefaultNodeModule() {
}
return DefaultNodeModule;
}());
DefaultNodeModule.decorators = [
{ type: i0.NgModule, args: [{
declarations: [DefaultNodeComponent],
imports: [common.CommonModule],
exports: [DefaultNodeComponent],
entryComponents: [DefaultNodeComponent],
},] }
];
var DefaultPortModule = /** @class */ (function () {
function DefaultPortModule() {
}
return DefaultPortModule;
}());
DefaultPortModule.decorators = [
{ type: i0.NgModule, args: [{
declarations: [DefaultPortComponent],
imports: [common.CommonModule],
exports: [DefaultPortComponent],
entryComponents: [DefaultPortComponent]
},] }
];
var DefaultLabelModule = /** @class */ (function () {
function DefaultLabelModule() {
}
return DefaultLabelModule;
}());
DefaultLabelModule.decorators = [
{ type: i0.NgModule, args: [{
declarations: [DefaultLabelComponent],
imports: [common.CommonModule],
exports: [DefaultLabelComponent],
entryComponents: [DefaultLabelComponent],
},] }
];
var DagreEngine = /** @class */ (function () {
function DagreEngine() {
}
DagreEngine.prototype.instantiate = function () {
try {
this.g = new dagre.graphlib.Graph({ multigraph: true });
}
catch (error) {
console.warn("`dagre` packages isn't installed, please install it before using the DagreEngine plugin");
}
};
DagreEngine.prototype.redistribute = function (model, options) {
var _this = this;
if (options === void 0) { options = {}; }
this.instantiate();
this.g.setGraph(options.graph || {});
this.g.setDefaultEdgeLabel(function () {
return {};
});
var processedlinks = {};
// set nodes
model.getNodes().forEach(function (node) {
_this.g.setNode(node.id, {
width: node.getWidth(),
height: node.getHeight()
});
});
model.getLinks().forEach(function (link) {
// set edges
if (link.getSourcePort() && link.getTargetPort()) {
processedlinks[link.id] = true;
_this.g.setEdge({
v: link.getSourcePort().getNode().id,
w: link.getTargetPort().getNode().id,
name: link.id
});
}
});
// layout the graph
dagre.layout(this.g, options.layout);
this.g.nodes().forEach(function (v) {
var _a = _this.g.node(v), x = _a.x, y = _a.y;
model.getNode(v).setCoords({ x: x, y: y });
});
// also include links?
if (options.includeLinks) {
this.g.edges().forEach(function (e) {
var edge = _this.g.edge(e);
var link = model.getLink(e.name);
var points = [link.getFirstPoint()];
for (var i = 1; i < edge.points.length - 2; i++) {
points.push(new PointModel(link, { x: edge.points[i].x, y: edge.points[i].y }));
}
link.setPoints(points.concat(link.getLastPoint()));
});
}
};
return DagreEngine;
}());
DagreEngine.decorators = [
{ type: i0.Injectable }
];
/*
* Public API Surface of ngx-diagrams library
*/
/**
* Generated bundle index. Do not edit.
*/
exports.AbstractFactory = AbstractFactory;
exports.AbstractLabelFactory = AbstractLabelFactory;
exports.AbstractLinkFactory = AbstractLinkFactory;
exports.AbstractNodeFactory = AbstractNodeFactory;
exports.AbstractPortFactory = AbstractPortFactory;
exports.BaseAction = BaseAction;
exports.BaseEvent = BaseEvent;
exports.BaseModel = BaseModel;
exports.DagreEngine = DagreEngine;
exports.DefaultLabelComponent = DefaultLabelComponent;
exports.DefaultLabelFactory = DefaultLabelFactory;
exports.DefaultLabelModel = DefaultLabelModel;
exports.DefaultLabelModule = DefaultLabelModule;
exports.DefaultLinkComponent = DefaultLinkComponent;
exports.DefaultLinkFactory = DefaultLinkFactory;
exports.DefaultLinkModel = DefaultLinkModel;
exports.DefaultLinkModule = DefaultLinkModule;
exports.DefaultNodeComponent = DefaultNodeComponent;
exports.DefaultNodeFactory = DefaultNodeFactory;
exports.DefaultNodeModel = DefaultNodeModel;
exports.DefaultNodeModule = DefaultNodeModule;
exports.DefaultPortComponent = DefaultPortComponent;
exports.DefaultPortFactory = DefaultPortFactory;
exports.DefaultPortModel = DefaultPortModel;
exports.DefaultPortModule = DefaultPortModule;
exports.DiagramEngine = DiagramEngine;
exports.DiagramModel = DiagramModel;
exports.InvalidLinkDestroyed = InvalidLinkDestroyed;
exports.LabelModel = LabelModel;
exports.LinkCreatedAction = LinkCreatedAction;
exports.LinkModel = LinkModel;
exports.LockEvent = LockEvent;
exports.LooseLinkDestroyed = LooseLinkDestroyed;
exports.MoveCanvasAction = MoveCanvasAction;
exports.MoveItemsAction = MoveItemsAction;
exports.NgxDiagramComponent = NgxDiagramComponent;
exports.NgxDiagramsModule = NgxDiagramsModule;
exports.NodeModel = NodeModel;
exports.OutsideZone = OutsideZone;
exports.PaintedEvent = PaintedEvent;
exports.ParentChangeEvent = ParentChangeEvent;
exports.PointModel = PointModel;
exports.PortModel = PortModel;
exports.SelectingAction = SelectingAction;
exports.SelectionEvent = SelectionEvent;
exports.UID = UID;
exports.arrayToMap = arrayToMap;
exports.coerceArray = coerceArray;
exports.enableDiagramProdMode = enableDiagramProdMode;
exports.entityProperty = entityProperty;
exports.generateCurvePath = generateCurvePath;
exports.generateDynamicPath = generateDynamicPath;
exports.generateLinePath = generateLinePath;
exports.isArray = isArray;
exports.isDev = isDev;
exports.isEmptyArray = isEmptyArray;
exports.isFunction = isFunction;
exports.isNil = isNil;
exports.isString = isString;
exports.log = log;
exports.mapToArray = mapToArray;
exports.mapToEntries = mapToEntries;
exports.setLogLevel = setLogLevel;
exports.unique = unique;
exports.withLog = withLog;
exports.ɵa = OutsideZone;
exports.ɵb = TemplateVarDirective;
exports.ɵc = DefaultLinkModel;
exports.ɵd = LinkModel;
exports.ɵe = BaseModel;
exports.ɵf = BaseEntity;
exports.ɵh = DefaultNodeModel;
exports.ɵi = NodeModel;
exports.ɵk = DefaultPortModel;
exports.ɵl = PortModel;
exports.ɵm = DefaultLabelModel;
exports.ɵn = LabelModel;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=ngx-diagrams.umd.js.map