family-hierarchy
Version:
A small library for **Angular 9+** that implements [vis-network](https://github.com/visjs/vis-network) to generate a hierarchy chart of a family.
378 lines (370 loc) • 19.4 kB
JavaScript
import { __spread, __decorate } from 'tslib';
import { ɵɵdefineInjectable, Injectable, ViewChild, ContentChild, Input, Component, NgModule } from '@angular/core';
import { BehaviorSubject, Subject, Subscription } from 'rxjs';
import { DataSet, Network } from 'vis-network/standalone';
import { isObject } from 'util';
import { CommonModule } from '@angular/common';
var DEFAULT_NODE_IMAGE = 'data:image/png;base64,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';
var DEFAULT_UNION_IMAGE = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE4LjEuMSwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJDYXBhXzEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4Ig0KCSB2aWV3Qm94PSIwIDAgMzEuODkxIDMxLjg5MSIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzEuODkxIDMxLjg5MTsiIHhtbDpzcGFjZT0icHJlc2VydmUiPg0KPGc+DQoJPHBhdGggZD0iTTMwLjU0Myw1Ljc0bC00LjA3OC00LjAzNWMtMS44MDUtMS43NzctNC43MzYtMS43ODktNi41NDUtMC4wMmwtNC41MjUsNC40MTRjLTEuODEyLDEuNzY4LTEuODIsNC42NDgtMC4wMiw2LjQyNA0KCQlsMi41ODYtMi40ODRjLTAuMjYyLTAuNzkxLDAuMDYxLTEuNjk3LDAuNzAxLTIuMzI0bDIuODc5LTIuODA3YzAuOTEyLTAuODg1LDIuMzc1LTAuODgxLDMuMjc1LDAuMDFsMi40NDksMi40Mg0KCQljMC45LDAuODkxLDAuODk2LDIuMzI2LTAuMDEsMy4yMTNsLTIuODc5LDIuODA5Yy0wLjYwOSwwLjU5NC0xLjYwOSwwLjkyLTIuMzg1LDAuNzExbC0yLjUzMywyLjQ4Ng0KCQljMS44MDMsMS43ODEsNC43MzIsMS43ODksNi41NDUsMC4wMmw0LjUyLTQuNDFDMzIuMzQsMTAuMzk2LDMyLjM0Niw3LjUxOSwzMC41NDMsNS43NHoiLz4NCgk8cGF0aCBkPSJNMTMuOTc1LDIxLjg5NGMwLjIxNSwwLjc3My0wLjEyOSwxLjc3My0wLjc1MiwyLjM4MWwtMi42ODksMi42MjdjLTAuOTIyLDAuOS0yLjQxNCwwLjg5NS0zLjMzMi0wLjAxMmwtMi40OTgtMi40NjENCgkJYy0wLjkxNi0wLjkwNi0wLjkxLTIuMzc5LDAuMDEyLTMuMjc1bDIuNjkxLTIuNjI3YzAuNjU2LTAuNjM3LDEuNTk4LTAuOTYxLDIuNDItMC42ODlsMi41OTQtMi41Nw0KCQljLTEuODM2LTEuODExLTQuODI0LTEuODItNi42NjgtMC4wMmwtNC4zNjMsNC4yNmMtMS44NDYsMS44MDMtMS44NTUsNC43MzQtMC4wMiw2LjU0OWw0LjE1NCw0LjEwNw0KCQljMS44MzQsMS44MDksNC44MiwxLjgxOCw2LjY2OCwwLjAxOGw0LjM2My00LjI2YzEuODQ0LTEuODA1LDEuODUyLTQuNzM0LDAuMDItNi41NDdMMTMuOTc1LDIxLjg5NHoiLz4NCgk8cGF0aCBkPSJNMTEuMTM5LDIwLjcyMmMwLjYxMSwwLjYxNywxLjYxMSwwLjYyMywyLjIzNCwwLjAwOGw3LjQ1NS03LjQxNmMwLjYyMS0wLjYxNywwLjYyNS0xLjYxNSwwLjAwOC0yLjIzNA0KCQljLTAuNjEzLTAuNjE1LTEuNjExLTAuNjE5LTIuMjMtMC4wMDZsLTcuNDU3LDcuNDE0QzEwLjUyOSwxOS4xMDMsMTAuNTI1LDIwLjEwMSwxMS4xMzksMjAuNzIyeiIvPg0KPC9nPg0KPC9zdmc+DQo=';
var OPTION_DEFAULT = {
interaction: {
hover: true,
selectConnectedEdges: false
},
layout: {
hierarchical: {
enabled: true,
levelSeparation: 150,
nodeSpacing: 200,
treeSpacing: 200,
blockShifting: true,
edgeMinimization: true,
parentCentralization: true,
direction: 'UD',
sortMethod: 'directed',
shakeTowards: 'leaves' // roots, leaves
}
},
edges: {
shadow: true
},
nodes: {
shadow: true
},
physics: {
maxVelocity: 10,
minVelocity: 0.1,
}
};
var DEFAULT_CONFIG = {
links: {
childrens: {
styles: {
color: '#848484',
highlight: '#848484',
hover: '#848484'
}
},
parents: {
styles: {
color: '#99004d',
highlight: '#800040',
hover: '#800040',
}
}
},
nodes: {
images: DEFAULT_NODE_IMAGE,
size: 20
},
union: {
images: DEFAULT_UNION_IMAGE,
size: 20
}
};
/* tslint:disable */
var FamilyHierarchyService = /** @class */ (function () {
function FamilyHierarchyService() {
this.currentEdges = new BehaviorSubject(new DataSet());
this._Edges = this.currentEdges.asObservable();
this.currentNodes = new BehaviorSubject(new DataSet());
this._Nodes = this.currentNodes.asObservable();
this.currentFhNodes = new BehaviorSubject([]);
this._fhNodes = this.currentFhNodes.asObservable();
this.currentFhUnions = new BehaviorSubject([]);
this._fhUnions = this.currentFhUnions.asObservable();
this.currentFhLinks = new BehaviorSubject([]);
this._fhLinks = this.currentFhLinks.asObservable();
this.currentConfig = new BehaviorSubject(DEFAULT_CONFIG);
this._config = this.currentConfig.asObservable();
this.init = new Subject();
this._init = this.init.asObservable();
this._clickNode = new Subject();
this.clickNode = this._clickNode.asObservable();
this._clickUnion = new Subject();
this.clickUnion = this._clickUnion.asObservable();
this._clickLink = new Subject();
this.clickLink = this._clickLink.asObservable();
}
Object.defineProperty(FamilyHierarchyService.prototype, "Edges", {
get: function () {
return this._Edges;
},
enumerable: true,
configurable: true
});
Object.defineProperty(FamilyHierarchyService.prototype, "Nodes", {
get: function () {
return this._Nodes;
},
enumerable: true,
configurable: true
});
FamilyHierarchyService.prototype.setFhNodes = function (nodes) {
this.currentNodes.next(this.generateNodes(nodes));
this.currentFhNodes.next(nodes);
};
Object.defineProperty(FamilyHierarchyService.prototype, "FhNodes", {
get: function () {
return this._fhNodes;
},
enumerable: true,
configurable: true
});
FamilyHierarchyService.prototype.setFhUnions = function (unions) {
this.generateUnions(unions);
this.currentFhUnions.next(unions);
};
Object.defineProperty(FamilyHierarchyService.prototype, "FhUnions", {
get: function () {
return this._fhUnions;
},
enumerable: true,
configurable: true
});
FamilyHierarchyService.prototype.setFhLinks = function (links) {
this.currentEdges.next(this.generateEdges(links));
this.currentFhLinks.next(links);
};
Object.defineProperty(FamilyHierarchyService.prototype, "FhLinks", {
get: function () {
return this._fhLinks;
},
enumerable: true,
configurable: true
});
FamilyHierarchyService.prototype.setConfig = function (config) {
this.currentConfig.next(this.mergeDeep(this.currentConfig.getValue(), config));
};
Object.defineProperty(FamilyHierarchyService.prototype, "config", {
get: function () {
return this._config;
},
enumerable: true,
configurable: true
});
FamilyHierarchyService.prototype.sendClickEvent = function (e, type) {
if (type === 'node') {
var node = this.currentFhNodes.getValue().find(function (el) { return el.id === e.nodes[0]; });
if (node) {
this._clickNode.next(node);
}
else {
var id_1 = e.nodes[0].replace('u', '');
var union = this.currentFhUnions.getValue().find(function (el) { return el.id == id_1; });
this._clickUnion.next(union);
}
}
else {
var link = this.currentFhLinks.getValue().find(function (el) { return el.id == e.edges[0]; });
if (link) {
this._clickLink.next(link);
}
else {
var regex = /(?<=l)(.*?)(?=_)/;
var id_2 = e.edges[0].toString().match(regex)[0];
this._clickLink.next(this.currentFhUnions.getValue().find(function (o) { return o.id == id_2; }));
}
}
};
FamilyHierarchyService.prototype.initialize = function (data, config) {
this.currentFhLinks.next(data.links);
this.currentFhNodes.next(data.nodes);
this.currentFhUnions.next(data.unions);
this.currentEdges.next(this.generateEdges(data.links)),
this.currentNodes.next(this.generateNodes(data.nodes));
this.generateUnions(data.unions);
if (config) {
this.setConfig(config);
}
this.init.next(true);
};
FamilyHierarchyService.prototype.mergeDeep = function (target) {
var _a, _b;
var sources = [];
for (var _i = 1; _i < arguments.length; _i++) {
sources[_i - 1] = arguments[_i];
}
if (!sources.length) {
return target;
}
var source = sources.shift();
if (isObject(target) && isObject(source)) {
for (var key in source) {
if (isObject(source[key])) {
if (!target[key]) {
Object.assign(target, (_a = {}, _a[key] = {}, _a));
}
else {
target[key] = Object.assign({}, target[key]);
}
this.mergeDeep(target[key], source[key]);
}
else {
Object.assign(target, (_b = {}, _b[key] = source[key], _b));
}
}
}
return this.mergeDeep.apply(this, __spread([target], sources));
};
FamilyHierarchyService.prototype.generateNodes = function (nodes) {
var _this = this;
return new DataSet(nodes.map(function (o) {
return _this.createNode(o);
}));
};
FamilyHierarchyService.prototype.createNode = function (o) {
return {
id: o.id,
image: o.image ? o.image : this.currentConfig.getValue().nodes.images,
shape: 'image',
size: this.currentConfig.getValue().nodes.size,
level: (o.level * 2) - 1,
label: o.label
};
};
FamilyHierarchyService.prototype.createEdge = function (o) {
return {
id: o.id,
from: o.nodeId,
to: "u" + o.unionId,
color: this.currentConfig.getValue().links.childrens.styles
};
};
FamilyHierarchyService.prototype.generateEdges = function (links) {
var _this = this;
return new DataSet(links.map(function (o) {
return _this.createEdge(o);
}));
};
FamilyHierarchyService.prototype.generateUnions = function (unions) {
var _this = this;
unions.forEach(function (u) {
_this.createUnion(u);
});
};
FamilyHierarchyService.prototype.createUnion = function (u) {
var _this = this;
var level;
var node = {
id: "u" + u.id,
image: this.currentConfig.getValue().union.images,
shape: 'image',
size: this.currentConfig.getValue().union.size,
};
u.components.forEach(function (e) {
var edge = {
id: "l" + u.id + "_" + node.id + "-" + e,
from: node.id,
to: e,
color: _this.currentConfig.getValue().links.parents.styles,
};
level = _this.currentFhNodes.getValue().filter(function (n) { return n.id === e; })[0].level;
_this.currentEdges.getValue().add(edge);
});
node.level = (level * 2);
this.currentNodes.getValue().add(node);
};
FamilyHierarchyService.prototype.addNode = function (node) {
this.currentFhNodes.getValue().push(node);
this.currentNodes.getValue().add(this.createNode(node));
};
FamilyHierarchyService.prototype.addLink = function (link) {
this.currentFhLinks.getValue().push(link);
this.currentEdges.getValue().add(this.createEdge(link));
};
FamilyHierarchyService.prototype.addUnion = function (union) {
this.currentFhUnions.getValue().push(union);
this.createUnion(union);
};
FamilyHierarchyService.ɵprov = ɵɵdefineInjectable({ factory: function FamilyHierarchyService_Factory() { return new FamilyHierarchyService(); }, token: FamilyHierarchyService, providedIn: "root" });
FamilyHierarchyService = __decorate([
Injectable({
providedIn: 'root'
})
], FamilyHierarchyService);
return FamilyHierarchyService;
}());
var FamilyHierarchyComponent = /** @class */ (function () {
function FamilyHierarchyComponent(familyService) {
this.familyService = familyService;
this.class = '';
this.editMode = false;
this.subs = new Subscription();
}
FamilyHierarchyComponent.prototype.ngOnInit = function () {
};
FamilyHierarchyComponent.prototype.ngAfterViewInit = function () {
var _this = this;
var init = this.familyService._init
.subscribe(function (e) {
_this.createNetwork();
});
this.subs.add(init);
this.subs.add(this.familyService._config.subscribe(function (config) { return _this.config = config; }));
this.subs.add(this.familyService.Edges.subscribe(function (edges) { return _this.dsEdge = edges; }));
this.subs.add(this.familyService.Nodes.subscribe(function (nodes) { return _this.dsNode = nodes; }));
};
FamilyHierarchyComponent.prototype.createNetwork = function () {
var _this = this;
this.visNetworkData = { nodes: this.dsNode, edges: this.dsEdge };
this.visNetwork = new Network(this.el.nativeElement, this.visNetworkData, OPTION_DEFAULT);
this.visNetwork.on('selectNode', function (e) {
_this.familyService.sendClickEvent(e, 'node');
});
this.visNetwork.on('selectEdge', function (e) {
_this.familyService.sendClickEvent(e);
});
};
FamilyHierarchyComponent.prototype.ngOnDestroy = function () {
this.subs.unsubscribe();
};
FamilyHierarchyComponent.ctorParameters = function () { return [
{ type: FamilyHierarchyService }
]; };
__decorate([
ViewChild('box')
], FamilyHierarchyComponent.prototype, "el", void 0);
__decorate([
ContentChild('nodeTemplate')
], FamilyHierarchyComponent.prototype, "nodeTemplate", void 0);
__decorate([
ViewChild('contentNode')
], FamilyHierarchyComponent.prototype, "contentNode", void 0);
__decorate([
Input()
], FamilyHierarchyComponent.prototype, "class", void 0);
__decorate([
Input()
], FamilyHierarchyComponent.prototype, "editMode", void 0);
FamilyHierarchyComponent = __decorate([
Component({
selector: 'FamilyHierarchy',
template: "<!-- <div class=\"vis-container\"\r\n [visNetwork]=\"visNetwork\"\r\n [visNetworkData]=\"visNetworkData\"\r\n [visNetworkOptions]=\"visNetworkOptions\"\r\n (initialized)=\"networkInitialized()\">\r\n</div>\r\n -->\r\n<div #box [class.edit-mode]=\"editMode\" [ngClass]=\"['vis-container', class]\"></div>",
styles: [".vis-container{width:100%;height:100%;outline:0}.edit-mode{background-size:40px 40px;background-image:linear-gradient(to right,grey 1px,transparent 1px),linear-gradient(to bottom,grey 1px,transparent 1px)}"]
})
], FamilyHierarchyComponent);
return FamilyHierarchyComponent;
}());
var FamilyHierarchyModule = /** @class */ (function () {
function FamilyHierarchyModule() {
}
FamilyHierarchyModule = __decorate([
NgModule({
declarations: [FamilyHierarchyComponent],
imports: [
CommonModule,
],
exports: [FamilyHierarchyComponent]
})
], FamilyHierarchyModule);
return FamilyHierarchyModule;
}());
/*
* Public API Surface of family-hierarchy
*/
/**
* Generated bundle index. Do not edit.
*/
export { FamilyHierarchyComponent, FamilyHierarchyModule, FamilyHierarchyService };
//# sourceMappingURL=family-hierarchy.js.map