From 1d1cf149bb43be8ec97777ea85745c5c5a86c871 Mon Sep 17 00:00:00 2001 From: ziajka Date: Mon, 5 Nov 2018 14:21:53 +0100 Subject: [PATCH] Decouple project-map from map --- src/app/cartography/cartography.module.ts | 6 +- .../components/map/map.component.ts | 49 ++++++++++++---- src/app/cartography/models/context.ts | 8 ++- src/app/cartography/tools/moving-tool.ts | 47 ++++++++++----- src/app/cartography/tools/selection-tool.ts | 49 ++++++++++------ src/app/cartography/widgets/graph-layout.ts | 8 --- src/app/cartography/widgets/link.ts | 1 + .../node-select-interface.component.ts | 4 +- .../project-map-shortcuts.component.ts | 5 +- .../project-map/project-map.component.html | 4 +- .../project-map/project-map.component.ts | 58 +++++++++---------- 11 files changed, 149 insertions(+), 90 deletions(-) diff --git a/src/app/cartography/cartography.module.ts b/src/app/cartography/cartography.module.ts index 99b15b66..f106a29d 100644 --- a/src/app/cartography/cartography.module.ts +++ b/src/app/cartography/cartography.module.ts @@ -10,7 +10,7 @@ import { LayersManager } from './managers/layers-manager'; import { MapChangeDetectorRef } from './services/map-change-detector-ref'; import { GraphLayout } from './widgets/graph-layout'; import { LinksWidget } from './widgets/links'; -import { NodesWidget, NodeEvent } from './widgets/nodes'; +import { NodesWidget } from './widgets/nodes'; import { DrawingsWidget } from './widgets/drawings'; import { DrawingLineWidget } from './widgets/drawing-line'; import { SelectionTool } from './tools/selection-tool'; @@ -24,6 +24,7 @@ import { ImageDrawingWidget } from './widgets/drawings/image-drawing'; import { RectDrawingWidget } from './widgets/drawings/rect-drawing'; import { TextDrawingWidget } from './widgets/drawings/text-drawing'; import { LineDrawingWidget } from './widgets/drawings/line-drawing'; +import { Context } from './models/context'; @NgModule({ imports: [ @@ -55,7 +56,8 @@ import { LineDrawingWidget } from './widgets/drawings/line-drawing'; ImageDrawingWidget, LineDrawingWidget, RectDrawingWidget, - TextDrawingWidget + TextDrawingWidget, + Context ], exports: [MapComponent] }) diff --git a/src/app/cartography/components/map/map.component.ts b/src/app/cartography/components/map/map.component.ts index f5b557d6..f867e046 100644 --- a/src/app/cartography/components/map/map.component.ts +++ b/src/app/cartography/components/map/map.component.ts @@ -13,6 +13,9 @@ import { Drawing } from "../../models/drawing"; import { Symbol } from '../../../models/symbol'; import { NodeEvent, NodesWidget } from '../../widgets/nodes'; import { Subscription } from 'rxjs'; +import { InterfaceLabelWidget } from '../../widgets/interface-label'; +import { SelectionTool } from '../../tools/selection-tool'; +import { MovingTool } from '../../tools/moving-tool'; @Component({ @@ -34,7 +37,8 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { private d3: D3; private parentNativeElement: any; private svg: Selection; - private graphContext: Context; + + private isReady = false; private onNodeDraggingSubscription: Subscription; @@ -43,9 +47,13 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { }; constructor( + private context: Context, protected element: ElementRef, protected d3Service: D3Service, protected nodesWidget: NodesWidget, + protected interfaceLabelWidget: InterfaceLabelWidget, + protected selectionToolWidget: SelectionTool, + protected movingToolWidget: MovingTool, public graphLayout: GraphLayout ) { this.d3 = d3Service.getD3(); @@ -56,6 +64,28 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { @Input('show-interface-labels') set showInterfaceLabels(value) { this.settings.show_interface_labels = value; + this.interfaceLabelWidget.setEnabled(value); + if (this.isReady) { + this.redraw(); + } + } + + @Input('moving-tool') + set movingTool(value) { + this.movingToolWidget.setEnabled(value); + + if(this.isReady) { + this.redraw(); + } + } + + @Input('selection-tool') + set selectionTool(value) { + this.selectionToolWidget.setEnabled(value); + + if(this.isReady) { + this.redraw(); + } } ngOnChanges(changes: { [propKey: string]: SimpleChange }) { @@ -88,22 +118,17 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { } ngOnInit() { - const d3 = this.d3; - if (this.parentNativeElement !== null) { this.createGraph(this.parentNativeElement); } + this.context.size = this.getSize(); } public createGraph(domElement: HTMLElement) { const rootElement = this.d3.select(domElement); this.svg = rootElement.select('svg'); - this.graphContext = new Context(true); - - this.graphContext.size = this.getSize(); - - this.graphLayout.connect(this.svg, this.graphContext); + this.graphLayout.connect(this.svg, this.context); this.onNodeDraggingSubscription = this.graphLayout.getNodesWidget().onNodeDragging.subscribe((eventNode: NodeEvent) => { const linksWidget = this.graphLayout.getLinksWidget(); @@ -115,7 +140,9 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { }); }); - this.graphLayout.draw(this.svg, this.graphContext); + this.graphLayout.draw(this.svg, this.context); + + this.isReady = true; } public getSize(): Size { @@ -132,7 +159,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { private changeLayout() { if (this.parentNativeElement != null) { - this.graphContext.size = this.getSize(); + this.context.size = this.getSize(); } this.graphLayout.setNodes(this.nodes); @@ -174,7 +201,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { } public redraw() { - this.graphLayout.draw(this.svg, this.graphContext); + this.graphLayout.draw(this.svg, this.context); } public reload() { diff --git a/src/app/cartography/models/context.ts b/src/app/cartography/models/context.ts index cf91d7cf..c3a07008 100644 --- a/src/app/cartography/models/context.ts +++ b/src/app/cartography/models/context.ts @@ -1,5 +1,6 @@ import { Size } from "./size"; import { Point } from "./point"; +import { Injectable } from "@angular/core"; export class Transformation { constructor( @@ -9,12 +10,13 @@ export class Transformation { ) {} } - +@Injectable() export class Context { public transformation: Transformation; public size: Size; - - constructor(public centerZeroZeroPoint = true) { + public centerZeroZeroPoint = true; + + constructor() { this.size = new Size(0, 0); this.transformation = new Transformation(0, 0, 1); } diff --git a/src/app/cartography/tools/moving-tool.ts b/src/app/cartography/tools/moving-tool.ts index efd72b9a..2ecaf26f 100644 --- a/src/app/cartography/tools/moving-tool.ts +++ b/src/app/cartography/tools/moving-tool.ts @@ -9,32 +9,49 @@ import { Context} from "../models/context"; @Injectable() export class MovingTool { - private selection: SVGSelection; - private context: Context; + // private selection: SVGSelection; + private zoom: ZoomBehavior; - - constructor() { + private enabled = false; + private needsDeactivate = false; + private needsActivate = false; + + constructor( + private context: Context + ) { this.zoom = zoom() .scaleExtent([1 / 2, 8]); } - public connect(selection: SVGSelection, context: Context) { - this.selection = selection; - this.context = context; - + public setEnabled(enabled) { + if (this.enabled != enabled) { + if (enabled) { + this.needsActivate = true; + } + else { + this.needsDeactivate = true; + } + } + this.enabled = enabled; } public draw(selection: SVGSelection, context: Context) { - this.selection = selection; - this.context = context; + if(this.needsActivate) { + this.activate(selection); + this.needsActivate = false; + } + if(this.needsDeactivate) { + this.deactivate(selection); + this.needsDeactivate = false; + } } - public activate() { + private activate(selection: SVGSelection) { const self = this; const onZoom = function(this: SVGSVGElement) { - const canvas = self.selection.select("g.canvas"); + const canvas = selection.select("g.canvas"); const e: D3ZoomEvent = event; canvas.attr( 'transform', @@ -51,12 +68,12 @@ export class MovingTool { }; this.zoom.on('zoom', onZoom); - this.selection.call(this.zoom); + selection.call(this.zoom); } - public deactivate() { + private deactivate(selection: SVGSelection) { // d3.js preserves event `mousedown.zoom` and blocks selection - this.selection.on('mousedown.zoom', null); + selection.on('mousedown.zoom', null); this.zoom.on('zoom', null); } } diff --git a/src/app/cartography/tools/selection-tool.ts b/src/app/cartography/tools/selection-tool.ts index 2e1f6f12..da78d63a 100644 --- a/src/app/cartography/tools/selection-tool.ts +++ b/src/app/cartography/tools/selection-tool.ts @@ -11,26 +11,33 @@ import { Rectangle } from "../models/rectangle"; export class SelectionTool { static readonly SELECTABLE_CLASS = '.selectable'; - public rectangleSelected: Subject; + public rectangleSelected = new Subject(); - private selection: SVGSelection; private path; - private context: Context; + private enabled = false; + private needsDeactivate = false; + private needsActivate = false; - public constructor() { - this.rectangleSelected = new Subject(); + public constructor( + private context: Context + ) {} + + public setEnabled(enabled) { + if (this.enabled != enabled) { + if (enabled) { + this.needsActivate = true; + } + else { + this.needsDeactivate = true; + } + } + this.enabled = enabled; } - public connect(selection: SVGSelection, context: Context) { - this.selection = selection; - this.context = context; - } - - public activate() { + private activate(selection) { const self = this; - - this.selection.on("mousedown", function() { + selection.on("mousedown", function() { const subject = select(window); const parent = this.parentElement; @@ -38,7 +45,7 @@ export class SelectionTool { self.startSelection(start); // clear selection - self.selection + selection .selectAll(SelectionTool.SELECTABLE_CLASS) .classed("selected", false); @@ -56,8 +63,8 @@ export class SelectionTool { }); } - public deactivate() { - this.selection.on('mousedown', null); + private deactivate(selection) { + selection.on('mousedown', null); } public draw(selection: SVGSelection, context: Context) { @@ -72,7 +79,15 @@ export class SelectionTool { .attr("class", "selection") .attr("visibility", "hidden"); } - this.selection = selection; + + if(this.needsActivate) { + this.activate(selection); + this.needsActivate = false; + } + if(this.needsDeactivate) { + this.deactivate(selection); + this.needsDeactivate = false; + } } private startSelection(start) { diff --git a/src/app/cartography/widgets/graph-layout.ts b/src/app/cartography/widgets/graph-layout.ts index 767b4f1f..ec1fd640 100644 --- a/src/app/cartography/widgets/graph-layout.ts +++ b/src/app/cartography/widgets/graph-layout.ts @@ -60,20 +60,12 @@ export class GraphLayout implements Widget { return this.drawingLineTool; } - public getMovingTool() { - return this.movingTool; - } - public getSelectionTool() { return this.selectionTool; } connect(view: SVGSelection, context: Context) { this.drawingLineTool.connect(view, context); - this.selectionTool.connect(view, context); - this.movingTool.connect(view, context); - - this.selectionTool.activate(); } draw(view: SVGSelection, context: Context) { diff --git a/src/app/cartography/widgets/link.ts b/src/app/cartography/widgets/link.ts index f790a823..c673c84a 100644 --- a/src/app/cartography/widgets/link.ts +++ b/src/app/cartography/widgets/link.ts @@ -1,4 +1,5 @@ import { Injectable } from "@angular/core"; + import { Widget } from "./widget"; import { SVGSelection } from "../models/types"; import { Link } from "../../models/link"; diff --git a/src/app/components/project-map/node-select-interface/node-select-interface.component.ts b/src/app/components/project-map/node-select-interface/node-select-interface.component.ts index 8b5100dc..708874c5 100644 --- a/src/app/components/project-map/node-select-interface/node-select-interface.component.ts +++ b/src/app/components/project-map/node-select-interface/node-select-interface.component.ts @@ -15,8 +15,8 @@ export class NodeSelectInterfaceComponent implements OnInit { @ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger; - private topPosition; - private leftPosition; + protected topPosition; + protected leftPosition; public node: Node; constructor( diff --git a/src/app/components/project-map/project-map-shortcuts/project-map-shortcuts.component.ts b/src/app/components/project-map/project-map-shortcuts/project-map-shortcuts.component.ts index 1e4813f3..41124df8 100644 --- a/src/app/components/project-map/project-map-shortcuts/project-map-shortcuts.component.ts +++ b/src/app/components/project-map/project-map-shortcuts/project-map-shortcuts.component.ts @@ -28,7 +28,10 @@ export class ProjectMapShortcutsComponent implements OnInit, OnDestroy { ) { } ngOnInit() { - this.deleteHotkey = new Hotkey('del', this.onDeleteHandler); + const self = this; + this.deleteHotkey = new Hotkey('del', (event: KeyboardEvent) => { + return self.onDeleteHandler(event); + }); this.hotkeysService.add(this.deleteHotkey); } diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 743f4e1c..51dbc8a6 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -7,6 +7,8 @@ [width]="project.scene_width" [height]="project.scene_height" [show-interface-labels]="project.show_interface_labels" + [selection-tool]="tools.selection" + [moving-tool]="tools.moving" (onNodeDragged)="onNodeDragged($event)" > @@ -53,7 +55,7 @@ - diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 105949d4..3ba1cc91 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -48,8 +48,13 @@ export class ProjectMapComponent implements OnInit, OnDestroy { private ws: Subject; private drawLineMode = false; - private movingMode = false; - private readonly = false; + + protected tools = { + 'selection': true, + 'moving': false + }; + + private inReadOnlyMode = false; protected selectionManager: SelectionManager; @@ -189,13 +194,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } setUpMapCallbacks(project: Project) { - if (this.readonly) { - this.mapChild.graphLayout.getSelectionTool().deactivate(); - } - this.mapChild.graphLayout.getNodesWidget().setDraggingEnabled(!this.readonly); - const onContextMenu = this.mapChild.graphLayout.getNodesWidget().onContextMenu.subscribe((eventNode: NodeEvent) => { this.nodeContextMenu.open(eventNode.node, eventNode.event.clientY, eventNode.event.clientX); }); @@ -217,9 +217,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.mapChild.graphLayout.getSelectionTool().rectangleSelected) ); - this.mapChild.graphLayout - .getLinksWidget().getLinkWidget().getInterfaceLabelWidget().setEnabled(this.project.show_interface_labels); - this.mapChild.reload(); } @@ -244,6 +241,27 @@ export class ProjectMapComponent implements OnInit, OnDestroy { }); } + public set readonly(value) { + this.inReadOnlyMode = value; + if (value) { + this.tools.selection = false; + } + else { + this.tools.selection = true; + } + } + + public get readonly() { + return this.inReadOnlyMode; + } + + public toggleMovingMode() { + this.tools.moving = !this.tools.moving; + if (!this.readonly) { + this.tools.selection = !this.tools.moving; + } + } + public toggleDrawLineMode() { this.drawLineMode = !this.drawLineMode; if (!this.drawLineMode) { @@ -251,22 +269,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } } - public toggleMovingMode() { - this.movingMode = !this.movingMode; - if (this.movingMode) { - if (!this.readonly) { - this.mapChild.graphLayout.getSelectionTool().deactivate(); - } - this.mapChild.graphLayout.getMovingTool().activate(); - } else { - this.mapChild.graphLayout.getMovingTool().deactivate(); - if (!this.readonly) { - this.mapChild.graphLayout.getSelectionTool().activate(); - } - } - } - - public onChooseInterface(event) { const node: Node = event.node; const port: Port = event.port; @@ -294,10 +296,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public toggleShowInterfaceLabels(enabled: boolean) { this.project.show_interface_labels = enabled; - - this.mapChild.graphLayout.getLinksWidget().getLinkWidget().getInterfaceLabelWidget() - .setEnabled(this.project.show_interface_labels); - this.mapChild.reload(); } public ngOnDestroy() {