UNPKG

ngx-diagrams

Version:

> Light Weight, Modular, Typed Diagram Engine for Angular

567 lines 82.7 kB
import { __decorate, __metadata } from "tslib"; import { DOCUMENT } from '@angular/common'; import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, EventEmitter, Inject, Input, NgZone, Output, Renderer2, ViewChild, ViewContainerRef } from '@angular/core'; import { BehaviorSubject, combineLatest, fromEvent, merge, ReplaySubject } from 'rxjs'; import { filter, take, takeUntil, tap } from 'rxjs/operators'; import { InvalidLinkDestroyed, LinkCreatedAction, MoveCanvasAction, SelectingAction } from '../../actions'; import { LooseLinkDestroyed } from '../../actions/loose-link-destroyed.action'; import { MoveItemsAction } from '../../actions/move-items.action'; import { DiagramModel } from '../../models/diagram.model'; import { NodeModel } from '../../models/node.model'; import { PointModel } from '../../models/point.model'; import { PortModel } from '../../models/port.model'; import { OutsideZone } from '../../utils'; export class NgxDiagramComponent { constructor(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 EventEmitter(); this.actionStillFiring = new EventEmitter(); this.actionStoppedFiring = new EventEmitter(); this.action$ = new BehaviorSubject(null); this.nodesRendered$ = new BehaviorSubject(false); this.destroyed$ = new ReplaySubject(1); } get host() { return this.elRef.nativeElement; } // TODO: handle destruction of container, resetting all observables to avoid memory leaks! ngAfterViewInit() { if (this.diagramModel) { this.initNodes(); this.initLinks(); this.initSubs(); } } ngOnDestroy() { this.destroyed$.next(true); this.destroyed$.complete(); } /** * fire the action registered and notify subscribers */ fireAction() { if (this.action$.value) { this.actionStillFiring.emit(this.action$.value); } } /** * Unregister the action, post firing and notify subscribers */ stopFiringAction(shouldSkipEvent) { if (!shouldSkipEvent) { this.actionStoppedFiring.emit(this.action$.value); } this.action$.next(null); } /** * Register the new action, pre firing and notify subscribers */ startFiringAction(action) { this.action$.next(action); this.actionStartedFiring.emit(action); } selectAction() { return this.action$; } shouldDrawSelectionBox() { const action = this.action$.getValue(); if (action instanceof SelectingAction) { action.getBoxDimensions(); return true; } return false; } getMouseElement(event) { const target = event.target; // is it a port? let element = target.closest('[data-portid]'); if (element) { // get the relevant node and return the port. const nodeEl = target.closest('[data-nodeid]'); return { model: this.diagramModel .getNode(nodeEl.getAttribute('data-nodeid')) .getPort(element.getAttribute('data-portid')), 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 }; } // look for a link element = target.closest('[data-linkid]'); if (element) { return { model: this.diagramModel.getLink(element.getAttribute('data-linkid')), element }; } // a node maybe element = target.closest('[data-nodeid]'); if (element) { return { model: this.diagramModel.getNode(element.getAttribute('data-nodeid')), element }; } // just the canvas return null; } onMouseUp(event) { const diagramEngine = this.diagramModel.getDiagramEngine(); const action = this.action$.getValue(); // are we going to connect a link to something? if (action instanceof MoveItemsAction) { const element = this.getMouseElement(event); action.selectionModels.forEach((model) => { // only care about points connecting to things if (!model || !(model.model instanceof PointModel)) { return; } let el; if (model.magnet) { el = model.magnet; } else if (element && element.model) { el = element.model; } if (el instanceof PortModel && !diagramEngine.isModelLocked(el)) { const 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) { const targetPort = link.getTargetPort(); const 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); const targetPort = link.getTargetPort(); const 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((model) => { // only care about points connecting to things if (!model || !(model.model instanceof PointModel)) { return; } const selectedPoint = model.model; const 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((model) => { // only care about points connecting to things if (!model || !(model.model instanceof PointModel)) { return; } const link = model.model.getLink(); const sourcePort = link.getSourcePort(); const 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((link) => 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 */ onMouseMove(event) { const action = this.action$.getValue(); if (action === null || action === undefined) { return; } if (action instanceof SelectingAction) { const relative = this.diagramModel.getDiagramEngine().getRelativePoint(event.clientX, event.clientY); this.diagramModel.getNodes().forEach((node) => { if (action.containsElement(node.getCoords(), this.diagramModel)) { node.setSelected(); } else { node.setSelected(false); } }); this.diagramModel.getLinks().forEach((link) => { let allSelected = true; link.getPoints().forEach((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) { const coords = { x: event.clientX - action.mouseX, y: event.clientY - action.mouseY }; const amountZoom = this.diagramModel.getZoomLevel() / 100; action.selectionModels.forEach((selectionModel) => { // 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())) { const newCoords = { x: selectionModel.initialX + coords.x / amountZoom, y: selectionModel.initialY + coords.y / amountZoom }; const 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! const portsMap = this.diagramModel.getAllPorts({ filter: (p) => p.getMagnetic() }); for (const port of portsMap.values()) { const portCoords = port.getCoords(); const distance = Math.hypot(portCoords.x - newCoords.x, portCoords.y - newCoords.y); if (distance <= this.portMagneticRadius) { const portCenter = this.diagramModel.getDiagramEngine().getPortCenter(port); selectionModel.model.setCoords(portCenter); selectionModel.magnet = port; return; } } } selectionModel.model.setCoords(gridRelativeCoords); if (selectionModel.model instanceof NodeModel) { // update port coordinates as well selectionModel.model.getPorts().forEach((port) => { const portCoords = this.diagramModel.getDiagramEngine().getPortCoords(port); port.updateCoords(portCoords); }); } if (this.diagramModel.getDiagramEngine().getSmartRouting()) { setTimeout(() => { 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 const newCoords = this.diagramModel.getGridPosition({ x: coords.x / amountZoom, y: coords.y / amountZoom }); 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(); } } } onMouseDown(event) { if (event.button === 3) { return; } const selectedModel = this.getMouseElement(event); // canvas selected if (selectedModel === null) { // multiple selection if (event.shiftKey) { // initiate multiple selection selector const 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()) { const relative = this.diagramModel.getDiagramEngine().getRelativeMousePoint(event); const sourcePort = selectedModel.model; const 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(); } onMouseWheel(event) { if (!this.allowCanvasZoom) { return; } event.preventDefault(); event.stopPropagation(); const currentZoomLevel = this.diagramModel.getZoomLevel(); const oldZoomFactor = currentZoomLevel / 100; let 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) { const newZoomLvl = currentZoomLevel + scrollDelta; this.diagramModel.setZoomLevel(newZoomLvl); } const updatedZoomLvl = this.diagramModel.getZoomLevel(); const zoomFactor = updatedZoomLvl / 100; const boundingRect = event.currentTarget.getBoundingClientRect(); const clientWidth = boundingRect.width; const clientHeight = boundingRect.height; // compute difference between rect before and after scroll const widthDiff = clientWidth * zoomFactor - clientWidth * oldZoomFactor; const heightDiff = clientHeight * zoomFactor - clientHeight * oldZoomFactor; // compute mouse coords relative to canvas const clientX = event.clientX - boundingRect.left; const clientY = event.clientY - boundingRect.top; // compute width and height increment factor const xFactor = (clientX - this.diagramModel.getOffsetX()) / oldZoomFactor / clientWidth; const yFactor = (clientY - this.diagramModel.getOffsetY()) / oldZoomFactor / clientHeight; const updatedXOffset = this.diagramModel.getOffsetX() - widthDiff * xFactor; const updatedYOffset = this.diagramModel.getOffsetY() - heightDiff * yFactor; this.diagramModel.setOffset(updatedXOffset, updatedYOffset); } setLayerStyles(x, y, zoom) { const nodesLayer = this.getNodesLayer(); const linksLayer = this.getLinksLayer(); const style = 'transform'; const value = `translate(${x}px, ${y}px) scale(${zoom / 100.0})`; this.renderer.setStyle(nodesLayer, style, value); this.renderer.setStyle(linksLayer, style, value); } initNodes() { 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(takeUntil(this.destroyed$)).subscribe((nodes) => { this.nodesRendered$.next(false); for (const node of nodes.values()) { if (!node.getPainted()) { this.diagramModel.getDiagramEngine().generateWidgetForNode(node, this.nodesLayer); this.cdRef.detectChanges(); } } this.nodesRendered$.next(true); }); } initLinks() { this.links$ = this.diagramModel.selectLinks(); combineLatest([this.nodesRendered$, this.links$]) .pipe(filter(([nodesRendered]) => !!nodesRendered), takeUntil(this.destroyed$)) .subscribe(([, links]) => { for (const link of links.values()) { if (!link.getPainted() && link.getSourcePort().getPainted()) { if (link.getSourcePort() !== null) { const portCenter = this.diagramModel.getDiagramEngine().getPortCenter(link.getSourcePort()); link.getPoints()[0].setCoords(portCenter); const portCoords = this.diagramModel.getDiagramEngine().getPortCoords(link.getSourcePort()); link.getSourcePort().updateCoords(portCoords); } if (link.getTargetPort() !== null) { const portCenter = this.diagramModel.getDiagramEngine().getPortCenter(link.getTargetPort()); link.getPoints()[link.getPoints().length - 1].setCoords(portCenter); const portCoords = this.diagramModel.getDiagramEngine().getPortCoords(link.getTargetPort()); link.getTargetPort().updateCoords(portCoords); } this.diagramModel.getDiagramEngine().generateWidgetForLink(link, this.linksLayer); this.cdRef.detectChanges(); } } }); } initSubs() { combineLatest([ this.diagramModel.selectOffsetX(), this.diagramModel.selectOffsetY(), this.diagramModel.selectZoomLevel() ]) .pipe(tap(([x, y, zoom]) => this.setLayerStyles(x, y, zoom)), takeUntil(this.destroyed$)) .subscribe(); } getNodesLayer() { return this.host.querySelector('.ngdx-nodes-layer'); } getLinksLayer() { return this.host.querySelector('.ngdx-links-layer'); } createMouseListeners() { const mouseUp$ = fromEvent(this.document, 'mouseup').pipe(tap((e) => this.onMouseUp(e)), take(1)); const mouseMove$ = fromEvent(this.document, 'mousemove').pipe(tap((e) => this.onMouseMove(e)), takeUntil(mouseUp$)); merge(mouseMove$, mouseUp$).subscribe(); } } NgxDiagramComponent.decorators = [ { type: 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: 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 = () => [ { type: undefined, decorators: [{ type: Inject, args: [DOCUMENT,] }] }, { type: NgZone }, { type: Renderer2 }, { type: ChangeDetectorRef }, { type: ElementRef } ]; NgxDiagramComponent.propDecorators = { diagramModel: [{ type: Input, args: ['model',] }], allowCanvasZoom: [{ type: Input }], allowCanvasTranslation: [{ type: Input }], inverseZoom: [{ type: Input }], allowLooseLinks: [{ type: Input }], maxZoomOut: [{ type: Input }], maxZoomIn: [{ type: Input }], portMagneticRadius: [{ type: Input }], smartRouting: [{ type: Input }], actionStartedFiring: [{ type: Output }], actionStillFiring: [{ type: Output }], actionStoppedFiring: [{ type: Output }], nodesLayer: [{ type: ViewChild, args: ['nodesLayer', { read: ViewContainerRef },] }], linksLayer: [{ type: ViewChild, args: ['linksLayer', { read: ViewContainerRef },] }], canvas: [{ type: ViewChild, args: ['canvas', { read: 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); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGlhZ3JhbS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiLi4vLi4vLi4vLi4vbGlicy9uZ3gtZGlhZ3JhbXMvc3JjLyIsInNvdXJjZXMiOlsibGliL2NvbnRhaW5lcnMvZGlhZ3JhbS9kaWFncmFtLmNvbXBvbmVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzNDLE9BQU8sRUFFTCx1QkFBdUIsRUFDdkIsaUJBQWlCLEVBQ2pCLFNBQVMsRUFDVCxVQUFVLEVBQ1YsWUFBWSxFQUNaLE1BQU0sRUFDTixLQUFLLEVBQ0wsTUFBTSxFQUVOLE1BQU0sRUFDTixTQUFTLEVBQ1QsU0FBUyxFQUNULGdCQUFnQixFQUNqQixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsZUFBZSxFQUFFLGFBQWEsRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFjLGFBQWEsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNuRyxPQUFPLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDOUQsT0FBTyxFQUFjLG9CQUFvQixFQUFFLGlCQUFpQixFQUFFLGdCQUFnQixFQUFFLGVBQWUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN2SCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUMvRSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFHbEUsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBRTFELE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFDdEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQ3BELE9BQU8sRUFBYSxXQUFXLEVBQWMsTUFBTSxh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